STM32 Bootloader
Customizable Bootloader for STM32 microcontrollers
sdmmc.c
Go to the documentation of this file.
1 
25 /* Includes ------------------------------------------------------------------*/
26 #include "sdmmc.h"
27 
28 #include "board.h"
29 #include "error_handler.h"
30 #include "mcu_hal.h"
31 #include "rcc.h"
32 
33 /* Private variables ---------------------------------------------------------*/
35 static SD_HandleTypeDef sdHandle = {0};
40 
41 /* Private function prototypes -----------------------------------------------*/
45 static void SdmmcResetPeripheralHandleState(void);
46 
52 static bool SdmmcConfigureDmaRx(void);
53 
59 static bool SdmmcConfigureDmaTx(void);
60 
61 /* Functions -----------------------------------------------------------------*/
62 bool SdmmcInit(void)
63 {
64  bool result = false;
65 
67  RccEnableDma2();
68 
69  // Message: A conversion should not be performed between a pointer to
70  // object and an integer type [misra-c2012-11.4]
71  // Reason: The following instance definition is addressing the memory
72  // mapped base register of the hardware peripheral.
73  // Risk: Conversion of a pointer to object into an integer may
74  // produce a value that cannot be represented in the chosen
75  // integer type resulting in undefined behavior.
76  // Prevention: Code reviews.
77  // cppcheck-suppress [misra-c2012-11.4]
78  sdHandle.Instance = SDMMC1;
79  sdHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
80  sdHandle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
81  sdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
82  sdHandle.Init.BusWide = SDMMC_BUS_WIDE_1B;
83  sdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
84  sdHandle.Init.ClockDiv = 0;
85 
86  for (uint_fast8_t tries = 0; tries < SDMMC_INIT_MAX_TRIES; ++tries)
87  {
89  if (HAL_OK != HAL_SD_Init(&sdHandle))
90  {
91  /* Retry */
92  continue;
93  }
94 
95  /* Enable wide bus operation */
96  if (HAL_OK !=
97  HAL_SD_ConfigWideBusOperation(&sdHandle, SDMMC_BUS_WIDE_4B))
98  {
99  /* Retry */
100  continue;
101  }
102 
103  result = true;
104  }
105 
106  HAL_NVIC_SetPriority(SDMMC1_IRQn, SDMMC_IRQ_PRIORITY, 0U);
107  HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
108 
109  // Note: there is only one DMA channel for RX and TX, therefore the DMA
110  // initialization is done directly before a DMA transfer.
111 
112  return result;
113 }
114 
115 void SdmmcDeInit(void)
116 {
117  (void)HAL_SD_DeInit(&sdHandle);
119 
120  HAL_NVIC_DisableIRQ(SDMMC1_IRQn);
121  HAL_NVIC_DisableIRQ(DMA2_Channel5_IRQn);
122 
124  RccDisableDma2();
125 }
126 
127 bool SdmmcGetCardInfo(SdCardInfo* const cardInfo)
128 {
129  return (HAL_OK == HAL_SD_GetCardInfo(&sdHandle, cardInfo));
130 }
131 
133 {
134  return (HAL_SD_CARD_TRANSFER == HAL_SD_GetCardState(&sdHandle));
135 }
136 
137 bool SdmmcReadBlocks(uint8_t* const data,
138  const uint32_t blockAddress,
139  const uint32_t numOfBlocks,
140  const uint32_t timeout)
141 {
142  return (HAL_OK == HAL_SD_ReadBlocks(&sdHandle, data, blockAddress,
143  numOfBlocks, timeout));
144 }
145 
146 bool SdmmcWriteBlocks(const uint8_t* const data,
147  const uint32_t blockAddress,
148  const uint32_t numOfBlocks,
149  const uint32_t timeout)
150 {
151  // Message: A conversion shall not remove any const, volatile or _Atomic
152  // qualification from the type pointed to by a pointer
153  // [misra-c2012-11.8]
154  // Reason: The HAL implementation expects a non-const pointer to
155  // non-const data, however the write operation does not
156  // (and should not) modify neither the pointer, nor the
157  // value. Therefore, this wrapper function expects a const
158  // pointer to const data and both the MISRA rule and the
159  // the message from clang-tidy [error: cast from 'const
160  // unsigned X *' to 'unsigned X *' drops const qualifier]
161  // is suppressed here.
162  // Risk: Removing a const qualifier might circumvent the
163  // read-only status of an object and result in it being
164  // modified.
165  // Prevention: Code reviews.
166  // cppcheck-suppress [misra-c2012-11.8]
167  // NOLINTNEXTLINE(clang-diagnostic-cast-qual)
168  return (HAL_OK == HAL_SD_WriteBlocks(&sdHandle, (uint8_t*)data,
169  blockAddress, numOfBlocks, timeout));
170 }
171 
172 bool SdmmcReadBlocksDma(uint8_t* const data,
173  const uint32_t blockAddress,
174  const uint32_t numOfBlocks)
175 {
176  bool result = false;
177 
178  // Invalidate the dma tx handle
179  sdHandle.hdmatx = NULL;
180 
181  // Prepare the dma channel for read operation
182  if (SdmmcConfigureDmaRx())
183  {
184  result = (HAL_OK == HAL_SD_ReadBlocks_DMA(&sdHandle, data, blockAddress,
185  numOfBlocks));
186  }
187 
188  return result;
189 }
190 
191 bool SdmmcWriteBlocksDma(const uint8_t* const data,
192  const uint32_t blockAddress,
193  const uint32_t numOfBlocks)
194 {
195  bool result = false;
196 
197  // Invalidate the dma rx handle
198  sdHandle.hdmarx = NULL;
199 
200  // Prepare the dma channel for write operation
201  if (SdmmcConfigureDmaTx())
202  {
203  // Message: A conversion shall not remove any const, volatile or
204  // _Atomic
205  // qualification from the type pointed to by a pointer
206  // [misra-c2012-11.8]
207  // Reason: The HAL implementation expects a non-const pointer to
208  // non-const data, however the write operation does not
209  // (and should not) modify neither the pointer, nor the
210  // value. Therefore, this wrapper function expects a const
211  // pointer to const data and both the MISRA rule and the
212  // the message from clang-tidy [error: cast from 'const
213  // unsigned X *' to 'unsigned X *' drops const qualifier]
214  // is suppressed here.
215  // Risk: Removing a const qualifier might circumvent the
216  // read-only status of an object and result in it being
217  // modified.
218  // Prevention: Code reviews.
219  // cppcheck-suppress [misra-c2012-11.8]
220  // NOLINTNEXTLINE(clang-diagnostic-cast-qual)
221  result = (HAL_OK == HAL_SD_WriteBlocks_DMA(&sdHandle, (uint8_t*)data,
222  blockAddress, numOfBlocks));
223  }
224 
225  return result;
226 }
227 
228 static bool SdmmcConfigureDmaRx(void)
229 {
230  static DMA_HandleTypeDef dmaRx = {0};
231 
232  // Message: A conversion should not be performed between a pointer to
233  // object and an integer type [misra-c2012-11.4]
234  // Reason: The following instance definition is addressing the memory
235  // mapped base register of the hardware peripheral.
236  // Risk: Conversion of a pointer to object into an integer may
237  // produce a value that cannot be represented in the chosen
238  // integer type resulting in undefined behavior.
239  // Prevention: Code reviews.
240  // cppcheck-suppress [misra-c2012-11.4]
241  dmaRx.Instance = DMA2_Channel5;
242  dmaRx.Init.Request = DMA_REQUEST_7;
243  dmaRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
244  dmaRx.Init.PeriphInc = DMA_PINC_DISABLE;
245  dmaRx.Init.MemInc = DMA_MINC_ENABLE;
246  dmaRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
247  dmaRx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
248  dmaRx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
249 
250  /* Associate the DMA handle */
251  __HAL_LINKDMA(&sdHandle, hdmarx, dmaRx);
252 
253  /* Stop any ongoing transfer and reset the state */
254  (void)HAL_DMA_Abort(&dmaRx);
255 
256  /* Deinitialize the Channel for new transfer */
257  (void)HAL_DMA_DeInit(&dmaRx);
258 
259  /* Configure the DMA Channel */
260  const bool result = (HAL_OK == HAL_DMA_Init(&dmaRx));
261  if (result)
262  {
263  /* NVIC configuration for DMA transfer complete interrupt */
264  HAL_NVIC_SetPriority(DMA2_Channel5_IRQn, SDMMC_DMA_IRQ_PRIORITY, 0U);
265  HAL_NVIC_EnableIRQ(DMA2_Channel5_IRQn);
266  }
267 
268  return result;
269 }
270 
271 static bool SdmmcConfigureDmaTx(void)
272 {
273  static DMA_HandleTypeDef dmaTx = {0};
274 
275  // Message: A conversion should not be performed between a pointer to
276  // object and an integer type [misra-c2012-11.4]
277  // Reason: The following instance definition is addressing the memory
278  // mapped base register of the hardware peripheral.
279  // Risk: Conversion of a pointer to object into an integer may
280  // produce a value that cannot be represented in the chosen
281  // integer type resulting in undefined behavior.
282  // Prevention: Code reviews.
283  // cppcheck-suppress [misra-c2012-11.4]
284  dmaTx.Instance = DMA2_Channel5;
285  dmaTx.Init.Request = DMA_REQUEST_7;
286  dmaTx.Init.Direction = DMA_MEMORY_TO_PERIPH;
287  dmaTx.Init.PeriphInc = DMA_PINC_DISABLE;
288  dmaTx.Init.MemInc = DMA_MINC_ENABLE;
289  dmaTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
290  dmaTx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
291  dmaTx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
292 
293  /* Associate the DMA handle */
294  __HAL_LINKDMA(&sdHandle, hdmatx, dmaTx);
295 
296  /* Stop any ongoing transfer and reset the state */
297  (void)HAL_DMA_Abort(&dmaTx);
298 
299  /* Deinitialize the Channel for new transfer */
300  (void)HAL_DMA_DeInit(&dmaTx);
301 
302  /* Configure the DMA Channel */
303  const bool result = (HAL_OK == HAL_DMA_Init(&dmaTx));
304  if (result)
305  {
306  /* NVIC configuration for DMA transfer complete interrupt */
307  HAL_NVIC_SetPriority(DMA2_Channel5_IRQn, SDMMC_DMA_IRQ_PRIORITY, 0U);
308  HAL_NVIC_EnableIRQ(DMA2_Channel5_IRQn);
309  }
310 
311  return result;
312 }
313 
315 {
316  rxCompleteCallback = callback;
317 }
318 
320 {
321  txCompleteCallback = callback;
322 }
323 
325 {
326  sdHandle.State = HAL_SD_STATE_RESET;
327  sdHandle.Context = 0;
328  sdHandle.ErrorCode = 0;
329  sdHandle.SdCard.CardType = 0;
330  sdHandle.SdCard.CardVersion = 0;
331  sdHandle.SdCard.Class = 0;
332  sdHandle.SdCard.RelCardAdd = 0;
333  sdHandle.SdCard.BlockNbr = 0;
334  sdHandle.SdCard.BlockSize = 0;
335  sdHandle.SdCard.LogBlockNbr = 0;
336  sdHandle.SdCard.LogBlockSize = 0;
337  sdHandle.CSD[0] = 0;
338  sdHandle.CSD[1] = 0;
339  sdHandle.CSD[2] = 0;
340  sdHandle.CSD[3] = 0;
341  sdHandle.CID[0] = 0;
342  sdHandle.CID[1] = 0;
343  sdHandle.CID[2] = 0;
344  sdHandle.CID[3] = 0;
345 }
346 
350 // NOLINTNEXTLINE(readability-identifier-naming,clang-diagnostic-missing-prototypes)
352 {
353  HAL_SD_IRQHandler(&sdHandle);
354 }
355 
359 // NOLINTNEXTLINE(readability-identifier-naming,clang-diagnostic-missing-prototypes)
361 {
362  if ((sdHandle.Context == (SD_CONTEXT_DMA | SD_CONTEXT_READ_SINGLE_BLOCK)) ||
363  (sdHandle.Context == (SD_CONTEXT_DMA | SD_CONTEXT_READ_MULTIPLE_BLOCK)))
364  {
365  HAL_DMA_IRQHandler(sdHandle.hdmarx);
366  }
367  else if ((sdHandle.Context ==
368  (SD_CONTEXT_DMA | SD_CONTEXT_WRITE_SINGLE_BLOCK)) ||
369  (sdHandle.Context ==
370  (SD_CONTEXT_DMA | SD_CONTEXT_WRITE_MULTIPLE_BLOCK)))
371  {
372  HAL_DMA_IRQHandler(sdHandle.hdmatx);
373  }
374  else
375  {
376  ErrorHandler();
377  }
378 }
379 
386 void HAL_SD_RxCpltCallback(SD_HandleTypeDef* hsd)
387 {
388  UNUSED(hsd);
389  if (rxCompleteCallback != NULL)
390  {
392  }
393 }
394 
401 void HAL_SD_TxCpltCallback(SD_HandleTypeDef* hsd)
402 {
403  UNUSED(hsd);
404  if (txCompleteCallback != NULL)
405  {
407  }
408 }
409 
416 void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd)
417 {
418  UNUSED(hsd);
419  // Do nothing
420 }
421 
428 void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd)
429 {
430  UNUSED(hsd);
431  ErrorHandler();
432 }
433 
This file contains the board-specific GPIO pin definitions, peripheral configurations,...
This file contains the error handling function prototypes.
void ErrorHandler(void)
This function is executed in case of error occurrence.
Definition: error_handler.c:32
#define SDMMC_INIT_MAX_TRIES
Definition: board.h:86
#define SDMMC_DMA_IRQ_PRIORITY
Definition: board.h:90
#define SDMMC_IRQ_PRIORITY
Definition: board.h:88
void RccDisableDma2(void)
Disable the DMA2 peripheral clock.
Definition: rcc.c:47
void RccEnableSdmmc1(void)
Enable the SDMMC1 peripheral clock.
Definition: rcc.c:112
void RccEnableDma2(void)
Enable the DMA2 peripheral clock.
Definition: rcc.c:42
void RccDisableSdmmc1(void)
Disable the SDMMC1 peripheral clock.
Definition: rcc.c:117
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
SD card receive complete callback.
Definition: sdmmc.c:386
static bool SdmmcConfigureDmaTx(void)
Configure the DMA channel for SD card transmit transfers.
Definition: sdmmc.c:271
static void SdmmcResetPeripheralHandleState(void)
Reset the SD peripheral handle state and card information.
Definition: sdmmc.c:324
bool SdmmcInit(void)
Initialize the SDMMC peripheral and the SD card.
Definition: sdmmc.c:62
bool SdmmcGetCardInfo(SdCardInfo *const cardInfo)
Get the SD card information (capacity, block size, etc.).
Definition: sdmmc.c:127
void SdmmcRegisterRxCompleteCallback(Callback callback)
Register a callback for the DMA receive complete event.
Definition: sdmmc.c:314
static Callback txCompleteCallback
Definition: sdmmc.c:39
void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd)
SD card abort callback.
Definition: sdmmc.c:416
void DMA2_Channel5_IRQHandler(void)
DMA2 Channel 5 interrupt handler for SDMMC DMA transfers.
Definition: sdmmc.c:360
bool SdmmcWriteBlocks(const uint8_t *const data, const uint32_t blockAddress, const uint32_t numOfBlocks, const uint32_t timeout)
Write blocks to the SD card in blocking mode.
Definition: sdmmc.c:146
bool SdmmcReadBlocks(uint8_t *const data, const uint32_t blockAddress, const uint32_t numOfBlocks, const uint32_t timeout)
Read blocks from the SD card in blocking mode.
Definition: sdmmc.c:137
static bool SdmmcConfigureDmaRx(void)
Configure the DMA channel for SD card receive transfers.
Definition: sdmmc.c:228
bool SdmmcReadBlocksDma(uint8_t *const data, const uint32_t blockAddress, const uint32_t numOfBlocks)
Read blocks from the SD card using DMA.
Definition: sdmmc.c:172
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
SD card transmit complete callback.
Definition: sdmmc.c:401
static SD_HandleTypeDef sdHandle
Definition: sdmmc.c:35
void SdmmcDeInit(void)
De-initialize the SDMMC peripheral.
Definition: sdmmc.c:115
void SDMMC1_IRQHandler(void)
SDMMC1 interrupt handler.
Definition: sdmmc.c:351
void(* Callback)(void)
Definition: sdmmc.h:44
void SdmmcRegisterTxCompleteCallback(Callback callback)
Register a callback for the DMA transmit complete event.
Definition: sdmmc.c:319
static Callback rxCompleteCallback
Definition: sdmmc.c:37
bool SdmmcWriteBlocksDma(const uint8_t *const data, const uint32_t blockAddress, const uint32_t numOfBlocks)
Write blocks to the SD card using DMA.
Definition: sdmmc.c:191
HAL_SD_CardInfoTypeDef SdCardInfo
Definition: sdmmc.h:41
bool SdmmcIsCardInTransferState(void)
Check if the SD card is in the transfer state.
Definition: sdmmc.c:132
void HAL_SD_ErrorCallback(SD_HandleTypeDef *hsd)
SD card error callback.
Definition: sdmmc.c:428
This file includes the microcontroller-specific HAL header files.
This file contains the RCC (Reset and Clock Control) driver function prototypes for enabling and disa...
This file contains the SDMMC peripheral driver function prototypes for SD card initialization,...