6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 8:04 pm

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: Fri Feb 16, 2024 8:07 pm 
Offline

Joined: Tue Sep 26, 2023 11:09 am
Posts: 109
After many false starts and a lot of learning and trawling here (starting from viewtopic.php?t=1674), I finally managed to get the VIA shift-out (phi2 clock) talking to my SD card using SPI mode 0 without bit-banging!

I thought I'd share here in case it's useful for others, or if anyone has ideas for improvements. My current code runs at 22 cycles per byte, but I think it could go
slightly faster (question below). I guess the theoretical max is 16 cycles/byte since VIA clocks out bits at half the phi2 clock rate, but not sure if
you could actually code the read loop that tightly?

The schematic sketches my hardware setup, with a timing diagram showing my current understanding. I originally thought I only needed half a phi2 cycle delay on CB1, but as I learned from my scope that doesn't work because of how CB2 lags CB1. Note that RCLK in my h/w is just wired directly to phi2, not what's shown in the timing diagram (again see below). I learned that the pullup resistors are important (I'm surprised they're not built in to the breakout board?) and that an SD card draws a lot of current - had to up my bench cutoff point.

Basically the VIA SR writes a byte out to the SD card while the SD card sends a byte in to a shift register mapped to VIA port A, both clocked by the delayed and inverted CB1 signal. It took a while for me to understand that SPI doesn't really have a separate notion of read vs write - it always just exchanges a byte each way with a pre-agreed notion of which side of the swap is currently meaningful (I guess in principle useful data could actually be exchanged in both directions concurrently?).

When the VIA is "reading" by convention it writes #$ff to trigger the exchange and looks at the byte arriving at port A; when it's "writing" it writes the actual data byte and ignores the incoming data. My block read is shown below (full code on github). The inner page read section runs in 22 cycles per byte.

I've currently got the external shift register RCLK wired to phi2, making it update continuously at port A. This means I need to be careful to read the incoming data after it arrives but before I trigger the next incoming byte (I leave 18 cycles between, plus the LDA time gives 22 cycles).

