source: ctrl/firmware/Main/CubeMX/FATFS/Target/sd_diskio.c @ 74

Last change on this file since 74 was 74, checked in by Zed, 3 months ago

FatFs? with DMA were implemented.

File size: 13.6 KB
Line 
1/* USER CODE BEGIN Header */
2/**
3  ******************************************************************************
4  * @file    sd_diskio.c
5  * @brief   SD Disk I/O driver
6  ******************************************************************************
7  * @attention
8  *
9  * Copyright (c) 2025 STMicroelectronics.
10  * All rights reserved.
11  *
12  * This software is licensed under terms that can be found in the LICENSE file
13  * in the root directory of this software component.
14  * If no LICENSE file comes with this software, it is provided AS-IS.
15  *
16  ******************************************************************************
17  */
18/* USER CODE END Header */
19
20/* Note: code generation based on sd_diskio_dma_template_bspv1.c v2.1.4
21   as "Use dma template" is enabled. */
22
23/* USER CODE BEGIN firstSection */
24/* can be used to modify / undefine following code or add new definitions */
25/* USER CODE END firstSection*/
26
27/* Includes ------------------------------------------------------------------*/
28#include "ff_gen_drv.h"
29#include "sd_diskio.h"
30
31#include <string.h>
32
33/* Private typedef -----------------------------------------------------------*/
34/* Private define ------------------------------------------------------------*/
35
36 /*
37 * the following Timeout is useful to give the control back to the applications
38 * in case of errors in either BSP_SD_ReadCpltCallback() or BSP_SD_WriteCpltCallback()
39 * the value by default is as defined in the BSP platform driver otherwise 30 secs
40 */
41#define SD_TIMEOUT 30 * 1000
42
43#define SD_DEFAULT_BLOCK_SIZE 512
44
45/*
46 * Depending on the use case, the SD card initialization could be done at the
47 * application level: if it is the case define the flag below to disable
48 * the BSP_SD_Init() call in the SD_Initialize() and add a call to
49 * BSP_SD_Init() elsewhere in the application.
50 */
51/* USER CODE BEGIN disableSDInit */
52/* #define DISABLE_SD_INIT */
53/* USER CODE END disableSDInit */
54
55/*
56 * when using cacheable memory region, it may be needed to maintain the cache
57 * validity. Enable the define below to activate a cache maintenance at each
58 * read and write operation.
59 * Notice: This is applicable only for cortex M7 based platform.
60 */
61/* USER CODE BEGIN enableSDDmaCacheMaintenance */
62#define ENABLE_SD_DMA_CACHE_MAINTENANCE  1
63/* USER CODE END enableSDDmaCacheMaintenance */
64
65/*
66* Some DMA requires 4-Byte aligned address buffer to correctly read/write data,
67* in FatFs some accesses aren't thus we need a 4-byte aligned scratch buffer to correctly
68* transfer data
69*/
70/* USER CODE BEGIN enableScratchBuffer */
71#define ENABLE_SCRATCH_BUFFER
72/* USER CODE END enableScratchBuffer */
73
74/* Private variables ---------------------------------------------------------*/
75#if defined(ENABLE_SCRATCH_BUFFER)
76#if defined (ENABLE_SD_DMA_CACHE_MAINTENANCE)
77ALIGN_32BYTES(static uint8_t scratch[BLOCKSIZE]); // 32-Byte aligned for cache maintenance
78#else
79__ALIGN_BEGIN static uint8_t scratch[BLOCKSIZE] __ALIGN_END;
80#endif
81#endif
82/* Disk status */
83static volatile DSTATUS Stat = STA_NOINIT;
84
85static volatile  UINT  WriteStatus = 0, ReadStatus = 0;
86/* Private function prototypes -----------------------------------------------*/
87static DSTATUS SD_CheckStatus(BYTE lun);
88DSTATUS SD_initialize (BYTE);
89DSTATUS SD_status (BYTE);
90DRESULT SD_read (BYTE, BYTE*, DWORD, UINT);
91#if _USE_WRITE == 1
92DRESULT SD_write (BYTE, const BYTE*, DWORD, UINT);
93#endif /* _USE_WRITE == 1 */
94#if _USE_IOCTL == 1
95DRESULT SD_ioctl (BYTE, BYTE, void*);
96#endif  /* _USE_IOCTL == 1 */
97
98const Diskio_drvTypeDef  SD_Driver =
99{
100  SD_initialize,
101  SD_status,
102  SD_read,
103#if  _USE_WRITE == 1
104  SD_write,
105#endif /* _USE_WRITE == 1 */
106
107#if  _USE_IOCTL == 1
108  SD_ioctl,
109#endif /* _USE_IOCTL == 1 */
110};
111
112/* USER CODE BEGIN beforeFunctionSection */
113/* can be used to modify / undefine following code or add new code */
114/* USER CODE END beforeFunctionSection */
115
116/* Private functions ---------------------------------------------------------*/
117
118static int SD_CheckStatusWithTimeout(uint32_t timeout)
119{
120  uint32_t timer = HAL_GetTick();
121  /* block until SDIO IP is ready again or a timeout occur */
122  while(HAL_GetTick() - timer < timeout)
123  {
124    if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
125    {
126      return 0;
127    }
128  }
129
130  return -1;
131}
132
133static DSTATUS SD_CheckStatus(BYTE lun)
134{
135  Stat = STA_NOINIT;
136
137  if(BSP_SD_GetCardState() == MSD_OK)
138  {
139    Stat &= ~STA_NOINIT;
140  }
141
142  return Stat;
143}
144
145/**
146  * @brief  Initializes a Drive
147  * @param  lun : not used
148  * @retval DSTATUS: Operation status
149  */
150DSTATUS SD_initialize(BYTE lun)
151{
152
153#if !defined(DISABLE_SD_INIT)
154
155  if(BSP_SD_Init() == MSD_OK)
156  {
157    Stat = SD_CheckStatus(lun);
158  }
159
160#else
161  Stat = SD_CheckStatus(lun);
162#endif
163
164  return Stat;
165}
166
167/**
168  * @brief  Gets Disk Status
169  * @param  lun : not used
170  * @retval DSTATUS: Operation status
171  */
172DSTATUS SD_status(BYTE lun)
173{
174  return SD_CheckStatus(lun);
175}
176
177/* USER CODE BEGIN beforeReadSection */
178/* can be used to modify previous code / undefine following code / add new code */
179/* USER CODE END beforeReadSection */
180/**
181  * @brief  Reads Sector(s)
182  * @param  lun : not used
183  * @param  *buff: Data buffer to store read data
184  * @param  sector: Sector address (LBA)
185  * @param  count: Number of sectors to read (1..128)
186  * @retval DRESULT: Operation result
187  */
188
189DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
190{
191  DRESULT res = RES_ERROR;
192  uint32_t timeout;
193#if defined(ENABLE_SCRATCH_BUFFER)
194  uint8_t ret;
195#endif
196#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
197  uint32_t alignedAddr;
198#endif
199
200  /*
201  * ensure the SDCard is ready for a new operation
202  */
203
204  if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
205  {
206    return res;
207  }
208
209#if defined(ENABLE_SCRATCH_BUFFER)
210  if (!((uint32_t)buff & 0x3))
211  {
212#endif
213    if(BSP_SD_ReadBlocks_DMA((uint32_t*)buff,
214                             (uint32_t) (sector),
215                             count) == MSD_OK)
216    {
217      ReadStatus = 0;
218      /* Wait that the reading process is completed or a timeout occurs */
219      timeout = HAL_GetTick();
220      while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
221      {
222      }
223      /* in case of a timeout return error */
224      if (ReadStatus == 0)
225      {
226        res = RES_ERROR;
227      }
228      else
229      {
230        ReadStatus = 0;
231        timeout = HAL_GetTick();
232
233        while((HAL_GetTick() - timeout) < SD_TIMEOUT)
234        {
235          if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
236          {
237            res = RES_OK;
238#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
239            /*
240            the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
241            adjust the address and the D-Cache size to invalidate accordingly.
242            */
243            alignedAddr = (uint32_t)buff & ~0x1F;
244            SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
245#endif
246            break;
247          }
248        }
249      }
250    }
251#if defined(ENABLE_SCRATCH_BUFFER)
252  }
253    else
254    {
255      /* Slow path, fetch each sector a part and memcpy to destination buffer */
256      int i;
257
258      for (i = 0; i < count; i++) {
259        ret = BSP_SD_ReadBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
260        if (ret == MSD_OK) {
261          /* wait until the read is successful or a timeout occurs */
262
263          timeout = HAL_GetTick();
264          while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
265          {
266          }
267          if (ReadStatus == 0)
268          {
269            res = RES_ERROR;
270            break;
271          }
272          ReadStatus = 0;
273
274#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
275          /*
276          *
277          * invalidate the scratch buffer before the next read to get the actual data instead of the cached one
278          */
279          SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
280#endif
281          memcpy(buff, scratch, BLOCKSIZE);
282          buff += BLOCKSIZE;
283        }
284        else
285        {
286          break;
287        }
288      }
289
290      if ((i == count) && (ret == MSD_OK))
291        res = RES_OK;
292    }
293#endif
294
295  return res;
296}
297
298/* USER CODE BEGIN beforeWriteSection */
299/* can be used to modify previous code / undefine following code / add new code */
300/* USER CODE END beforeWriteSection */
301/**
302  * @brief  Writes Sector(s)
303  * @param  lun : not used
304  * @param  *buff: Data to be written
305  * @param  sector: Sector address (LBA)
306  * @param  count: Number of sectors to write (1..128)
307  * @retval DRESULT: Operation result
308  */
309#if _USE_WRITE == 1
310
311DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
312{
313  DRESULT res = RES_ERROR;
314  uint32_t timeout;
315#if defined(ENABLE_SCRATCH_BUFFER)
316  uint8_t ret;
317  int i;
318#endif
319
320   WriteStatus = 0;
321#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
322  uint32_t alignedAddr;
323#endif
324
325  if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
326  {
327    return res;
328  }
329
330#if defined(ENABLE_SCRATCH_BUFFER)
331  if (!((uint32_t)buff & 0x3))
332  {
333#endif
334#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
335
336    /*
337    the SCB_CleanDCache_by_Addr() requires a 32-Byte aligned address
338    adjust the address and the D-Cache size to clean accordingly.
339    */
340    alignedAddr = (uint32_t)buff &  ~0x1F;
341    SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
342#endif
343
344    if(BSP_SD_WriteBlocks_DMA((uint32_t*)buff,
345                              (uint32_t)(sector),
346                              count) == MSD_OK)
347    {
348      /* Wait that writing process is completed or a timeout occurs */
349
350      timeout = HAL_GetTick();
351      while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
352      {
353      }
354      /* in case of a timeout return error */
355      if (WriteStatus == 0)
356      {
357        res = RES_ERROR;
358      }
359      else
360      {
361        WriteStatus = 0;
362        timeout = HAL_GetTick();
363
364        while((HAL_GetTick() - timeout) < SD_TIMEOUT)
365        {
366          if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
367          {
368            res = RES_OK;
369            break;
370          }
371        }
372      }
373    }
374#if defined(ENABLE_SCRATCH_BUFFER)
375  }
376    else
377    {
378      /* Slow path, fetch each sector a part and memcpy to destination buffer */
379#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
380      /*
381      * invalidate the scratch buffer before the next write to get the actual data instead of the cached one
382      */
383      SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
384#endif
385
386      for (i = 0; i < count; i++)
387      {
388        WriteStatus = 0;
389
390        memcpy((void *)scratch, (void *)buff, BLOCKSIZE);
391        buff += BLOCKSIZE;
392
393        ret = BSP_SD_WriteBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
394        if (ret == MSD_OK) {
395          /* wait for a message from the queue or a timeout */
396          timeout = HAL_GetTick();
397          while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
398          {
399          }
400          if (WriteStatus == 0)
401          {
402            break;
403          }
404
405        }
406        else
407        {
408          break;
409        }
410      }
411      if ((i == count) && (ret == MSD_OK))
412        res = RES_OK;
413    }
414#endif
415  return res;
416}
417#endif /* _USE_WRITE == 1 */
418
419/* USER CODE BEGIN beforeIoctlSection */
420/* can be used to modify previous code / undefine following code / add new code */
421/* USER CODE END beforeIoctlSection */
422/**
423  * @brief  I/O control operation
424  * @param  lun : not used
425  * @param  cmd: Control code
426  * @param  *buff: Buffer to send/receive control data
427  * @retval DRESULT: Operation result
428  */
429#if _USE_IOCTL == 1
430DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
431{
432  DRESULT res = RES_ERROR;
433  BSP_SD_CardInfo CardInfo;
434
435  if (Stat & STA_NOINIT) return RES_NOTRDY;
436
437  switch (cmd)
438  {
439  /* Make sure that no pending write process */
440  case CTRL_SYNC :
441    res = RES_OK;
442    break;
443
444  /* Get number of sectors on the disk (DWORD) */
445  case GET_SECTOR_COUNT :
446    BSP_SD_GetCardInfo(&CardInfo);
447    *(DWORD*)buff = CardInfo.LogBlockNbr;
448    res = RES_OK;
449    break;
450
451  /* Get R/W sector size (WORD) */
452  case GET_SECTOR_SIZE :
453    BSP_SD_GetCardInfo(&CardInfo);
454    *(WORD*)buff = CardInfo.LogBlockSize;
455    res = RES_OK;
456    break;
457
458  /* Get erase block size in unit of sector (DWORD) */
459  case GET_BLOCK_SIZE :
460    BSP_SD_GetCardInfo(&CardInfo);
461    *(DWORD*)buff = CardInfo.LogBlockSize / SD_DEFAULT_BLOCK_SIZE;
462    res = RES_OK;
463    break;
464
465  default:
466    res = RES_PARERR;
467  }
468
469  return res;
470}
471#endif /* _USE_IOCTL == 1 */
472
473/* USER CODE BEGIN afterIoctlSection */
474/* can be used to modify previous code / undefine following code / add new code */
475/* USER CODE END afterIoctlSection */
476
477/* USER CODE BEGIN callbackSection */
478/* can be used to modify / following code or add new code */
479/* USER CODE END callbackSection */
480/**
481  * @brief Tx Transfer completed callbacks
482  * @param hsd: SD handle
483  * @retval None
484  */
485void BSP_SD_WriteCpltCallback(void)
486{
487
488  WriteStatus = 1;
489}
490
491/**
492  * @brief Rx Transfer completed callbacks
493  * @param hsd: SD handle
494  * @retval None
495  */
496void BSP_SD_ReadCpltCallback(void)
497{
498  ReadStatus = 1;
499}
500
501/* USER CODE BEGIN ErrorAbortCallbacks */
502/*
503void BSP_SD_AbortCallback(void)
504{
505#if (osCMSIS < 0x20000U)
506   osMessagePut(SDQueueID, RW_ABORT_MSG, 0);
507#else
508   const uint16_t msg = RW_ABORT_MSG;
509   osMessageQueuePut(SDQueueID, (const void *)&msg, 0, 0);
510#endif
511}
512*/
513/* USER CODE END ErrorAbortCallbacks */
514
515/* USER CODE BEGIN lastSection */
516/* can be used to modify / undefine previous code or add new code */
517/* USER CODE END lastSection */
Note: See TracBrowser for help on using the repository browser.