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
// 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.
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.
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:
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.
Maintaining a repository (or site or forum) is a lot like tending to a garden - it requires constant care and attention to keep it thriving. If you're a skilled gardener (or coder!) and want to help keep our repository blooming, we'd love to have you on board! We're also looking for talented writers and forum moderators to help us grow our community. Interested in joining our team? Don't hesitate to reach out and let us know how you can contribute!
Are you a fan of electronics or programming? Share your knowledge with others, write a simple tutorial or how to make a great project Contact me: share_your_ideas@mischianti.org
The content displayed on this website is protected under a CC BY-NC-ND license. Visitors are prohibited from using, redistributing, or altering any content from this website for commercial purposes, including generating revenue through advertising. Any unauthorized use is a violation of the license terms and legal action may be taken against individuals or entities found to be in violation.
You must also provide the link to the source.
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.