Tagged: SdCard, SDFAT, STM32, STM32Duino
- This topic has 5 replies, 2 voices, and was last updated 1 year, 6 months ago by
Renzo Mischianti.
-
AuthorPosts
-
-
3 November 2023 at 08:53 #27967
Hello,
I’m trying to connect my STM32L452 chip to an SD Card for logging purpose but it doesn’t seem to work using port assignation delivered by STM32duino.
I tried using STM32Cube libraries and it’s working, so the problem is not on my PCB but really the SdFat and/or STM32duino and the way I’m initializing things.I tried to use the code example you provided in here which is shown bellow with the only modification being the SPI port values. I wonder if only STM32F1 and F4 are supported and is there a way to make it work for L4 boards.
/* SD card test for stm32 and SdFat library This example shows how use the utility libraries SD card attached to the secondary SPI as follows: SS = PB2; MOSI = PC3; MISO = PC2; SCK = PB10; by Mischianti Renzo <https://mischianti.org> https://www.mischianti.org */ #include <SPI.h> #include "SdFat.h" SdFat SD; // Define your pin configuration for SPI2 const int spi2ClockPin = PB10; // SCK (Serial Clock) const int spi2MisoPin = PC2; // MISO (Master In Slave Out) const int spi2MosiPin = PC3; // MOSI (Master Out Slave In) const int spi2chipSelectPin = PB2; // CS (Chip Select) #define SD2_CONFIG SdSpiConfig(spi2chipSelectPin, USER_SPI_BEGIN,SD_SCK_MHZ (10)) void printDirectory(File dir, int numTabs); void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } SPIClass SPI_2(spi2MosiPin, spi2MisoPin, spi2ClockPin); SPI_2.begin(spi2chipSelectPin); // SPI_2.setFrequency(1000000); Serial.print("\nInitializing SD card..."); // we'll use the initialization code from the utility libraries // since we're just testing if the card is working! if (!SD.begin(SD2_CONFIG)) { // if (!SD.begin(SD_CS_PIN)) { Serial.println("initialization failed. Things to check:"); Serial.println("* is a card inserted?"); Serial.println("* is your wiring correct?"); Serial.println("* did you change the chipSelect pin to match your shield or module?"); while (1); } else { Serial.println("Wiring is correct and a card is present."); } uint32_t cardSize = SD.card()->sectorCount(); // print the type of card Serial.println(); Serial.print("Card type: "); switch (SD.card()->type()) { case SD_CARD_TYPE_SD1: Serial.println(F("SD1")); break; case SD_CARD_TYPE_SD2: Serial.println(F("SD2")); break; case SD_CARD_TYPE_SDHC: if (cardSize < 70000000) { Serial.println(F("SDHC")); } else { Serial.println(F("SDXC")); } break; default: Serial.println(F("Unknown")); } // print the type and size of the first FAT-type volume uint32_t volumesize; Serial.print("Volume type is: FAT"); Serial.println(int(SD.vol()->fatType()), DEC); Serial.print("Card size: "); Serial.println((float) 0.000512*cardSize); Serial.print("Total bytes: "); Serial.println(0.000512*SD.vol()->clusterCount()*SD.sectorsPerCluster()); Serial.print("Free bytes: "); Serial.println(0.000512*SD.vol()->freeClusterCount()*SD.sectorsPerCluster()); File dir = SD.open("/"); printDirectory(dir, 0); } void loop(void) { } void printDirectory(File dir, int numTabs) { while (true) { File entry = dir.openNextFile(); if (! entry) { // no more files break; } for (uint8_t i = 0; i < numTabs; i++) { Serial.print('\t'); } entry.printName(&Serial); if (entry.isDirectory()) { Serial.println("/"); printDirectory(entry, numTabs + 1); } else { // files have sizes, directories do not Serial.print("\t\t"); Serial.print(entry.size(), DEC); uint16_t pdate; uint16_t ptime; entry.getModifyDateTime(&pdate, &ptime); Serial.printf("\tLAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", FS_YEAR(pdate), FS_MONTH(pdate), FS_DAY(pdate), FS_HOUR(ptime), FS_MINUTE(ptime), FS_SECOND(ptime)); } entry.close(); } } #ifdef __cplusplus extern "C" { #endif /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = { 0 }; RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 }; /** Configure the main internal regulator output voltage */ if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) { Error_Handler(); } /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } #ifdef __cplusplus } #endif
Attachments:
You must be logged in to view attached files. -
3 November 2023 at 09:22 #27975
Hi Nezha,
I write a little article about that and when I do the test, I follow the pinout I retrieve from the STMicroelectronic core code.I check your pin selection, and it seems to be ok.
#ifdef HAL_SPI_MODULE_ENABLED WEAK const PinMap PinMap_SPI_MOSI[] = { {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PA_12, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PB_5_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, {PC_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, {PC_12, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, {NC, NP, 0} }; #endif #ifdef HAL_SPI_MODULE_ENABLED WEAK const PinMap PinMap_SPI_MISO[] = { {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PA_11, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PB_4_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, {PC_2, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, {PC_11, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, {NC, NP, 0} }; #endif #ifdef HAL_SPI_MODULE_ENABLED WEAK const PinMap PinMap_SPI_SCLK[] = { {PA_1, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)}, {PB_3_ALT1, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)}, {PC_10, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)}, {NC, NP, 0} }; #endif
The SS isn’t so important but if you can try the default also
// SPI definitions #ifndef PIN_SPI_SS #define PIN_SPI_SS PA4 #endif #ifndef PIN_SPI_SS1 #define PIN_SPI_SS1 PA15 #endif #ifndef PIN_SPI_SS2 #define PIN_SPI_SS2 PB0 #endif #ifndef PIN_SPI_SS3 #define PIN_SPI_SS3 PNUM_NOT_DEFINED #endif #ifndef PIN_SPI_MOSI #define PIN_SPI_MOSI PA7 #endif #ifndef PIN_SPI_MISO #define PIN_SPI_MISO PA6 #endif #ifndef PIN_SPI_SCK #define PIN_SPI_SCK PA1 #endif
In the code, you begin two times the spi interface, and I think It can generate some problems.
Try to use a configuration declaration like this// SD card attached to the secondary SPI as follows: // SS = PB2; // MOSI = PC3; // MISO = PB15; // SCK = PB10; #define SD_CS_PIN PB12 static SPIClass mySPI2(PC2, PC3, PB10, SD_CS_PIN); #define SD2_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
then only one begin.
// we'll use the initialization code from the utility libraries // since we're just testing if the card is working! if (!SD.begin(SD2_CONFIG)) { // if (!SD.begin(SD_CS_PIN)) { Serial.println("initialization failed. Things to check:"); Serial.println("* is a card inserted?"); Serial.println("* is your wiring correct?"); Serial.println("* did you change the chipSelect pin to match your shield or module?"); while (1); } else { Serial.println("Wiring is correct and a card is present."); }
But check the STM32duino core can change the pin.
Try to use also the example I wrote and tested for the Arduino environment.
How to use SD card with stm32 and SdFat library
Bye Renzo
-
3 November 2023 at 15:34 #27976
Hello Renzo,
Thank you for your response! I actually tried your example but it did not work that’s why I posted in the forum. I don’t think I tried to start it twice. Here’s a code that I did for SPI1 port of my PCB and it works well.
void setup() { Serial.begin(9600); /////////////////////////////////////////////// // RADIO SETUP /////////////////////////////////////////////// SPIClass SPI_1(SPI1_MOSI, SPI1_MISO, SPI1_SCK); SPI_1.begin(SPI1_CS); // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... "));
I also tried the QuickStart example and it worked by hardcoding the default SPI values.
I did also change
#define SPI_DRIVER_SELECT 1 #define USE_SPI_ARRAY_TRANSFER 4
And then -see attachment- I kind of also forced the default SPI pins to be SPI2 ports: (CS = PB2, MOSI = PC3, MISO = PC2, SCK = PB10)
Where in the code could I hard code the pins it’s taking without compromising SPI1 port? Because I cannot just do it this way since I’m also using SPI1 for other purposes.For references you can see the second attachment that shows the output of the quickstart test which shows that the lib was able to connect with the SD CARD on SPI2.
I wonder why would it work when I hardcode the SPI values, but not when I assign custom ones..
I tried what you suggested and also this way to no luck:
#define SD_CS_PIN PB2 static SPIClass mySPI2(PC3, PC2, PB10); mySPI2.begin(SD_CS_PIN); #define SD2_CONFIG SdSpiConfig(SD_CS_PIN, USER_SPI_BEGIN, SD_SCK_MHZ(100), &mySPI2) if (!sd.begin(SD2_CONFIG)) {
I wonder if the bug is on sd.begin() side.
-
This reply was modified 1 year, 7 months ago by
Nezha.
Attachments:
You must be logged in to view attached files. -
This reply was modified 1 year, 7 months ago by
-
5 November 2023 at 11:12 #28008
Hi Nezha,
your problem. It’s very strange.
I think you can try to use a “first choice” SPI2 and “second choice” in coherence, like so:PB15
PB14
PB10and
PC3
PC2
PB13After that test, you can try the official STMicroelectronics core to check if STM32duino.
Bye Renzo
-
7 November 2023 at 17:31 #28045
Hello Renzo,
Thank you for your time. So I finally made it work. For some reason, it takes different tries to make the initialization happen.
If I power cycle, I need to reset the board and unmount/remount the card so the initialization would work.All this to say this is working on a STM32L4 !
You can check the issue I posted on SdFat github repo.
https://github.com/greiman/SdFat/issues/447 -
8 November 2023 at 10:14 #28048
Hi Nezha,
thanks for your feedback, not all makers work with STM32, if you’d like to share your projects we are happy to publish Them.
Bye Renzo
-
-
AuthorPosts
- You must be logged in to reply to this topic.