6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Mon May 13, 2024 9:38 am

All times are UTC




Post new topic Reply to topic  [ 11 posts ] 
Author Message
PostPosted: Fri Aug 19, 2022 6:54 pm 
Offline
User avatar

Joined: Mon Aug 30, 2021 11:52 am
Posts: 268
Location: South Africa
Sometimes I worry about myself. I could have just been normal and used an SD card in SPI mode like everyone. But, no, I had to be special and try to use an SD card in SD mode. Unlike every. single. other. person who has ever posted anything about using SD cards.

So this post falls somewhere between a plea for help and a tutorial on how to use an SD card in SD mode.

The first problem I ran into (apart from nobody at all posting anything about SD mode) is that there are a dozen conflicting datasheets over about two decades; none of which contained the whole story. You might expect the SD card association would be the place to start but the Simplified Physical Layer Specification is three hundred pages. And unless you already know what you're looking for it is almost impossible to find anything in it.

For example: When is data on the CMD line read by the card? Is it when the CLK transitions high-to-low or low-to-high? Or something else? It's on page 273 under bus timings. Like. I. just... Aaaagh
Attachment:
SD Card Bus Timing.png
SD Card Bus Timing.png [ 72.91 KiB | Viewed 1564 times ]
I only found that after a muddy version in a twenty year old SanDisk datasheet that clued me in on what to search for.

Incidentally, the answer is low-to-high. The SD card reads data on the CMD line when the CLK goes low-to-high. And the host must similarly read data on the CMD line (presented by the card) when the CLK goes low-to-high.

Speaking of CMD, below is an SD card pin-out:
Attachment:
SD Card Pins.png
SD Card Pins.png [ 99.79 KiB | Viewed 1564 times ]

With that out the way let the adventure begin with trying to initialise an SD card.
Attachment:
SD Card Initialistion Flow.png
SD Card Initialistion Flow.png [ 157.55 KiB | Viewed 1564 times ]


First you have to put a newly powered up card into IDLE mode by sending it cmd0 and then send it cmd8 to ask what voltages it supports. Before you can send cmd0 you you have to set CMD high and tick the CLK 80 times at 100KHz. Or maybe you have to tick the clock 75 times. Or none. I ticked it 8 times and the category 10 SanDisk card I'm using seemed happy.

Again before cmd0 can be sent to put the card in SD mode DAT3 must be set high too. In theory all you DAT lines should be set as high impedance inputs and each should have a 10KΩ+ pull up resistor on. I used pull down resistors (because of course I did) so I had to set DAT3 as a high output because I couldn't rely on the (non-existent) pull-up resistor to do it for me. Still worked fine though. CMD should also have a 10KΩ+ pull up resistor. If DAT3 is set a low output the SD card will switch into SPI mode at this point.

Next we're going to jump straight over how to send commands and take a look at what a successfully sent command looks like on an oscilloscope. A picture really is worth a thousand words.
Attachment:
SD Card Cmd0 Detail.png
SD Card Cmd0 Detail.png [ 128.49 KiB | Viewed 1564 times ]

A SD card command has the following form:
Attachment:
SD Card Command Format.png
SD Card Command Format.png [ 17.16 KiB | Viewed 1475 times ]
It is sent on the CMD line at one bit per CLK tick from the highest bit first, bit 47, until the stop transmission bit, bit 0. The stop transmission bit basically just leaves CMD high so that the next transmission start bit can be detected. With that said it has been suggested that CLK should be ticked 8 times after cmd0 has been sent to allow the card to initialise itself. Is it necessary nowadays? I don't know but I'm afraid to not tick the clock of the idle command now.

The argument bits to cmd0 are ignored but best practice is to send all zeros. It's also worth noting there is a bit of confusion around the internet on what the CRC of an SD card command is (either in SD mode or SPI mode). The SD card command uses a crc7 with the generator polynomial: x7 + x3 + 1. For the five cmd0 zero bytes 0x40 00 00 00 00 that 7 bit crc is calculated to be 0x4a. To bring it to 8 bits the stop transmission bit is appended to the end making the 6 byte for cmd0 0x95. 0x95 is not the CRC 0x4a is.

In the attached oscilloscope screenshot you might have seen that I hold the clock high for some time after I'm done ticking cmd0. That's not intentional, it is an artifact from the Raspberry Pi Pico I'm using to bit-bang out the signal. I suspect it has something to do with the debugger but having it attached or not makes no difference. The Pico pauses occasionally but very consistently.