But if RCLK instead triggered only once every eight bits, then the byte would stay latched at PORT A even while the next byte was arriving. Then I could safely trigger the next byte exchange *before* reading the value of the previous one, in a tighter loop of 16 to 18 cycles total (I'm still fuzzy about the timing between writing the VIA SR and the CB1 clock starting).

Is there some clever way to do that? It seems like you'd often want an 8-bit shift register to behave that way (wait for all eight bits to arrive, then latch to the outputs). I guess a 3 (or 4) bit counter could count falling SCK edges and generate a rising edge just after the last bit arrives, as shown in the last line of the timing diagram?

Not sure I actually care enough about saving the extra cycles to fight with it, but curious if it's feasible?

Next planning to hook up the ProDOS kernel and try booting from the SD card. Fun, fun...

Code:
        ; now read 512 bytes of data
        ; unroll first loop step to interpose indexing stuff between write/write

        ldx #$ff
        bit sd_cmd0         ; set overflow as page 0 indicator (all cmd bytes have bit 6 set)
        stx VIA_SR          ; 4 cycles      trigger first byte in
        DELAY12
        ldy #0              ; 2 cycles      byte counter
@next:  lda DVC_DATA        ; 4 cycles
        stx VIA_SR          ; 4 cycles      trigger next byte
        sta (sd_bufp),y     ; 6 cycles
        DELAY3              ; 3 cycles
        iny                 ; 2 cycles
        bne @next           ; 2(+1) cycles
        inc sd_bufp+1
        bvc @crc            ; second page?
        clv                 ; clear overflow for second page
        bra @next


Attachments:
via-sr-schematic.png
via-sr-schematic.png [ 52.55 KiB | Viewed 2990 times ]
sr-timing.jpg
sr-timing.jpg [ 321.67 KiB | Viewed 2990 times ]
Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 17, 2024 8:02 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
Well done - and thanks for the code and attachments!


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 17, 2024 11:08 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
I still have to have a deeper look at your post, looks interesting! I have a schematics shown in my followup video to the VIA shift register bug, where I use clever handshaking modes and a single shift register to count incoming bits... https://youtu.be/nvnz_34uWSg if that helps you
Schematics will be published elsewhere but I don't have them yet on github IIRC

André

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 18, 2024 5:50 am 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
pdragon wrote:
... But if RCLK instead triggered only once every eight bits, then the byte would stay latched at PORT A even while the next byte was arriving. Then I could safely trigger the next byte exchange *before* reading the value of the previous one, in a tighter loop of 16 to 18 cycles total (I'm still fuzzy about the timing between writing the VIA SR and the CB1 clock starting).

Is there some clever way to do that? It seems like you'd often want an 8-bit shift register to behave that way (wait for all eight bits to arrive, then latch to the outputs). I guess a 3 (or 4) bit counter could count falling SCK edges and generate a rising edge just after the last bit arrives, as shown in the last line of the timing diagram? ...


I think a 74x191 Up/Down binary counter might do it.

It would need D/U tied to ground to count up, /DTEN tied low since there is no need to inhibit the counter, your SO signal as an active low enable, /SO, tied to the /LOAD pin, and pins A-D tied to GND so that it loads $0 into the counter.

Your CB1" (unused Q output of the second delay latch) would be the CLK input. The eight rising clocks on CB1" will count %0001, %0010, %0011, %0100, %0101, %0110, %0111, %1000, and the last count happens after the last MISO bit has been latched, so that makes QD a candidate for your RCLK signal.

If the HC or HCT series are fast enough, it looks like Mouser has both 74HC191 and 74HCT191 ICs in stock through hole, and 74HC91 SMB.


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 18, 2024 9:25 am 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
I have used a shift register to count bits. Reset before starting. Shift in 1s. After 8 shifts the last bit goes from 0 to 1.

Together with the VIA handshake modes this is a nice feature - readin/writing PA automatically resets the counter if you use CA2 as shift register reset.

Btw for the record, I have used all SPI modes with the VIA SR simply with some clever inverting and programming. It relies on hair thin timing though. http://www.6502.org/users/andre/csa/spi/index.html

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 18, 2024 10:44 am 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
here's my schematic of the receive shift register:
http://www.6502.org/users/andre/csa/iec ... -sch-2.png


Attachments:
Screenshot_20240218_114312.png
Screenshot_20240218_114312.png [ 172.12 KiB | Viewed 2893 times ]

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/
Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 18, 2024 10:57 am 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
@pdragon: I am wondering. "Officially" SPI modes 0 and 2 expect data to change on 180° clock phase shift to modes 1 and 3. In your schematics you don't do this but delay by phi2 - which obviously works. And looks kind of 180° as you are shifting out that fast.

My original problem was that I didn't have any of phi0/1/2 on the PET userport - so I was limited to other means.

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 18, 2024 12:43 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
Link to another thread where we (esp. Bruce McFarling) has found another very interesting and easy way of creating an SPI mode 0 clock: viewtopic.php?f=4&t=7937#p106621

Edit: corrected Bruce's family name

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/


Last edited by fachat on Sun Feb 18, 2024 7:30 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 18, 2024 4:19 pm 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
fachat wrote:
@pdragon: I am wondering. "Officially" SPI modes 0 and 2 expect data to change on 180° clock phase shift to modes 1 and 3. In your schematics you don't do this but delay by phi2 - which obviously works. And looks kind of 180° as you are shifting out that fast.


Yeah, since SPI is a patient serial bus, the pretty symmetric serial clock cycles don't have to be respected perfectly as long as set-up and hold timing requirements are met. If the servant-side MOSI SSR has a max 5ns rise/fall, 25ns set-up and 3ns hold for reliable input, and the servant-side MISO SSR requires a 12ns set-up for output and 15ns after the latch before the shift transition, it might say its maximum bus frequency is 16MHz, but finding the asymmetric SCLK cycle that gives its fastest throughput is being left as an "exercise for the reader" (and, of course, not worth the trouble if you intend to be able to support a variety of devices on the SPI bus).

With a Phi2/2 frequency SCLK, delaying by exactly one full clock will get it lined up correctly, and that's what you get in theory with a clocked latch on Phi1 followed by a clock latch on Phi2.

Now, in practice the timing might be a little sloppy, since the W65C02 PHI2O and PHI1O seem to be legacy support for circuits designed for older, slower parts, and the timing tolerances are not part of the specs, but if Phi2/2 is not pressing the maximum serial clock frequency specified for the SPI servant device, my guess would be that it should be OK.

If doing the circuit for a faster host system and slower SPI device, or if the timing doesn't have enough tolerances for breadboarding delays, it might be necessary to go from a Phi2 toggle SCLK to a timer driven SCLK. The latch delay approach is parsimonious for Phi2/2, because of the complementary output of the latch avoiding the need for a distinct NOT gate, but if a longer delay is needed for a timer driven CLK3, using an inverter of CLK3 into a serial-in, parallel-out serial shift register gives flexibility in how much delay is needed to make it work.

To crank up the speed, if using a Phi2 SCLK (with the VIA just loading or writing distinct MISO and MOSI SSR's), with an active low /Start pulse generating an active low /Enable line, passed through an OR gate with Phi2 to generate an SPI_CLK3, and a counter on the SCLK to turn off the /Enable line, you would only need a single Phi1O delay latch, to delay CLK3 by a half Phi2 clock phase, and since the dual latch being used here has /Preset and /Clear, the other side of the delay latch could latch the /Enable line.


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 18, 2024 9:57 pm 
Offline

Joined: Tue Sep 26, 2023 11:09 am
Posts: 109
Andre - I discovered your nice trailing bit shift code as part of my journey, but I figured this would be simpler on the s/w side of things,
and gave me a chance to learn more about shift registers and flip flops.

Bruce/fachat - I actually forgot there was a phi1O on the 65c02 so I think currently have it wired as phi2 thru an inverter. i can't remember if I tested both ways, but I'm only running at 1Mhz so maybe not a big deal. I'll check out those other threads you linked.

It does seem like I could get the RCLK 8-bit cycle working with a 4-bit counter or another shift-register that is cleared and then shifts in 1s until a 1 appears on the daisy chain. I thought I might be able to avoid an extra IC if there was some kind of shift register that automatically latched output or otherwise flagged "complete" somehow every 8 bits, but purely speculation on my part.

BTW, I was able to wrap it all up as a prodos device driver with the relocatable prodos FS kernel I extracted so now I can use the std prodos8 MLI to read (and theoretically write) files from up to 14 x 32Mb volumes on a raw SD card. Picture over here: viewtopic.php?f=1&t=7948&p=106634#p106634


Top
 Profile  
Reply with quote  
PostPosted: Mon Feb 19, 2024 12:05 am 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
pdragon wrote:
... Bruce/fachat - I actually forgot there was a phi1O on the 65c02 so I think currently have it wired as phi2 thru an inverter. i can't remember if I tested both ways, but I'm only running at 1Mhz so maybe not a big deal. I'll check out those other threads you linked. ...


I was reading it as PHI1O, but it did indeed just say "Phi1". Inverting the system Phi2 and using that is, IMHO, the better way to do it in any event, given that the timing tolerances of the PHI1O and PHI2O are not specified in the datasheet, and IIRC, the datasheet recommends against using them with new circuit designs.


Top
 Profile  
Reply with quote  
PostPosted: Mon Feb 19, 2024 12:42 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8506
Location: Midwestern USA
BruceRMcF wrote:
...and IIRC, the datasheet recommends against using them with new circuit designs.

From page 26 of the data sheet:

Quote:
1. Timing measurement points are 50% VDD.
2. PHI1O and PHI2O clock delay from PHI2 is no longer specified or tested and WDC recommends using an oscillator for system time base and PHI2 processor input clock.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 36 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: