/NUCLEO-H755ZI-uSD-FatFS-DMA

ST MCU NUCLEO-H755ZI-Q Development board, Implementation of [SDMMC uSD + FatFs + DMA] with STM32CubeMX Code Generation

Primary LanguageCMIT LicenseMIT

NUCLEO-H755ZI-Q [uSD + FatFs + DMA]

Pre-requisites

  • Hardware

    • NUCLEO-H755ZI-Q (STM32H755ZI Development board): Click! NUCLEO-H755ZI-Q

    • Digilent Pmod MicroSD (4-bit SDIO Breakout board): Click! Pmod-MicroSD

    • Pinout

      J1-Conn

      Connector J1- Pin Descriptions

      Pin Signal Description Pin Signal Description
      1 DAT3 Chip Select / Data3 7 DAT1 Data 1
      2 CMD MOSI / Command 8 DAT2 Data 2
      3 DAT0 MISO / Data0 9 CD Card Detect
      4 CK Serial Clock 10 NC Not Connected
      5 GND Power Supply Ground 11 GND Power Supply Ground
      6 VCC Power Supply (3.3V) 12 VCC Power Supply (3.3V)
  • Software

    • IDE
      • STM32CubeIDE
    • Drivers
      • STM32 HAL H7xx Drivers Package
    • Middlewares
      • FatFS (File System Format)

NUCLEO-H755ZI-Q SDMMC1 I/F Pinout

  • SDMMC1 Interface
    • Connector CN8 --SDMMC-- (Arduino Uno compatible)

      CN8-SH

    • Schematics

      CN8-SDMMC-SCH

    • SDMMC1 Pinout Table

      Pin Pin name Pin Assignment Pin Context Assignment User Label
      37 PA0 GPIO_INPUT Cortex-M7 SDMMC1_uSD_DETECT
      114 PD2 SDMMC1 Cortex-M7 SDMMC1_CMD
      95 PC8 SDMMC1 Cortex-M7 SDMMC1_D0
      96 PC9 SDMMC1 Cortex-M7 SDMMC1_D1
      109 PC10 SDMMC1 Cortex-M7 SDMMC1_D2
      110 PC11 SDMMC1 Cortex-M7 SDMMC1_D3
      111 PC12 SDMMC1 Cortex-M7 SDMMC1_CK

Steps

  1. Creating a STM32 project with STM32CubeMX,
    New Project -> Board Selector -> NUCLEO-H755ZI-Q
    Then Click "Start Project"

    New-project

  2. Select components from BSP Drivers for NUCLEO-H755ZI-Q

    bsp-select

  3. CubeMX -> Connectivity -> Enable SDMMC1 on context of Cortex-M7

    sd-conf

    • SDMMC Mode:

      • "SD 4 bits Wide Bus mode"
    • SDMMC1 -> Parameter Settings

      • SDMMC1 Clock divide factor = 0x04 or SDMMC_NSPEED_CLK_DIV
      // In .../stm32h7xx_ll_sdmmc.h
      
      /* SDMMC Initialization Frequency (400KHz max) for Peripheral CLK 200MHz*/
      #define SDMMC_INIT_CLK_DIV ((uint8_t)0xFA)
      
      /* SDMMC Default Speed Frequency (25Mhz max) for Peripheral CLK 200MHz*/
      #define SDMMC_NSPEED_CLK_DIV ((uint8_t)0x4)
      
      /* SDMMC High Speed Frequency (50Mhz max) for Peripheral CLK 200MHz*/
      #define SDMMC_HSPEED_CLK_DIV ((uint8_t)0x2)
    • SDMMC1 -> NVIC Settings

      sdmmc-isr

      • Enabled SDMMC1 Global Interrupt, you change ISR priority on NVIC page
  4. Clock Configuration (RCC), Default we will use HSI Oscillator

    alt text

    • Clock Settings

      • SYSCLK = 400 MHz
      • CPU1_CLK (M7) = 400 MHz
      • CPU2_CLK (M4) = 200 MHz
      • PCLK = 200 MHz
    • SDMMC1, Clock Mux

      alt text

      • SDMMC1_CLK = 200 MHz
      • Actual SDMMC1 Clock = SDMMC1_CLK / SDMMC_DIVIDE_FACTOR
      • ACTUAL_SDMMC1_CLK = (200 MHz/ 4) = 50 MHz
  5. FATFS Middleware Configuration

    • Middleware and Software Packs -> FATFS_M7

      • Enabled FATFS_M7 with default defines configuration and select it as "SD CARD"

      alt text

    • FATFS_M7 -> Advanced Settings, Enabled DMA Template

      alt text

      • FATFS_M7 -> Platform Settings

        • Select PA0[SDMMC1_uSD_DETECT] as SD Card Detect pin

        alt text

  6. MPU Configuration

    • Memory Protection Unit (MPU)

      • MPU Region 0 and CPU L1 Cache

        MPU-Region0

        • Speculation default mode
          • Enabled
        • Cortex Interface Settings
          • CPU I-Cache
            • Enabled
          • CPU D-Cache
            • Enabled
        • For MPU Region 0
          • Keep everything as default
    • MPU Region 1 "AXIM SRAM Region"

      MPU-Region1

      • For MPU Region 1

        • MPU Regin
          • Enabled
        • MPU Region Base Address
          • 0x24000000 (AXIM SRAM)
        • MPU Region Size
          • 512 KB
        • MPU Region SubRegion Disable
          • 0x0
        • MPU Region TEX field level
          • Level 1
        • MPU Region Access Permission
          • ALL ACCESS PERMISSION
        • MPU Region Instruction Access
          • ENABLE
        • MPU Region Shareability Permission
          • DISABLE
        • MPU Region Cacheable Permission
          • DISABLE
        • MPU Region Bufferable Permission
          • DISABLE
      • STM32H755xx Memory Map

        • axim-map
  7. NVIC (Nested Vector Interrupt Controller)

    alt text

    • ISR Priority
      • Time base: Systick Timer = 14
      • SDMMC1 = 14
      • EXTI line[15:10] = 15
  8. Linker settings

    linker-conf

    • Cortex-M7
      • Minimum Heap Size = 0x400
      • Minimum Stack Size = 0x800
    • Cortex-M4
      • Minimum Heap Size = 0x400
      • Minimum Stack Size = 0x800
  9. Add source code to ../CM7/Core/main.c

  /* Private function prototypes -----------------------------------------------*/
  /* USER CODE BEGIN PFP */

  static void FS_FormatDisk(void);
  static void FS_FileOperations(void);
  static uint8_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength);

  /* USER CODE END PFP */

  /* Private user code ---------------------------------------------------------*/
  /* USER CODE BEGIN 0 */

  uint8_t workBuffer[_MAX_SS];

  /*
  * ensure that the read buffer 'rtext' is 32-Byte aligned in address and size
  * to guarantee that any other data in the cache won't be affected when the 'rtext'
  * is being invalidated.
  */
  ALIGN_32BYTES(uint8_t rtext[64]);

  /* USER CODE END 0 */

  int main(void)
  {
    /* USER CODE BEGIN BSP */
    /* -- Sample board code to send message over COM1 port ---- */
    printf("[CORE_CM7]: Program Starting... \r\n");

    BSP_LED_On(LED_YELLOW);

  //  FS_FormatDisk();
    FS_FileOperations();

    BSP_LED_Off(LED_YELLOW);

    /* USER CODE END BSP */
  }

  /* USER CODE BEGIN 4 */

  /**
   * @brief Format the disk with the FatFs file system.
   * 
   * This function mounts the file system, formats the SD card,
   * and provides diagnostic prints for each step. If any operation
   * fails, it calls Error_Handler().
   * 
   * @note Ensure that the file system is properly mounted and the
   *       SD card is inserted before calling this function.
   */
  static void FS_FormatDisk(void)
  {
    FRESULT fres; /* FatFs function common result code */

    /* Mount the file system */
    fres = f_mount(&SDFatFS, (TCHAR const*)SDPath, 0);
    if (fres == FR_OK)
    {
      printf("[CORE_CM7/FatFs]: Successfully mounted SD Card\n");

      /* Format the file system */
      fres = f_mkfs((TCHAR const*)SDPath, FM_ANY, 0, workBuffer, sizeof(workBuffer));
      if (fres == FR_OK)
      {
        printf("[CORE_CM7/FatFs]: Successfully formatted SD Card\n");
        return;
      }
    }

    /* Error handling */
    Error_Handler();
  }

  /**
   * @brief Performs file operations on an SD card using the FatFs library.
   *
   * This function mounts the file system, creates and opens a text file for writing,
   * writes data to the file, closes the file, then reopens it for reading, and finally
   * reads the data back. It compares the read data with the written data to ensure
   * the integrity of the file operations. If any operation fails, it calls the 
   * Error_Handler() function.
   *
   * @note Ensure that the file system is properly mounted and the
   *       SD card is inserted before calling this function.
   *
   * @return void
   */
  static void FS_FileOperations(void)
  {
    FRESULT res;                      /* FatFs function common result code */
    uint32_t bytesWritten, bytesRead; /* File write/read counts */
    uint8_t wtext[] = "[CORE_CM7]: This is STM32 working with FatFs + DMA"; /* File write buffer */

    /* Mount the file system */
    res = f_mount(&SDFatFS, (TCHAR const*)SDPath, 0);
    if (res != FR_OK)
    {
      printf("[CORE_CM7/FatFs]: Failed to mount SD card (error code: %d)\n", res);
      Error_Handler();
    }
    else
    {
      printf("[CORE_CM7/FatFs]: Successfully mounted SD Card\n");

      /* Open or create a new text file for writing */
      res = f_open(&SDFile, "STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE);
      if (res != FR_OK)
      {
        printf("[CORE_CM7/FatFs]: Failed to open file for writing (error code: %d)\n", res);
        Error_Handler();
      }
      else
      {
        printf("[CORE_CM7/FatFs]: Successfully opened file for writing\n");

        /* Write data to the text file */
        res = f_write(&SDFile, wtext, sizeof(wtext), (void*)&bytesWritten);
        if (res != FR_OK || bytesWritten != sizeof(wtext))
        {
          printf("[CORE_CM7/FatFs]: Failed to write data to file (error code: %d, bytes "
                "written: %lu)\n",
                res, bytesWritten);
          Error_Handler();
        }
        else
        {
          printf("[CORE_CM7/FatFs]: Data successfully written to file (bytes written: %lu)\n",
                bytesWritten);

          /* Close the text file after writing */
          f_close(&SDFile);

          /* Open the text file for reading */
          res = f_open(&SDFile, "STM32.TXT", FA_READ);
          if (res != FR_OK)
          {
            printf("[CORE_CM7/FatFs]: Failed to open file for reading (error code: %d)\n", res);
            Error_Handler();
          }
          else
          {
            printf("[CORE_CM7/FatFs]: Successfully opened file for reading\n");

            /* Read data from the text file */
            res = f_read(&SDFile, rtext, sizeof(wtext), (void*)&bytesRead);
            if (res != FR_OK || bytesRead != bytesWritten)
            {
              printf("[CORE_CM7/FatFs]: Failed to read the correct amount of data (error code: %d, "
                    "bytes read: %lu, expected: %lu)\n",
                    res, bytesRead, bytesWritten);
              Error_Handler();
            }
            else
            {
              printf("[CORE_CM7/FatFs]: Data successfully read from file (bytes read: %lu)\n",
                    bytesRead);

              /* Close the text file after reading */
              f_close(&SDFile);

              /* Compare read data with the written data */
              if (Buffercmp(rtext, wtext, bytesWritten) == 0)
              {
                printf("[CORE_CM7/FatFs]: Data written and read are identical\n");
                BSP_LED_On(LED_GREEN);
                return;
              }
              else
              {
                printf("[CORE_CM7/FatFs]: Data mismatch\n");
                Error_Handler();
              }
            }
          }
        }
      }
    }

    /* If any error occurs, handle it here */
    Error_Handler();
  }

  /**
   * @brief  Compares two buffers.
   * @param  pBuffer1, pBuffer2: buffers to be compared.
   * @param  BufferLength: buffer's length
   * @retval 1: pBuffer identical to pBuffer1
   *         0: pBuffer differs from pBuffer1
   */
  static uint8_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength)
  {
    while (BufferLength--)
    {
      if (*pBuffer1 != *pBuffer2)
      {
        return 1;
      }

      pBuffer1++;
      pBuffer2++;
    }
    return 0;
  }

  /* USER CODE END 4 */

Demonstration

demo

Reference