After the SD card has been placed in idle mode with cmd0 (and there is no response to cmd0 so in SD mode so you just have to hope it worked); then cmd8 must be sent to select the allowed supply voltage. Practically there is only one voltage option so set command bit 16 to a one. Bits 19 to 16 are the voltage arguments but I think it might be best to steer clear of low voltage SD cards for hobby projects.
Attachment:
SD Card Cmd8 Detail.png
SD Card Cmd8 Detail.png [ 120.25 KiB | Viewed 1564 times ]
cmd8 is useful in that it also has a check pattern that will be echoed back in its response. I've used 0xAA but the choice of bits is entirely optional.

Once I'm done banging out the command the CMD line must be set to input as cmd8 expects a response. The line briefly goes to a noise high impedance state from both the Pico (the host) and the SD card. I did eventually swap out my pull-down for pull-up resistors.

Within two clock ticks after completing the command send the SD card has grabbed the CMD line and started driving it high.
Attachment:
SD Card Cmd8 Response Detail.png
SD Card Cmd8 Response Detail.png [ 122.23 KiB | Viewed 1564 times ]
A few clock ticks later and the SD cards transmission start bit (a zero) is seen on the CMD line followed by another zero indicating it is the card transmitting. CLK is still being driven by the Pico and is never set to be an input.

The most interesting thing to note here (apart from getting any response at all from the blasted card) is the the check pattern being echoed back. Bit 16 will also be set to indicate the card supports 3.3V. The long clock on the last check bit is, again, the Pico doing some random wait thing.

And that's it for now. The start of a long journey but getting any response at all in SD mode is far from simple. I'm pretty happy with where it is and am going to leave it here for now.


Last edited by AndrewP on Sat Aug 20, 2022 7:13 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 19, 2022 8:15 pm 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 298
You're not the only one. Yes, I could have used SPI mode just like everyone else. But where's the fun in that?

At the moment, I'm bit-banging the interface in software. The VHDL interface is waiting for a better understanding of what it needs to do, freeing up some space in the FPGA, and for me to find sufficient time and strength to do it. That's going to be a long wait.

The specification is a very big document. The information you need is scattered all the way through it. Hit your head against it enough, and you will eventually learn how to find things. But there will always be surprise bits of information in footnotes in chapters you haven't even glanced at. They'll turn out to be important.

My power-up sequence goes:
  • CMD0 "GO_IDLE_STATE"
  • CMD8 "SEND_IF_COND"
  • CMD55 "APP_CMD", ACMD41 "SD_SEND_OP_COND" with argument 40100000 (HCS=1, voltage = 3.3). The R3 response has HCS and the supported voltages set. Repeat until bit 31 of the response is 1.
  • CMD2 "ALL_SEND_CID" with argument 00000000. The R2 response has the CID. I ignore it.
  • CMD3 "SEND_RELATIVE_ADDR" with argument 00000000. The R6 response contains the RCA and some status that I ignore.

The card is now in the stand-by state. Reading a block is accomplished by
  • CMD7 "SELECT/DESELECT_CARD" with argument bits 31-16 = the RCA you were given, 15-0 = 0. The R1b response I ignore.
  • CMD17 "READ_SINGLE_BLOCK" with argument = the block address. The R1 response I ignore, but there will also be the block data. Keep toggling the clock, and you'll eventually see a start bit followed by a block of data and a CRC.
For a while I was trying to send CMD12 "STOP_TRANSMISSION" and wondering why I wasn't getting a response. But that command can only be used if you asked for multiple blocks. I'm OK with the inefficiency of reading blocks one at a time, so now I don't send it.

I haven't implemented block writes yet.

You'll need two CRC routines. I found them fairly straight-forward, following the description in section 4.5. I do them one bit at a time as the bit is sent, rather than trying to work a byte at a time. There are examples in the specification to test with, and I can provide more if you need them.

I can post my code if it would help. It's for my 65020 CPU, which although derived from and compatible with the 6502, is not a 6502. You wouldn't be able to use it directly.


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 19, 2022 8:29 pm 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
reading a bit online, i'm not sure if SD Mode is ok to use for hobbyist.
you need a licence to be allowed to implement an SD Mode interface for a commercial product, or even to get the full documentation on the standard. but DIY projects like these aren't about selling a product (they are about learning and giving hobbyists more things to play with!) so i don't know if a licence is still required to publish this kind of information and potentially fully functional SD compatibile controllers online for free.

overall i can kinda see why no one really bothers with SD-Mode, it seems like a legal headache for open source/public projects.


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 19, 2022 9:22 pm 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 298
There are parts of the specification missing from the freely-downloadable document, but they aren't necessary to implement a hobbyist-level interface. It includes timing specification (rise and fall times, setup and hold, etc), but not voltage thresholds and power consumption. And I think some details of some of the advanced features that I have no intention of using are omitted too.
Curiously, the timing specification for SPI mode is one of the things that's missing.

No reverse-engineering is required - everything you need is in the freely available document. It's not easy to find, because it's a huge document. But it is in there.

"No one" (it's not really no one) uses SD mode because the microcontrollers that people tend to use already have SPI in hardware, and SPI mode is a little easier to implement - the CRCs are optional, to start with. SD mode is more work. That's all it is.

The legal argument strikes me as a red herring. There is no difference in licencing between SD mode and SPI mode. If you need it for the way you're using SD mode, you need it for SPI mode too. If I was selling a product, I would have to do things properly. But I'm not and have no intention to.


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 19, 2022 10:04 pm 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
John West wrote:
There are parts of the specification missing from the freely-downloadable document, but they aren't necessary to implement a hobbyist-level interface. It includes timing specification (rise and fall times, setup and hold, etc), but not voltage thresholds and power consumption. And I think some details of some of the advanced features that I have no intention of using are omitted too.
Curiously, the timing specification for SPI mode is one of the things that's missing.

No reverse-engineering is required - everything you need is in the freely available document. It's not easy to find, because it's a huge document. But it is in there.

well that's good to know. though honestly the interface still seems like a pain to implement compared to SPI (though it's be interesting to see what kind of speeds can be gotten with the 4-bit SD-Mode)
John West wrote:
"No one" (it's not really no one) uses SD mode because the microcontrollers that people tend to use already have SPI in hardware, and SPI mode is a little easier to implement - the CRCs are optional, to start with. SD mode is more work. That's all it is.

i should've rather said that it's harder to find projects using SD Mode since, like you said, SPI is more commonly used due to it being more available in Microcontrollers and such.
John West wrote:
The legal argument strikes me as a red herring. There is no difference in licencing between SD mode and SPI mode. If you need it for the way you're using SD mode, you need it for SPI mode too.

hmm, i don't think so. it makes sense that SPI wouldn't require a license as the SD Association doesn't own the SPI spec. So they have no legal right to lock it behind a paywall, unlike their self made SD-Modes.
John West wrote:
If I was selling a product, I would have to do things properly. But I'm not and have no intention to.

yea that's fair, and i doubt they would actually go after some random DIY projects online.
I think i'm overreacting because i don't know much about legal stuff so i try to steer clear of anything close to being in a legal gray/red zone... sorry about that.


Top
 Profile  
Reply with quote  
PostPosted: Sat Aug 20, 2022 9:14 pm 
Offline

Joined: Wed Mar 02, 2016 12:00 pm
Posts: 343
I can understand your frustration. And I have only used the SD interface in SPI mode… but there is really no «correct» way to get all cards to work. I even used error checksums (which most DIY instructions jumps over). So I settled with one card working. I can’t say it is finished, but at least its able to read files 99% of the time.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 21, 2022 8:24 am 
Offline
User avatar

Joined: Mon Aug 30, 2021 11:52 am
Posts: 268
Location: South Africa
John West wrote:
My power-up sequence goes:
  • CMD0 "GO_IDLE_STATE"
  • CMD8 "SEND_IF_COND"
  • CMD55 "APP_CMD", ACMD41 "SD_SEND_OP_COND" with argument 40100000 (HCS=1, voltage = 3.3). The R3 response has HCS and the supported voltages set. Repeat until bit 31 of the response is 1.
  • CMD2 "ALL_SEND_CID" with argument 00000000. The R2 response has the CID. I ignore it.
  • CMD3 "SEND_RELATIVE_ADDR" with argument 00000000. The R6 response contains the RCA and some status that I ignore.

The card is now in the stand-by state. Reading a block is accomplished by
  • CMD7 "SELECT/DESELECT_CARD" with argument bits 31-16 = the RCA you were given, 15-0 = 0. The R1b response I ignore.
  • CMD17 "READ_SINGLE_BLOCK" with argument = the block address. The R1 response I ignore, but there will also be the block data. Keep toggling the clock, and you'll eventually see a start bit followed by a block of data and a CRC.
For a while I was trying to send CMD12 "STOP_TRANSMISSION" and wondering why I wasn't getting a response. But that command can only be used if you asked for multiple blocks. I'm OK with the inefficiency of reading blocks one at a time, so now I don't send it.
Thanks, that is most helpful!

What I really want to do is read in data as 8 bits at 10MHz. Why? Well in theory (and simulation) I have a DMA transfer that can do 1 byte every 100ns (or 10MB/s) and that seems like a perfect match for an SD card. For a '816 based system with limited memory being able to dump data into memory faster than the CPU can read it opens the door to some interesting tricks. But I'm rambling and none of this exists in the real world.

More practically what I actually have is '816 stress testing board which is an '816 connected directly to 512KB of SRAM. Absolutely nothing else, no address decoding, no nothing. Kinda. There is also a Raspberry Pi Pico on the board that can (slowly) write into memory when it has disabled the '816's bus. The Pico then disconnects itself from the bus, resets the '816 and lets it fly using an LTC6903 to generate PHI2. To check everything went well it disables the '816s bus again and (slowly) reads that memory back in.

Where does SD card reading come into this? Well, I need practice reading an SD Card for the future and I need *something* to put in memory for the '816 to run against. I also need to get the contents of that memory back out onto a (human) usable device. Plugging an SD card into a Windows PC just seems like less pain than trying to do '816 dev on Raspberry Pi 4.

John West wrote:
You'll need two CRC routines. I found them fairly straight-forward, following the description in section 4.5. I do them one bit at a time as the bit is sent, rather than trying to work a byte at a time. There are examples in the specification to test with, and I can provide more if you need them.

I can post my code if it would help. It's for my 65020 CPU, which although derived from and compatible with the 6502, is not a 6502. You wouldn't be able to use it directly.
Thanks again. Any source code to use as reference would be really useful. I'm using this website to check my CRC calculations so no worries on the CRC front.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 21, 2022 10:21 am 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 298
OK, here it is. The CPU is based on the 6502, but there are some important differences you'll need to know to understand the code.

Memory locations are 16 bits wide. So address 0 contains 16 bits, address 1 contains another 16 bits, and so on. Registers are 32 bits wide. The .w and .l suffixes on instructions indicate that it's operating on 16 or 32 bits of data. 32 bit data in memory is stored in an unusual format in two consecutive locations, but I don't think the details are important here.

There are twelve general purpose registers: A0 to A3, X0 to X3, and Y0 to Y3. LDR and STR are aliases for LDA, LDX, LDY and STA, STX, STY that choose the right instruction based on the register they're given. Similarly, PSH and PUL are aliases for PHA, PHX, PHY and PLA, PLX, PLY. RLB is like ROL, except it doesn't include carry. BRA is an unconditional branch. BRA.l pushes the value of PC before it branches: it's just like JSR, except one location shorter and one cycle faster if the destination is within +/-32K. Shift and rotate instructions have an optional immediate operand, which specifies how many bits to shift.

Registers used in indexed addressing are always 32 bits. I often swap the interpretation of address and index, so instead of being a (small on the 6502) variable offset from a fixed base address, I have a small fixed offset from a variable base. In softSD_checkDat0, rol.w 0, x0 is shifting the new bit into the location that x0 points to. The buffer isn't at 0.

The entry points for this code are softSD_init, softSD_read_block, and softSD_write_block. That last one is still using a 512 location buffer, with 8 bits per location. And it hasn't been tested properly, so might not work at all.

Finally, the board I'm using (a Papilio Duo with the Classic Computing shield) only connects one of the data lines, so I am only using DAT0. Using all four looks like a headache I don't need to have.


Attachments:
softSD.asm [11.73 KiB]
Downloaded 43 times
Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 23, 2022 12:15 pm 
Offline
User avatar

Joined: Mon Aug 30, 2021 11:52 am
Posts: 268
Location: South Africa
John West wrote:
OK, here it is. The CPU is based on the 6502, but there are some important differences you'll need to know to understand the code.
Thanks, I've seen your posts on the 65020 and would love to see a fast, modern successor to the 6502 / 65816. My life would be so much easier if I could only use one fast MPU rather than four slow 65816s. But I digress. The 65020s assembly was easy enough to read and the specification page number comments were a great help.

Actually your previous comment was a life saver. I was sending ACMD41 with argument 0x40000000 instead of 0x40100000 because I was reading the SPI argument format instead of the SD mode argument format (that bit is reserved and should be 0 in SPI mode). My card was just sitting in an endless busy loop and had me stumped. I suspect ACMD41 with argument 0x00000000 would have worked too but that's an experiment for another time.

So far I've gotten CMD0 to CMD8 to CMD55 + CMD41 (ACMD41) to give me a positive response in SD mode I'll post up some of the timing quirks I ran into in a longer message later. Also worth noting the 74 CLK ticks before CMD0 are required by the specification (page 231) and the 8 ticks after CMD0 are too but I can no longer find where I read that.

Other interesting mistakes I made. CMD55 (the first half of an application specific command) has a response (R1) and testing with an oscilloscope attached rather than a logic analyzer was invaluable as I could see that both the Pico and the Card were driving the CMD line at the same time.

I used 47KΩ pull-up resistors but I should have used something smaller (10KΩ being the smallest suggested). They didn't pull-up fast enough so when I put the Pico CMD pin in input mode it immediately saw a low voltage and thought it was the start transmission bit from the SD card. The work around I'm using is to set the CMD pin as an input (i.e. high impedance) for 4 clocks ticks before I start reading from it and looking for a low. The SD card generally starts driving the CMD line around tick two and starts transmitting around tick 7 after the end of the command transmission.

John West wrote:
Finally, the board I'm using (a Papilio Duo with the Classic Computing shield) only connects one of the data lines, so I am only using DAT0. Using all four looks like a headache I don't need to have.
Some time ago I looked into buying a Papilio Duo but it wasn't in stock (and looks like it isn't again) because it seemed like quite a good way to get into FPGA dev. I've settled on discrete ICs since then ... so ... er. Ya.


Last edited by AndrewP on Tue Aug 23, 2022 12:32 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 23, 2022 12:30 pm 
Offline
User avatar

Joined: Mon Aug 30, 2021 11:52 am
Posts: 268
Location: South Africa
kakemoms wrote:
I can understand your frustration. And I have only used the SD interface in SPI mode… but there is really no «correct» way to get all cards to work. I even used error checksums (which most DIY instructions jumps over). So I settled with one card working. I can’t say it is finished, but at least its able to read files 99% of the time.
Yup I'm using this SanDisk card (with a Sparkfun breadboard adapter)
Attachment:
20220823_142107.jpg
20220823_142107.jpg [ 912.34 KiB | Viewed 1375 times ]
... and I've managed to get it stuck in modes where it just will not respond without cycling the power.

I'm going to probably go the same route where I can get a card working and stick with it; there's just too much wriggle room in the spec. I like the SanDisk 16GB Ultras because they're *really* cheap but run fine in high performance mode.


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 21, 2022 12:26 pm 
Offline
User avatar

Joined: Tue Aug 11, 2020 3:45 am
Posts: 311
Location: A magnetic field
Thank you for doing this essential work. A trend I've noticed in computing is that a storage interface gets deprecated when a linear scan takes more than 48 hours. (Sheep64's 48 Hour Rule.) If I leave a disk formatting on Friday and it isn't finished by Monday then it isn't practical. Likewise for an unindexed search. This limitation applied to ST-506 and IDE. It now applies to 512GB MicroSD accessed at 15Mb/s (or variations thereof).

