6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 4:11 pm

All times are UTC




Post new topic Reply to topic  [ 20 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Wed Nov 22, 2023 1:24 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
gfoot wrote:
How about this version - put MOSI on bit 2, with bit 1 being an unconnected output pin, and then:
Whoa -- VERY nice, George! That's about 23% faster than my latest effort (which AFAIK was already in first place compared with anything similar).

And bit1 needn't be wasted and left unconnected -- it's still available for other applications. (This applies to unused bits in my version, too.) If the other application uses the bit as an input then there's no interference from the writes done by the SPI code. And even if the other application does use the bit as an output, it's possible -- depending on the scenario -- that the interference will be tolerable, as long as both applications aren't simultaneously active. (I know Garth gets some extra serious mileage by having umpteen applications on a single VIA port... :) )

So, on the VIA port we have...

  • bit7 is in input mode -- attaches to MISO
  • bit6 is available for other uses, esp. as an input, or it may be chosen as the one to output MOSI
  • [... same ...]
  • bit2 is available for other uses, esp. as an input, or it may be chosen as the one to output MOSI
  • bit1 is available for other uses, esp. as an input
  • bit0 is in output mode -- attaches to Ck

And -- for even more speed :shock: -- your version of the code lends itself very readily to loop unrolling, for a further savings of as much as 3 cycles per SPI bit! For example, here I've unrolled by two:
Code:
SPIBYTEIN:    LDA #$FE        ; for counting, and as a nice supply of set bits
              SEC
INPUTLOOP: 4  STZ VIAPORT_IO  ; Ck=0, mosi=0
           6  ROL VIAPORT_IO  ; set Ck=1, shift MISO into carry
           2  ROL A
           4  STZ VIAPORT_IO  ; Ck=0, mosi=0
           6  ROL VIAPORT_IO  ; set Ck=1, shift MISO into carry
           2  ROL A
           3  BCS INPUTLOOP

That's 13.5 cycles per SPI bit, plus a few cycles for the setup code. And with 8X unrolling it's 12 cycles per SPI bit.

(And knock off 2 more cycles if your I/O is in zero-page, as is mine. I won't dispute that priorities vary -- that's fine -- but for a further 20% increase... )

Quote:
Though I think for SD cards you're meant to be sending set bits - not clear bits - on MOSI when reading data.
You sound a little uncertain about this point (and so am I). Can anyone confirm? In any case, it's true (as you say) that you can avoid the issue. Just load an appropriate value into X or Y and use STX or STY instead of STZ.

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 2:23 am 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
Dr Jefyll wrote:
And bit1 needn't be wasted and left unconnected -- it's still available for other applications. (This applies to unused bits in my version, too.) If the other application uses the bit as an input then there's no interference from the writes done by the SPI code. And even if the other application does use the bit as an output, it's possible -- depending on the scenario -- that the interference will be tolerable, as long as both applications aren't simultaneously active. (I know Garth gets some extra serious mileage by having umpteen applications on a single VIA port... :) )
The reason I inserted the extra bit there was to ensure that the level on MOSI is held steady while the clock goes high. It's the rising edge that triggers the card to read, I believe, and we need to set up the data level before causing the rising edge. So I reserved that extra bit to hold a dummy copy of MOSI. In your read code this is just zero, but if we were writing data it wouldn't be (but maybe we'd use INC for that instead of ROL).

Quote:
Quote:
Though I think for SD cards you're meant to be sending set bits - not clear bits - on MOSI when reading data.
You sound a little uncertain about this point (and so am I). Can anyone confirm? In any case, it's true (as you say) that you can avoid the issue. Just load an appropriate value into X or Y and use STX or STY instead of STZ.

It's how I've always done it - the main source I learned from was http://elm-chan.org/docs/mmc/mmc_e.html which says (in the "Command and Response" section) "The DI signal must be kept high during read transfer (send a 0xFF and get the received data)."

The official specification is rather redacted in its publicly-available version (https://academy.cba.mit.edu/classes/net ... /SD/SD.pdf) and I had a look but can't find this information in there.

By the way, if you're willing to give up the whole VIA for SD card access, but don't want to use the shift register, then take a look at the implementation I posted in NormalLuser's thread here: viewtopic.php?f=2&t=7840&start=0#p104565 I think it's only 6 cycles per bit to read this way! (with unrolled loops)


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 3:05 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
gfoot wrote:
The reason I inserted the extra bit there was [...] if we were writing data
Hm, okay... My focus was entirely on reading. And yet it'd be nice if there were no conflict with the optimizations for writing. Hm, for writing, it may be best, as you say, to use INC instead of ROL to wiggle the clock (on bit0).

gfoot wrote:
By the way, if you're willing to give up the whole VIA for SD card access, but don't want to use the shift register, then take a look at the implementation I posted in NormalLuser's thread here: viewtopic.php?f=2&t=7840&start=0#p104565 I think it's only 6 cycles per bit to read this way! (with unrolled loops)
Yes, this method and the shift register method are both quite compelling! And both exploit the resources available in a VIA.

The code recently posted in this thread doesn't require any extra resources (handshaking, or a shift register) -- just a bare bones parallel I/O port will suffice. But it's pretty easy to justify including one or more VIA's in one's project, so...

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 22, 2023 5:37 pm 
Offline
User avatar

Joined: Mon Mar 06, 2023 9:26 am
Posts: 88
Location: UK
My design uses the VIA's shift register for data out and a 74HC595 for data in, mainly because I wanted and potentially needed full duplex and didn't want to bother with writing loads of code to bitbang it.

The '595 is accessed through port B, and port A is used for such things as chip selects and other bit IO. I don't even have to use interrupts - I can just watch the shift register bit in the IFR.

_________________
probably the youngest person on this forum


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 24, 2023 3:15 pm 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
gfoot wrote:
Dr Jefyll wrote:
And bit1 needn't be wasted and left unconnected -- it's still available for other applications. (This applies to unused bits in my version, too.) If the other application uses the bit as an input then there's no interference from the writes done by the SPI code. And even if the other application does use the bit as an output, it's possible -- depending on the scenario -- that the interference will be tolerable, as long as both applications aren't simultaneously active. (I know Garth gets some extra serious mileage by having umpteen applications on a single VIA port... :) )
The reason I inserted the extra bit there was to ensure that the level on MOSI is held steady while the clock goes high. It's the rising edge that triggers the card to read, I believe, and we need to set up the data level before causing the rising edge. ...


Yes, I like that.

If you want to use the shift to output MISO while toggling the clock, and want a SPI_OUT, SPI_IN and SPI_TX, the SPI_TX can have the write byte for the 0 bit in register X and the 1 bit in register Y. If the loop if fully unrolled, a count is not needed, so A can hold the output byte:

Code:
...
    ASL
    BCS +
    STX VIA_PORT ; reset output bit, clock bit
    SEC
    ROL VIA_PORT ; raise clock, read MISO
    ROL
    BCC ++
    BRA +++
+   STY VIA_PORT ; set output bit, reset clock bit
    ROL VIA_PORT ; raise clock, read MISO
    ROL
    BCS +++
++  STX VIA_PORT ; reset output bit, clock bit
    SEC
    ROL VIA_PORT ; raise clock, read MISO
    ROL
    BCC ++
    BRA ++++
+++ ...


If you only have one SPI device to connect to, you can set bit 0 to CLK, bits 1 and 2 to MOSI, with bit 2 connected, so it remains stable through the rotate, bit7 to MISO. Then if the other VIA port is allocated to something, bits 3 and 4 can be allocated to /SPI_SELECT with bit 4 to /SPI_SEL, and bits 5 and 6 are still available for an I2C port or for a second SPI select.

Or if GPIO are in higher demand than handshake lines, CA2 can be set to either low or high output, making a perfectly usable /SPI_SELECT line.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ]  Go to page Previous  1, 2

All times are UTC


Who is online

Users browsing this forum: No registered users and 15 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: