Page 1 of 1

STM32L452RE Configue SDMMC1 to HSI48?

Posted: Thu Jan 28, 2021 1:51 pm
by Bambo
Hi, i'm trying to link the HSI48 to SDMMC1 but i can't get the SD card to write to a file using STM32SD. The SD card info is read correctly however when trying to create a new file it fails. I've managed to have success by configuring the SDMMC1 to use PLLSAI1, but this clock is reserved for another peripherial so it can't be used. I've turned the HSI48 ON using the RCC_OscInitstruct and then set RCC_SDMMC1CLKSOURCE_HSI48 for the peripheral, but it fails to create new files.

Code: Select all

extern "C" void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };

    /* Configure LSE Drive Capability */
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_MSI | RCC_OSCILLATORTYPE_HSI48;
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
    RCC_OscInitStruct.MSICalibrationValue = 0;
    RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    RCC_OscInitStruct.PLL.PLLM = 1;
    RCC_OscInitStruct.PLL.PLLN = 40;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
        | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    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_4) != HAL_OK) {
        Error_Handler();
    }

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1;
    //PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLLSAI1;
    PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_HSI48;
    //PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
    //PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
   // PeriphClkInit.PLLSAI1.PLLSAI1N = 24;
    //PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
    //PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
    //PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
    //PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK | RCC_PLLSAI1_ADC1CLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
        Error_Handler();
    }

    /* Configure the main internal regulator output voltage */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
        Error_Handler();
    }
    /* Enable MSI Auto calibration */
    HAL_RCCEx_EnableMSIPLLMode();

}
13:49:28.244 -> Started
13:49:33.803 -> SDHC
13:49:33.803 -> Volume type is FAT
13:49:33.803 -> 32
13:49:33.803 -> Volume size is (MB): 14824
13:49:33.803 -> Did not create file.
13:49:33.803 -> Setup complete!
13:49:34.805 -> Finished! Size:
13:49:34.805 -> 0

Code: Select all

void setup() {
	Serial3.begin(115200);
    Serial3.println("Started");

    pinMode(SD1, OUTPUT);
    digitalWrite(SD1, HIGH);

    SystemClock_Config();

    delay(5000);  

	while (!card.init(SD_DETECT_NONE)) {
		Serial3.println("Init failed, is card inserted?");
		delay(10);
	}

    switch (card.type()) {
    case SD_CARD_TYPE_SD1:
        Serial3.println("SD1");
        break;
    case SD_CARD_TYPE_SD2:
        Serial3.println("SD2");
        break;
    case SD_CARD_TYPE_SDHC:
        Serial3.println("SDHC");
        break;
    default:
        Serial3.println("Unknown card type.");
        break;
    }

    if (!fatFs.init()) {
        Serial3.println("Couldn't find FAT16/FAT32 partiton");
        return;
    }

    Serial3.println("Volume type is FAT");
    Serial3.println(fatFs.fatType(), DEC);

    uint64_t volume_size;
    volume_size = fatFs.blocksPerCluster();
    volume_size *= fatFs.clusterCount();
    volume_size *= 512;
    volume_size /= 1024;
    volume_size /= 1024;
    Serial3.print("Volume sie ix (MB): ");
    Serial3.println(volume_size);

    out_file = SD.open("T.TXT", FILE_WRITE);
    out_file.print("hello");
    out_file.close();

    if (SD.exists("T.TXT")) {
        Serial3.println("Created file OK");
    }
    else {
        Serial3.println("Did not create file.");
    }

    out_file = SD.open("T.TXT", FILE_WRITE);

	Serial3.println("Setup complete!");

    time_started = micros();

    end_time = time_started + 1000000;
}

void loop() {
    if (micros() < end_time) {
        out_file.write(3);
    }
    else {
        Serial3.println("Finished! Size: ");
        Serial3.println(out_file.size());
        out_file.close();
        delay(100000);
    }
}

Re: STM32L452RE Configue SDMMC1 to HSI48?

Posted: Thu Jan 28, 2021 2:41 pm
by fpiSTM
Well, that's sound logical...
Where is the:

Code: Select all

SD.begin(SD_DETECT_PIN)
Moreover you don't need to call the systemClockConfig in the setup... seems you don't understand what is a weak function.

Please use the default examples provided (adding your specifoc clock config) and then check if they work.
I've tested the SD with the Nucleo L452RE without any issue.

Re: STM32L452RE Configue SDMMC1 to HSI48?

Posted: Thu Jan 28, 2021 2:59 pm
by Bambo
Ok i removed the call to the SystenmClock_Config(), but this sketch (from here https://www.arduino.cc/en/Tutorial/Libr ... ples/Files) doesn't work properly? the output follows:
Initializing SD card...initialization done.
14:56:52.747 -> example.txt doesn't exist.
14:56:52.747 -> Creating example.txt...
14:56:52.747 -> example.txt doesn't exist.
14:56:52.747 -> Removing example.txt...
14:56:52.747 -> example.txt doesn't exist.

Code: Select all

#include <STM32SD.h>

#ifndef SD_DETECT_PIN
#define SD_DETECT_PIN SD_DETECT_NONE
#endif

void setup() {

    Serial.begin(115200);
    Serial.println("Started");

    pinMode(SD1, OUTPUT);
    digitalWrite(SD1, HIGH);


    delay(5000);  


    Serial.print("Initializing SD card...");

    if (!SD.begin(SD_DETECT_PIN)) {

        Serial.println("initialization failed!");

        while (1);

    }

    Serial3.println("initialization done.");

    if (SD.exists("example.txt")) {

        Serial.println("example.txt exists.");

    }
    else {

        Serial.println("example.txt doesn't exist.");

    }

    // open a new file and immediately close it:

    Serial.println("Creating example.txt...");

    File myFile = SD.open("example.txt", FILE_WRITE);

    myFile.close();

    // Check to see if the file exists:

    if (SD.exists("example.txt")) {

        Serial.println("example.txt exists.");

    }
    else {

        Serial.println("example.txt doesn't exist.");

    }

    // delete the file:

    Serial.println("Removing example.txt...");

    SD.remove("example.txt");

    if (SD.exists("example.txt")) {

        Serial.println("example.txt exists.");

    }
    else {

        Serial.println("example.txt doesn't exist.");

    }

    myFile.close();
}

void loop() {
}

Re: STM32L452RE Configue SDMMC1 to HSI48?

Posted: Thu Jan 28, 2021 3:02 pm
by Bambo
The clock setup function is this

Code: Select all

#pragma once

extern "C" void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };

    /* Configure LSE Drive Capability */
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_MSI | RCC_OSCILLATORTYPE_HSI48;
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
    RCC_OscInitStruct.MSICalibrationValue = 0;
    RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    RCC_OscInitStruct.PLL.PLLM = 1;
    RCC_OscInitStruct.PLL.PLLN = 40;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
        | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    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_4) != HAL_OK) {
        Error_Handler();
    }

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1;
    //PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLLSAI1;
    PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_HSI48;
    //PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
    //PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
    //PeriphClkInit.PLLSAI1.PLLSAI1N = 28;
    //PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV17;
    //PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
    //PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
    //PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK | RCC_PLLSAI1_ADC1CLK | RCC_PLLSAI1_48M2CLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
        Error_Handler();
    }


    /* Configure the main internal regulator output voltage */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
        Error_Handler();
    }

    /* Enable MSI Auto calibration */
    HAL_RCCEx_EnableMSIPLLMode();


}
- edit -
Strangely if i use the PLL clock instead of HSI48 it works?

Code: Select all

     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1;
    PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLLSAI1;
    //PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_HSI48;
    PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
    PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
    PeriphClkInit.PLLSAI1.PLLSAI1N = 16;
    PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV17;
    PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV8;
    PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
    PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK | RCC_PLLSAI1_ADC1CLK | RCC_PLLSAI1_48M2CLK;
Problem is the PLLSAI1 is already in use by another component

- edit -
It can handle 16MHz but not 32MHz!

Re: STM32L452RE Configue SDMMC1 to HSI48?

Posted: Tue Feb 02, 2021 12:03 pm
by Bambo