SD Card start up
Hello,
I am trying to get the SD card to respond on the P2 Edge. I ran a program that comes with Flexprop, sd_dir.bas, to make sure my card does work. Originally i got no output but now i've been able to get F6 and added a timeout to the program. It seems to always time out though. I did read a few other pieces of code in the obex and saw the response for success should be 0x01. I'm confused on what kind of timing is needed for the card to return CMD0 correctly though.
_CLKFREQ = 180_000_000 BAUD_RATE = 2_000_000 SERIAL_CLOCK = (_CLKFREQ / BAUD_RATE) BIT_PERIOD = ((SERIAL_CLOCK << 16) & $FFFFFC00) + (8 - 1) ' P2 smartpin bit-period calc RX_PIN = 63 TX_PIN = 62 SD_CS = 60 SD_CLK = 61 SD_MOSI = 59 SD_MISO = 58 dat org 0 asmclk main ' UART RX setup wrpin ##(P_ASYNC_RX | P_HIGH_15K), #RX_PIN wxpin ##BIT_PERIOD, #RX_PIN wypin #1, #RX_PIN dirh #RX_PIN ' UART TX setup wrpin ##(P_ASYNC_TX | P_OE), #TX_PIN wxpin ##BIT_PERIOD, #TX_PIN wypin #1, #TX_PIN dirh #TX_PIN ' SD pin directions drvh #SD_CS ' Deselect SD card dirh #SD_CS dirh #SD_CLK dirh #SD_MOSI dirl #SD_MISO ' Let MISO float as input ' UART startup test mov result, #"S" call #uart_tx_char mov result, #13 ' CR call #uart_tx_char mov result, #10 ' LF call #uart_tx_char ' Set bit_delay for SPI clock (200 kHz) mov bit_delay, ##(_CLKFREQ / 200_000) ' Send 80 dummy clocks with CS high (SD reset) mov temp, #80 .send_dummy drvh #SD_MOSI drvl #SD_CLK waitx bit_delay drvh #SD_CLK waitx bit_delay djnz temp, #.send_dummy ' Send CMD0 (GO_IDLE_STATE) drvl #SD_CS ' Select card mov transfer_data, #$40 ' CMD0 call #spi_tx8 mov transfer_data, #0 ' Argument = 0 call #spi_tx8 call #spi_tx8 call #spi_tx8 call #spi_tx8 mov transfer_data, #$95 ' Valid CRC for CMD0 call #spi_tx8 ' Send a few extra clocks (important!) mov temp, #10 .send_post mov transfer_data, #$FF call #spi_tx8 djnz temp, #.send_post ' Wait for response 0x01 (Idle state) mov temp2, #100 .wait_response mov transfer_data, #$FF call #spi_tx8 mov result, transfer_data call #print_hex_byte mov result, #" " call #uart_tx_char cmp transfer_data, #$01 wz if_z jmp #.got_response djnz temp2, #.wait_response ' Timed out mov result, #"T" call #uart_tx_char jmp #$ .got_response drvh #SD_CS ' Deselect card again mov result, #"!" call #uart_tx_char mov result, #13 call #uart_tx_char mov result, #10 call #uart_tx_char jmp #$ ' Transmit & receive 8-bit over SPI (MSB first) spi_tx8 mov result, #0 mov bitcnt, #8 mov temp3, transfer_data .txbit rcl temp3, #1 wc drvc #SD_MOSI drvl #SD_CLK waitx bit_delay drvh #SD_CLK waitx bit_delay testp #SD_MISO wc rcl result, #1 djnz bitcnt, #.txbit drvh #SD_MOSI ' Idle MOSI high mov transfer_data, result ret ' Print byte in RESULT as 2 hex chars print_hex_byte mov temp, result shr temp, #4 ' High nibble mov result, temp call #print_nibble and result, #$0F ' Low nibble call #print_nibble ret print_nibble cmp result, #10 wc if_b add result, #"0" if_nc add result, #"A"-10 call #uart_tx_char ret ' UART TX single character from RESULT uart_tx_char wypin result, #TX_PIN .wait_tx rdpin pr0, #TX_PIN wc if_c jmp #.wait_tx ret ' Variables bitcnt res 1 temp res 1 temp2 res 1 temp3 res 1 cnt res 1 result res 1 bit_delay res 1 transfer_data res 1
Comments
Are you sure you're wanting to talk directly to the SD card and not rather use existing ready to go libraries instead? Flexspin, for example, comes with the well tested C libs that can also be used by Spin programs.
Hi @evanh!!
Yes for now, it’s more about learning the assembly behind it than any kind of major project. If I need to I can just program anything I needed to use in production using C.
I think the timing for the Sd card or spi might be a little more strict than anything I’ve seen before.
Well, you might want to read the spin2 SD card driver, sdspi_bashed3.spin2, for FSRW or Kye's FAT32, I don't remember which API is which ... I fixed it up not long ago. The original had some missing checks in it that had made SD card support flaky prior to that.
https://forums.parallax.com/discussion/comment/1563810/#Comment_1563810
This snippet, at the head of the command routine, I think I took it from Flexspin's driver. It ensures a deselect-select cycle for every command except CMD12. And it also waits for the card to return from any busy activity. The old bashed driver didn't check anything I don't think.
Also, be aware that SD cards can get confused and not respond to anything. Sometimes you just have to resocket it. Roger added a controlled power switch to his 4-bit wired add-on board that allows the driver to power cycle the SD card at its convenience. https://forums.parallax.com/discussion/174988/new-sd-mode-p2-accessory-board/p1
And Rayman followed suit with his nice Propeller 2 Platform board https://forums.parallax.com/discussion/comment/1566287/#Comment_1566287
@evanh, Thanks for the suggestions! You're driver i must have missed some kind of way.
I'm re-writing a few things based on this and eliminating many assumptions in the code. I'm doing a few manual test before i send the $40 now. Any particular reason it gets confused? Does that mean that it might sometimes randomly drive something high or low? Or is is literally i need to take the card out and put it back in sometimes?
Also i corrected the code in the print_hex. I was printing high high instead of high low i noticed after going block by block. So far, I have a check to
Before:
After:
There will always be a reason. But I was pretty green when modifying the SPI mode stuff. And since it was already a done thing I mostly just optimised the low level bit-shifting routines at the time. Flexspin's original bit-bashing was very slow.
That said, SPI mode, unlike SD mode, is supposed to always respond to a command. Also, one can enter SPI mode from SD mode but not the reverse. That's one sure way to not get a response - Issue a SD mode CMD0 when already in SPI mode.
I just tested your code. It works when the "Flash" EEPROM is disabled.
Methods of sharing the pins is something that hasn't been documented by Parallax. The various developers have bumbled their ways through it. Easiest to just leave the EEPROM disabled for the moment.
I got the scope out to figure out why the EEPROM was such a problem when you're using SPI cmode 3, it shouldn't conflict ... found bugs!!!
First, you'd missed pre-shifting the tx byte,
temp3
, to the left end of the 32-bit register. You were just transmitting all zeros. I don't know why any combination appeared to work now.Next,
transfer_data
was being overwritten and therefore not holding its prior value, yet you were sending the command as if it did hold its value.Lastly, the "extra clocks" loop was completely skipping over the SD card's response so you'd not be seeing it even if the card had responded.
The initial pin setup wasn't ensuring the pins got set high either. Although I don't think that actually caused any problems.
Here's my hacked around version:
@evanh > @evanh said:
That checks out. I've been able to find a lot of tutorials and after the post to help. There is one by a fellow named potato-head and a ray desilva. But I think the documentation is kind of spread out. At least I know I am not the only one that has stumbled in the dark a bit.
I may need to purchase one then and learn to use it. Most of the soldering an projects I have done have been from basic electronics books as a hobby. Any recommendations on said scope?
I did see this one along with some other things that were not needed. I am still cleaning that up but I am going to merge what you have presented with what I have and clean things up a bit.
I think at this point I honestly want to shift directions on making things per and just do an unofficial document on learning the assembly stuff. At least someone coming behind me may not have to stumble as much. Thank you very much!
IMO: Get one of those sub-10€/$ 8ch USB logic analyzers. They're not good per se, but infinite times better than poking around in the dark, amazing value.
Your assembly ain't too bad really, just you've picked a messy problem to work with. I assume you've done a decent amount of assembly on other architectures already.
That said, yes, do tidy it up. More structure will help. Assembly lacking scoping of variables makes it too easy to reuse them when they probably shouldn't be. All too guilty of that myself.
Hello @Wuerfel_21!
Thank you! I'm going to go check that out this week then.
Thank you. Yes, I am coming from the Z80/6520 assembly world, strictly hobby stuff. I was able to pick up a piece of equipment called the Hydra Game Development Kit. It is great really, though it uses the P1 chip, and got me interested in learning more about Parallax stuff.
Will definitely do! Others have said I need to do the same so I think I really will now. Thank you again!
The Propellers caught my attention because of the open multicore access to all the hardware, and using assembly is well supported and in an uncomplicated way. Hitting the metal in a multicore environment is encouraged!
Get one that has a couple of analogue channels too. It's always good to be able to verify voltages and slopes to be sure the logic is powered properly.