A quad channel interface gains two iterations of Moore's law. The practical benefit of your work is that neo-retro enthusiasts will be able to buy contemporary consumer storage for an additional four years. Beyond that, I presume that an optical interface is essential.

AndrewP on Tue 23 Aug 2022 wrote:
I like the SanDisk 16GB Ultras because they're *really* cheap but run fine in high performance mode.


You might want to investigate Samsung MicroSD. From various firmware updates for cameras, phones and televisions, it is widely known that within the vendor-specific range of control codes, code zero enters debug mode and code one exits debug mode. When a Samsung MicroSD is in debug mode, arbitrary blocks of memory can be read or written. Its ARM microcontroller can also be instructed to execute from arbitrary address. This functionality can be used to temporarily install 6502 simulator. This simulation may have very fast and reliable access to the MicroSD's raw storage - which may be many multiples of the official size. Even without access to storage, this is a cheap, portable and energy efficient way to cluster 6502 simulators - and does not prevent subsequent use as general purpose storage.

There is precedent with 6502 storage. I believe that it is possible to send 256 bytes of executable code to a Commodore floppy drive and this mechanism was occasionally used for copy protection - or, more recently, the obscure demoscene category of Commodore floppy drive music. There is also a strong association between 6502 and ARM. Anyhow, running 6502 on ARM and running 6502 and a storage unit are both accepted practices. However, I don't believe that anyone has combined the practices or run 6502 programs on such small and affordable storage units.

_________________
Modules | Processors | Boards | Boxes | Beep, Beep! I'm a sheep!


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

All times are UTC


Who is online

Users browsing this forum: janrinze and 12 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: