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

Last change on this file since 112 was 112, checked in by Zed, 7 weeks ago

Fixing project. Need to add CAN in CubeMX.

File size: 18.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_rtos_template_bspv1.c v2.1.4
21   as FreeRTOS 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#include <stdio.h>
33
34/* Private typedef -----------------------------------------------------------*/
35/* Private define ------------------------------------------------------------*/
36
37#define QUEUE_SIZE         (uint32_t) 10
38#define READ_CPLT_MSG      (uint32_t) 1
39#define WRITE_CPLT_MSG     (uint32_t) 2
40/*
41==================================================================
42enable the defines below to send custom rtos messages
43when an error or an abort occurs.
44Notice: depending on the HAL/SD driver the HAL_SD_ErrorCallback()
45may not be available.
46See BSP_SD_ErrorCallback() and BSP_SD_AbortCallback() below
47==================================================================
48
49#define RW_ERROR_MSG       (uint32_t) 3
50#define RW_ABORT_MSG       (uint32_t) 4
51*/
52/*
53 * the following Timeout is useful to give the control back to the applications
54 * in case of errors in either BSP_SD_ReadCpltCallback() or BSP_SD_WriteCpltCallback()
55 * the value by default is as defined in the BSP platform driver otherwise 30 secs
56 */
57#define SD_TIMEOUT 30 * 1000
58
59#define SD_DEFAULT_BLOCK_SIZE 512
60
61/*
62 * Depending on the use case, the SD card initialization could be done at the
63 * application level: if it is the case define the flag below to disable
64 * the BSP_SD_Init() call in the SD_Initialize() and add a call to
65 * BSP_SD_Init() elsewhere in the application.
66 */
67/* USER CODE BEGIN disableSDInit */
68/* #define DISABLE_SD_INIT */
69/* USER CODE END disableSDInit */
70
71/*
72 * when using cacheable memory region, it may be needed to maintain the cache
73 * validity. Enable the define below to activate a cache maintenance at each
74 * read and write operation.
75 * Notice: This is applicable only for cortex M7 based platform.
76 */
77/* USER CODE BEGIN enableSDDmaCacheMaintenance */
78//#define ENABLE_SD_DMA_CACHE_MAINTENANCE  1
79/* USER CODE END enableSDDmaCacheMaintenance */
80
81/*
82* Some DMA requires 4-Byte aligned address buffer to correctly read/write data,
83* in FatFs some accesses aren't thus we need a 4-byte aligned scratch buffer to correctly
84* transfer data
85*/
86/* USER CODE BEGIN enableScratchBuffer */
87//#define ENABLE_SCRATCH_BUFFER
88/* USER CODE END enableScratchBuffer */
89
90/* Private variables ---------------------------------------------------------*/
91#if defined(ENABLE_SCRATCH_BUFFER)
92#if defined (ENABLE_SD_DMA_CACHE_MAINTENANCE)
93ALIGN_32BYTES(static uint8_t scratch[BLOCKSIZE]); // 32-Byte aligned for cache maintenance
94#else
95__ALIGN_BEGIN static uint8_t scratch[BLOCKSIZE] __ALIGN_END;
96#endif
97#endif
98/* Disk status */
99static volatile DSTATUS Stat = STA_NOINIT;
100
101#if (osCMSIS <= 0x20000U)
102static osMessageQId SDQueueID = NULL;
103#else
104static osMessageQueueId_t SDQueueID = NULL;
105#endif
106/* Private function prototypes -----------------------------------------------*/
107static DSTATUS SD_CheckStatus(BYTE lun);
108DSTATUS SD_initialize (BYTE);
109DSTATUS SD_status (BYTE);
110DRESULT SD_read (BYTE, BYTE*, DWORD, UINT);
111#if _USE_WRITE == 1
112DRESULT SD_write (BYTE, const BYTE*, DWORD, UINT);
113#endif /* _USE_WRITE == 1 */
114#if _USE_IOCTL == 1
115DRESULT SD_ioctl (BYTE, BYTE, void*);
116#endif  /* _USE_IOCTL == 1 */
117
118const Diskio_drvTypeDef  SD_Driver =
119{
120  SD_initialize,
121  SD_status,
122  SD_read,
123#if  _USE_WRITE == 1
124  SD_write,
125#endif /* _USE_WRITE == 1 */
126
127#if  _USE_IOCTL == 1
128  SD_ioctl,
129#endif /* _USE_IOCTL == 1 */
130};
131
132/* USER CODE BEGIN beforeFunctionSection */
133/* can be used to modify / undefine following code or add new code */
134/* USER CODE END beforeFunctionSection */
135
136/* Private functions ---------------------------------------------------------*/
137
138static int SD_CheckStatusWithTimeout(uint32_t timeout)
139{
140  uint32_t timer;
141  /* block until SDIO peripheral is ready again or a timeout occur */
142#if (osCMSIS <= 0x20000U)
143  timer = osKernelSysTick();
144  while( osKernelSysTick() - timer < timeout)
145#else
146  timer = osKernelGetTickCount();
147  while( osKernelGetTickCount() - timer < timeout)
148#endif
149  {
150    if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
151    {
152      return 0;
153    }
154  }
155
156  return -1;
157}
158
159static DSTATUS SD_CheckStatus(BYTE lun)
160{
161  Stat = STA_NOINIT;
162
163  if(BSP_SD_GetCardState() == SD_TRANSFER_OK)
164  {
165    Stat &= ~STA_NOINIT;
166  }
167
168  return Stat;
169}
170
171/**
172  * @brief  Initializes a Drive
173  * @param  lun : not used
174  * @retval DSTATUS: Operation status
175  */
176DSTATUS SD_initialize(BYTE lun)
177{
178Stat = STA_NOINIT;
179
180  /*
181   * check that the kernel has been started before continuing
182   * as the osMessage API will fail otherwise
183   */
184#if (osCMSIS <= 0x20000U)
185  if(osKernelRunning())
186#else
187  if(osKernelGetState() == osKernelRunning)
188#endif
189  {
190#if !defined(DISABLE_SD_INIT)
191
192    if(BSP_SD_Init() == MSD_OK)
193    {
194      Stat = SD_CheckStatus(lun);
195    }
196
197#else
198    Stat = SD_CheckStatus(lun);
199#endif
200
201    /*
202    * if the SD is correctly initialized, create the operation queue
203    * if not already created
204    */
205
206    if (Stat != STA_NOINIT)
207    {
208      if (SDQueueID == NULL)
209      {
210#if (osCMSIS <= 0x20000U)
211                  osMessageQDef(SD_Queue, QUEUE_SIZE, uint16_t);
212                  SDQueueID = osMessageCreate (osMessageQ(SD_Queue), NULL);
213#else
214                  SDQueueID = osMessageQueueNew(QUEUE_SIZE, 2, NULL);
215#endif
216      }
217
218      if (SDQueueID == NULL)
219      {
220        Stat |= STA_NOINIT;
221      }
222    }
223  }
224
225  return Stat;
226}
227
228/**
229  * @brief  Gets Disk Status
230  * @param  lun : not used
231  * @retval DSTATUS: Operation status
232  */
233DSTATUS SD_status(BYTE lun)
234{
235  return SD_CheckStatus(lun);
236}
237
238/* USER CODE BEGIN beforeReadSection */
239/* can be used to modify previous code / undefine following code / add new code */
240/* USER CODE END beforeReadSection */
241/**
242  * @brief  Reads Sector(s)
243  * @param  lun : not used
244  * @param  *buff: Data buffer to store read data
245  * @param  sector: Sector address (LBA)
246  * @param  count: Number of sectors to read (1..128)
247  * @retval DRESULT: Operation result
248  */
249
250DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
251{
252  uint8_t ret;
253  DRESULT res = RES_ERROR;
254  uint32_t timer;
255#if (osCMSIS < 0x20000U)
256  osEvent event;
257#else
258  uint16_t event;
259  osStatus_t status;
260#endif
261#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
262  uint32_t alignedAddr;
263#endif
264  /*
265  * ensure the SDCard is ready for a new operation
266  */
267
268  if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
269  {
270    return res;
271  }
272
273#if defined(ENABLE_SCRATCH_BUFFER)
274  if (!((uint32_t)buff & 0x3))
275  {
276#endif
277    /* Fast path cause destination buffer is correctly aligned */
278    ret = BSP_SD_ReadBlocks_DMA((uint32_t*)buff, (uint32_t)(sector), count);
279
280    if (ret == MSD_OK) {
281#if (osCMSIS < 0x20000U)
282    /* wait for a message from the queue or a timeout */
283    event = osMessageGet(SDQueueID, SD_TIMEOUT);
284
285    if (event.status == osEventMessage)
286    {
287      if (event.value.v == READ_CPLT_MSG)
288      {
289        timer = osKernelSysTick();
290        /* block until SDIO IP is ready or a timeout occur */
291        while(osKernelSysTick() - timer <SD_TIMEOUT)
292#else
293          status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
294          if ((status == osOK) && (event == READ_CPLT_MSG))
295          {
296            timer = osKernelGetTickCount();
297            /* block until SDIO IP is ready or a timeout occur */
298            while(osKernelGetTickCount() - timer <SD_TIMEOUT)
299#endif
300            {
301              if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
302              {
303                res = RES_OK;
304#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
305                /*
306                the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
307                adjust the address and the D-Cache size to invalidate accordingly.
308                */
309                alignedAddr = (uint32_t)buff & ~0x1F;
310                SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
311#endif
312                break;
313              }
314            }
315#if (osCMSIS < 0x20000U)
316          }
317        }
318#else
319      }
320#endif
321    }
322
323#if defined(ENABLE_SCRATCH_BUFFER)
324    }
325    else
326    {
327      /* Slow path, fetch each sector a part and memcpy to destination buffer */
328      int i;
329
330      for (i = 0; i < count; i++)
331      {
332        ret = BSP_SD_ReadBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
333        if (ret == MSD_OK )
334        {
335          /* wait until the read is successful or a timeout occurs */
336#if (osCMSIS < 0x20000U)
337          /* wait for a message from the queue or a timeout */
338          event = osMessageGet(SDQueueID, SD_TIMEOUT);
339
340          if (event.status == osEventMessage)
341          {
342            if (event.value.v == READ_CPLT_MSG)
343            {
344              timer = osKernelSysTick();
345              /* block until SDIO IP is ready or a timeout occur */
346              while(osKernelSysTick() - timer <SD_TIMEOUT)
347#else
348                status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
349              if ((status == osOK) && (event == READ_CPLT_MSG))
350              {
351                timer = osKernelGetTickCount();
352                /* block until SDIO IP is ready or a timeout occur */
353                ret = MSD_ERROR;
354                while(osKernelGetTickCount() - timer < SD_TIMEOUT)
355#endif
356                {
357                  ret = BSP_SD_GetCardState();
358
359                  if (ret == MSD_OK)
360                  {
361                    break;
362                  }
363                }
364
365                if (ret != MSD_OK)
366                {
367                  break;
368                }
369#if (osCMSIS < 0x20000U)
370              }
371            }
372#else
373          }
374#endif
375#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
376          /*
377          *
378          * invalidate the scratch buffer before the next read to get the actual data instead of the cached one
379          */
380          SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
381#endif
382          memcpy(buff, scratch, BLOCKSIZE);
383          buff += BLOCKSIZE;
384        }
385        else
386        {
387          break;
388        }
389      }
390
391      if ((i == count) && (ret == MSD_OK ))
392        res = RES_OK;
393    }
394#endif
395  return res;
396}
397
398/* USER CODE BEGIN beforeWriteSection */
399/* can be used to modify previous code / undefine following code / add new code */
400/* USER CODE END beforeWriteSection */
401/**
402  * @brief  Writes Sector(s)
403  * @param  lun : not used
404  * @param  *buff: Data to be written
405  * @param  sector: Sector address (LBA)
406  * @param  count: Number of sectors to write (1..128)
407  * @retval DRESULT: Operation result
408  */
409#if _USE_WRITE == 1
410
411DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
412{
413  DRESULT res = RES_ERROR;
414  uint32_t timer;
415
416#if (osCMSIS < 0x20000U)
417  osEvent event;
418#else
419  uint16_t event;
420  osStatus_t status;
421#endif
422
423#if defined(ENABLE_SCRATCH_BUFFER)
424  int32_t ret;
425#endif
426
427  /*
428  * ensure the SDCard is ready for a new operation
429  */
430
431  if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
432  {
433    return res;
434  }
435
436#if defined(ENABLE_SCRATCH_BUFFER)
437  if (!((uint32_t)buff & 0x3))
438  {
439#endif
440#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
441  uint32_t alignedAddr;
442  /*
443    the SCB_CleanDCache_by_Addr() requires a 32-Byte aligned address
444    adjust the address and the D-Cache size to clean accordingly.
445  */
446  alignedAddr = (uint32_t)buff & ~0x1F;
447  SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
448#endif
449
450  if(BSP_SD_WriteBlocks_DMA((uint32_t*)buff,
451                           (uint32_t) (sector),
452                           count) == MSD_OK)
453  {
454#if (osCMSIS < 0x20000U)
455    /* Get the message from the queue */
456    event = osMessageGet(SDQueueID, SD_TIMEOUT);
457
458    if (event.status == osEventMessage)
459    {
460      if (event.value.v == WRITE_CPLT_MSG)
461      {
462#else
463    status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
464    if ((status == osOK) && (event == WRITE_CPLT_MSG))
465    {
466#endif
467 #if (osCMSIS < 0x20000U)
468        timer = osKernelSysTick();
469        /* block until SDIO IP is ready or a timeout occur */
470        while(osKernelSysTick() - timer  < SD_TIMEOUT)
471#else
472        timer = osKernelGetTickCount();
473        /* block until SDIO IP is ready or a timeout occur */
474        while(osKernelGetTickCount() - timer  < SD_TIMEOUT)
475#endif
476        {
477          if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
478          {
479            res = RES_OK;
480            break;
481          }
482        }
483#if (osCMSIS < 0x20000U)
484      }
485    }
486#else
487    }
488#endif
489  }
490#if defined(ENABLE_SCRATCH_BUFFER)
491  else {
492    /* Slow path, fetch each sector a part and memcpy to destination buffer */
493    int i;
494
495#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
496    /*
497     * invalidate the scratch buffer before the next write to get the actual data instead of the cached one
498     */
499     SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
500#endif
501      for (i = 0; i < count; i++)
502      {
503        memcpy((void *)scratch, buff, BLOCKSIZE);
504        buff += BLOCKSIZE;
505
506        ret = BSP_SD_WriteBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
507        if (ret == MSD_OK )
508        {
509          /* wait until the read is successful or a timeout occurs */
510#if (osCMSIS < 0x20000U)
511          /* wait for a message from the queue or a timeout */
512          event = osMessageGet(SDQueueID, SD_TIMEOUT);
513
514          if (event.status == osEventMessage)
515          {
516            if (event.value.v == READ_CPLT_MSG)
517            {
518              timer = osKernelSysTick();
519              /* block until SDIO IP is ready or a timeout occur */
520              while(osKernelSysTick() - timer <SD_TIMEOUT)
521#else
522                status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
523              if ((status == osOK) && (event == READ_CPLT_MSG))
524              {
525                timer = osKernelGetTickCount();
526                /* block until SDIO IP is ready or a timeout occur */
527                ret = MSD_ERROR;
528                while(osKernelGetTickCount() - timer < SD_TIMEOUT)
529#endif
530                {
531                  ret = BSP_SD_GetCardState();
532
533                  if (ret == MSD_OK)
534                  {
535                    break;
536                  }
537                }
538
539                if (ret != MSD_OK)
540                {
541                  break;
542                }
543#if (osCMSIS < 0x20000U)
544              }
545            }
546#else
547          }
548#endif
549        }
550        else
551        {
552          break;
553        }
554      }
555
556      if ((i == count) && (ret == MSD_OK ))
557        res = RES_OK;
558    }
559
560  }
561#endif
562
563  return res;
564}
565 #endif /* _USE_WRITE == 1 */
566
567/* USER CODE BEGIN beforeIoctlSection */
568/* can be used to modify previous code / undefine following code / add new code */
569/* USER CODE END beforeIoctlSection */
570/**
571  * @brief  I/O control operation
572  * @param  lun : not used
573  * @param  cmd: Control code
574  * @param  *buff: Buffer to send/receive control data
575  * @retval DRESULT: Operation result
576  */
577#if _USE_IOCTL == 1
578DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
579{
580  DRESULT res = RES_ERROR;
581  BSP_SD_CardInfo CardInfo;
582
583  if (Stat & STA_NOINIT) return RES_NOTRDY;
584
585  switch (cmd)
586  {
587  /* Make sure that no pending write process */
588  case CTRL_SYNC :
589    res = RES_OK;
590    break;
591
592  /* Get number of sectors on the disk (DWORD) */
593  case GET_SECTOR_COUNT :
594    BSP_SD_GetCardInfo(&CardInfo);
595    *(DWORD*)buff = CardInfo.LogBlockNbr;
596    res = RES_OK;
597    break;
598
599  /* Get R/W sector size (WORD) */
600  case GET_SECTOR_SIZE :
601    BSP_SD_GetCardInfo(&CardInfo);
602    *(WORD*)buff = CardInfo.LogBlockSize;
603    res = RES_OK;
604    break;
605
606  /* Get erase block size in unit of sector (DWORD) */
607  case GET_BLOCK_SIZE :
608    BSP_SD_GetCardInfo(&CardInfo);
609    *(DWORD*)buff = CardInfo.LogBlockSize / SD_DEFAULT_BLOCK_SIZE;
610    res = RES_OK;
611    break;
612
613  default:
614    res = RES_PARERR;
615  }
616
617  return res;
618}
619#endif /* _USE_IOCTL == 1 */
620
621/* USER CODE BEGIN afterIoctlSection */
622/* can be used to modify previous code / undefine following code / add new code */
623/* USER CODE END afterIoctlSection */
624
625/* USER CODE BEGIN callbackSection */
626/* can be used to modify / following code or add new code */
627/* USER CODE END callbackSection */
628/**
629  * @brief Tx Transfer completed callbacks
630  * @param hsd: SD handle
631  * @retval None
632  */
633void BSP_SD_WriteCpltCallback(void)
634{
635
636  /*
637   * No need to add an "osKernelRunning()" check here, as the SD_initialize()
638   * is always called before any SD_Read()/SD_Write() call
639   */
640#if (osCMSIS < 0x20000U)
641   osMessagePut(SDQueueID, WRITE_CPLT_MSG, 0);
642#else
643   const uint16_t msg = WRITE_CPLT_MSG;
644   osMessageQueuePut(SDQueueID, (const void *)&msg, 0, 0);
645#endif
646}
647
648/**
649  * @brief Rx Transfer completed callbacks
650  * @param hsd: SD handle
651  * @retval None
652  */
653void BSP_SD_ReadCpltCallback(void)
654{
655  /*
656   * No need to add an "osKernelRunning()" check here, as the SD_initialize()
657   * is always called before any SD_Read()/SD_Write() call
658   */
659#if (osCMSIS < 0x20000U)
660   osMessagePut(SDQueueID, READ_CPLT_MSG, 0);
661#else
662   const uint16_t msg = READ_CPLT_MSG;
663   osMessageQueuePut(SDQueueID, (const void *)&msg, 0, 0);
664#endif
665}
666
667/* USER CODE BEGIN ErrorAbortCallbacks */
668/*
669void BSP_SD_AbortCallback(void)
670{
671#if (osCMSIS < 0x20000U)
672   osMessagePut(SDQueueID, RW_ABORT_MSG, 0);
673#else
674   const uint16_t msg = RW_ABORT_MSG;
675   osMessageQueuePut(SDQueueID, (const void *)&msg, 0, 0);
676#endif
677}
678*/
679/* USER CODE END ErrorAbortCallbacks */
680
681/* USER CODE BEGIN lastSection */
682/* can be used to modify / undefine previous code or add new code */
683/* USER CODE END lastSection */
Note: See TracBrowser for help on using the repository browser.