Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

about SD-card initialization #4

Closed
kittennbfive opened this issue Oct 14, 2023 · 20 comments
Closed

about SD-card initialization #4

kittennbfive opened this issue Oct 14, 2023 · 20 comments

Comments

@kittennbfive
Copy link
Contributor

Hi,

just a note about this:

Max tested SPI bus speed is FCLK/16, which is 1MHz on 16MHz atmega328p. If you set the speed higher than this, SD card won't initialize. This might be just my problem, so feel free to try.

If i remember correctly the standard says that for initialization the speed should be <400kHz, but you can switch much higher once the initialization is done. Don't forget the SPI2X-bit for even more speed!

Maybe this helps...

@raspiduino
Copy link
Owner

Thank you for your tips! I will check it out soon!

@raspiduino
Copy link
Owner

raspiduino commented Oct 15, 2023

Is it correct if I add a line SPI_init(SPI_MASTER | SPI_2X_FOSC_2 | SPI_MODE_0); after the line SD_readOCR(res); in the file sdcard.c, as described here?

@maxgerhardt
Copy link

maxgerhardt commented Oct 15, 2023

In the library greiman/SdFat, the clock speed is upped to max after CMD58 is sent here, which would also match what your SD_readOCR() does -- maybe it helps to compare? It also does a spiStop() just before that though.

@kittennbfive
Copy link
Contributor Author

Is it correct if I add a line SPI_init(SPI_MASTER | SPI_2X_FOSC_2 | SPI_MODE_0); after the line SD_readOCR(res); in the file sdcard.c, as described here?

At first glance this is the correct thing to do, however looking at the code https://github.com/raspiduino/arv32-opt/blob/f831c56cb7dc86fe63289bde70ce3d3ea5242d68/spi.c#L20C1-L21C36 there is a binary OR made instead of a plain write to SPCR and SPSR. This could make a mess depending on the constants as bits that may need to be cleared won't be cleared. You have to check carefully or change this code i think.

@raspiduino
Copy link
Owner

Is it correct if I add a line SPI_init(SPI_MASTER | SPI_2X_FOSC_2 | SPI_MODE_0); after the line SD_readOCR(res); in the file sdcard.c, as described here?

I have tried this, and it actually worked! I increased the clock to 8 MHz, and the average speed got up to 1100Hz. But the emulator will hang if I connect pin 9 to GND (to check speed), for some reason. If I just leave it there and don't check the speed, it will work.

At start:

4c58bc3b-6373-43ee-99f4-bbccb1d13610

Peak speed(?):

f2020abe-cd54-4be7-b270-4baeee2ff333

One hour from start:
ece3d747-4ffc-4bc2-a096-d8a7a5e03308

@kittennbfive
Copy link
Contributor Author

kittennbfive commented Oct 28, 2023

But the emulator will hang if I connect pin 9 to GND (to check speed), for some reason

Did you release pin 9 again? There is a loop in your code that will wait until pin 9 is high again: https://github.com/raspiduino/arv32-opt/blob/f9d3f5ff05c057cd85f6ce3f32edb875d328cb75/main.c#L301C13-L301C44

@raspiduino
Copy link
Owner

raspiduino commented Oct 29, 2023

But the emulator will hang if I connect pin 9 to GND (to check speed), for some reason

Did you release pin 9 again? There is a loop in your code that will wait until pin 9 is high again: https://github.com/raspiduino/arv32-opt/blob/f9d3f5ff05c057cd85f6ce3f32edb875d328cb75/main.c#L301C13-L301C44

Yes, I released it. That's weird. I think maybe because my SD card is damaged, sometime it also unreadable. I will try switching to another SD card.

@raspiduino
Copy link
Owner

There is a related issue #5 which also occurs when the SPI clock is 8MHz. Changed it back to 1MHz solved the problem, but I don't know why it will hang at 8MHz

@kittennbfive
Copy link
Contributor Author

I am afraid your commit a3a42ad did not change the SPI frequency to 8MHz (Fosc/2) but only to 250kHz (Fosc/64). This is because as i said you are doing an binary OR instead of a plain write to SPCR and SPSR.
I just simulated this with some code, carefuly compare the results of this code with the datasheet of the 328P:

#include <stdio.h>
#include <stdint.h>

#define SPE 6
#define SPI_MASTER          0b0001000000000000
#define SPI_SLAVE           0b0000000000000000
#define SPI_FOSC_4          0b0000000000000000
#define SPI_FOSC_8          0b0000010100000000
#define SPI_FOSC_16         0b0000000100000000
#define SPI_FOSC_64         0b0000001000000000
#define SPI_FOSC_128        0b0000001100000000
#define SPI_2X_FOSC_2       0b0000000000000001
#define SPI_2X_FOSC_8       0b0000000100000001
#define SPI_2X_FOSC_32      0b0000001000000001
#define SPI_2X_FOSC_64      0b0000001100000001
#define SPI_INTERRUPTS      0b1000000000000000
#define SPI_MODE_0          0b0000000000000000
#define SPI_MODE_1          0b0000010000000000
#define SPI_MODE_2          0b0000100000000000
#define SPI_MODE_3          0b0000110000000000
#define SPI_DEFAULT         SPI_MASTER | SPI_FOSC_128 | SPI_MODE_0


int main(void)
{
    uint16_t initParams;
    uint8_t SPCR=0;
    uint8_t SPSR=0;
    
    
    initParams=SPI_DEFAULT;
    SPCR |= ((uint8_t) (initParams >> 8)) | (1 << SPE);
    SPSR |= ((uint8_t) initParams);
    printf("SPCR: 0x%02X\n", SPCR);
    printf("SPSR: 0x%02X\n", SPSR);
    
    printf("\n");
    
    initParams=SPI_MASTER | SPI_2X_FOSC_2 | SPI_MODE_0;
    SPCR |= ((uint8_t) (initParams >> 8)) | (1 << SPE);
    SPSR |= ((uint8_t) initParams);
    
    printf("SPCR: 0x%02X\n", SPCR);
    printf("SPSR: 0x%02X\n", SPSR);
    
    return 0;
}

However i am not sure this explains the instability/problems you are encountering. :( But in any case i would suggest fixing sdcard.c (by removing the OR) and try again with max speed. If this does not work maybe you have some electrical issue (signal integrity, ...)? Can you check with a scope?

@raspiduino
Copy link
Owner

raspiduino commented Nov 7, 2023

did not change the SPI frequency to 8MHz (Fosc/2) but only to 250kHz (Fosc/64).

But if that's true, then I don't understand why the effective emulated speed is even higher than the speed when I run with 1MHz SPI clock.

This is because as i said you are doing an binary OR instead of a plain write to SPCR and SPSR.

Stupid me. I should have changed it to = instead of |=, right?

I'm not really good at plain AVR C registers tho, sorry for that.

@kittennbfive
Copy link
Contributor Author

I should have changed it to = instead of |=, right?

Yes, exactly. = is an assignment, |= is a logical OR between the current value inside the register and the new one.

For the speed issue i am not sure, i think you should fix sdcard.c and then test again. And if possible check the real clock speed of the SPI-bus with an oscilloscope or logic analyzer.

@raspiduino
Copy link
Owner

I just do that and the SD read failed 10 times in a row. I will try again later, probably my SD card problem.

@kittennbfive
Copy link
Contributor Author

I will see if i have a SD card somewhere and try myself if time allows.

@kittennbfive
Copy link
Contributor Author

kittennbfive commented Nov 7, 2023

DDR_SPI |= (1 << MISO);

That's not correct! If you want a pullup (which shouldn't be needed btw) you must write a '1' to PINx PORTx. Here you are setting MISO as an output so the SD card and the AVR will "fight" against each other!

EDIT: correction :(

@kittennbfive
Copy link
Contributor Author

kittennbfive commented Nov 7, 2023

Ok, so SPI2X does not work. I guess SD in SPI-mode have a maximum clock frequency <=4MHz? Does anybody know? This is weird...

However with 4MHz (XTAL/4) it works fine with my own SD-card routines. I used those because i am obviously more familiar with them. You can find them on my github but please note that they are AGPLv3+, so probably not compatible with your project. Of course you can look at them to see how they work anway, but you probably can't copy them to your project (you should specify a licence!).

My remark about the wrong register for Pullup also applies to the pin for dumping the emulator state. Should i make another PR to fix this?

EDIT: Speed is just above 2kHz for my test, Linux has started it's internal stuff, currently "devtmpfs: initialized". I will stop here to not write to much to the SD card.

@raspiduino
Copy link
Owner

That's not correct! If you want a pullup (which shouldn't be needed btw) you must write a '1' to PINx. Here you are setting MISO as an output so the SD card and the AVR will "fight" against each other!

Wait, so it should be PORT_SPI? I got that code from https://github.com/ryanj1234/SD_TUTORIAL_PART4/blob/b10700ff6571a1cc16299ad23dfeb40e90d7014d/spi.c#L17 and don't check it again because it already worked. My bad.

My remark about the wrong register for Pullup also applies to the pin for dumping the emulator state.

PORTB |= (1 << PINB1);

Wait, this code actually writes to PORTB, to enable pullup. I also didn't write anything to that pin's DDRB bit, so it should be 0 (input), right? So I don't really understand why the pullup code for pin 9 has wrong register used.

EDIT: Speed is just above 2kHz for my test, Linux has started it's internal stuff, currently "devtmpfs: initialized". I will stop here to not write to much to the SD card.

Thank you for testing. 2KHz is way much better than the normal 700Hz!

@kittennbfive
Copy link
Contributor Author

kittennbfive commented Nov 8, 2023

I apologize, i got confused. :( For the pullup it is indeed PORTx. It is not DDRx however, writing a '1' there will set the pin to output.
DDRx=1 -> output
PORTx=0/1 for 0/1 as output OR 1 for pullup for input

@mjungwirth
Copy link

Thanks for the great project!
With the standard 328a processor, I was able to get the boot time down to 8 hours, 18 minutes with the following changes:
spi.c:
// set SPI params
// SPCR |= ((uint8_t) (initParams >> 8)) | (1 << SPE);
// SPSR |= ((uint8_t) initParams);
SPCR = ((uint8_t) (initParams >> 8)) | (1 << SPE);
SPSR = ((uint8_t) initParams);

sdcard.c
//SPI_init(SPI_MASTER | SPI_2X_FOSC_2 | SPI_MODE_0);
// works! SPI_init(SPI_MASTER | SPI_2X_FOSC_8 | SPI_MODE_0);
SPI_init(SPI_MASTER | SPI_FOSC_4 | SPI_MODE_0);

Next up I plan to port the code to an Atmega1280 so I can increase the number of cache buffers with the extra RAM.
Cheers!
Mark Jungwirth

@raspiduino
Copy link
Owner

Thanks for the great project! With the standard 328a processor, I was able to get the boot time down to 8 hours, 18 minutes with the following changes: spi.c: // set SPI params // SPCR |= ((uint8_t) (initParams >> 8)) | (1 << SPE); // SPSR |= ((uint8_t) initParams); SPCR = ((uint8_t) (initParams >> 8)) | (1 << SPE); SPSR = ((uint8_t) initParams);

sdcard.c //SPI_init(SPI_MASTER | SPI_2X_FOSC_2 | SPI_MODE_0); // works! SPI_init(SPI_MASTER | SPI_2X_FOSC_8 | SPI_MODE_0); SPI_init(SPI_MASTER | SPI_FOSC_4 | SPI_MODE_0);

Next up I plan to port the code to an Atmega1280 so I can increase the number of cache buffers with the extra RAM. Cheers! Mark Jungwirth

Thank you! I will definitely try that soon! I would be happy to accept if you make a PR

@raspiduino
Copy link
Owner

I will close this as changes are merged to main. Feel free to reopen or create a new issue report if you want. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants