GadgetSeed  0.9.6
stm32f7xxx-disc_sdmmc.c
[詳解]
1 /** @file
2  @brief SD MMC ドライバ STM32F[769I|746G]-Discovery
3 
4  @date 2016.01.09
5  @author Takashi SHUDO
6 */
7 
8 #include "sysconfig.h"
9 #include "tkprintf.h"
10 #include "timer.h"
11 #include "device.h"
12 #include "str.h"
13 #include "interrupt.h"
14 #include "device/sd_ioctl.h"
15 #include "task/syscall.h"
16 
17 #ifdef GSC_TARGET_SYSTEM_STM32F769IDISCOVERY
18 #include "stm32f769i_discovery_sd.h"
19 #define SDMMC_IRQn SDMMC2_IRQn
20 #elif defined(GSC_TARGET_SYSTEM_STM32F746GDISCOVERY)
21 #include "stm32746g_discovery_sd.h"
22 #define SDMMC_IRQn SDMMC1_IRQn
23 #endif
24 
25 #define ENABLE_SDMMC_DMA /// DMA転送を使用する
26 #define SD_TIMEOUT (3*1000)
27 
28 //#define DEBUGKBITS 0x13
29 #include "dkprintf.h"
30 
31 
32 #ifdef ENABLE_SDMMC_DMA
33 extern SD_HandleTypeDef uSdHandle;
34 
35 static struct st_event dma_rx_evt;
36 static struct st_event dma_tx_evt;
37 
38 void HAL_SD_ErrorCallback(SD_HandleTypeDef *hsd)
39 {
40  SYSERR_PRINT("Error\n");
41 }
42 
43 void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd)
44 {
45  SYSERR_PRINT("Error\n");
46 }
47 
48 void BSP_SD_AbortCallback(void)
49 {
50  SYSERR_PRINT("Abort\n");
51 }
52 
53 static int flg_dma_rx_cmp = 0;
54 static int flg_dma_tx_cmp = 0;
55 static int flg_sd_cmp = 0;
56 
57 void BSP_SD_ReadCpltCallback(void)
58 {
59  DKFPRINTF(0x02, "\n");
60 
61  flg_dma_rx_cmp = 1;
62 }
63 
64 void BSP_SD_WriteCpltCallback(void)
65 {
66  DKFPRINTF(0x02, "\n");
67 
68  flg_dma_tx_cmp = 1;
69 }
70 
71 /* DMA2 Stream0 */
72 static void inthdr_sdmmc_dma_rx(unsigned int intnum, void *sp)
73 {
74  DKFPRINTF(0x02, "intnum=%d\n", intnum);
75 
76  HAL_DMA_IRQHandler(uSdHandle.hdmarx);
77 
78  DKFPRINTF(0x02, "end\n");
79 
80  if(flg_sd_cmp != 0) {
81  DKFPRINTF(0x02, "event wakeup dma_rx_evt\n");
82  flg_sd_cmp = 0;
83  event_wakeup_ISR(sp, &dma_rx_evt, 0);
84  }
85 }
86 
87 /* DMA2 Stream5 */
88 static void inthdr_sdmmc_dma_tx(unsigned int intnum, void *sp)
89 {
90  DKFPRINTF(0x02, "intnum=%d\n", intnum);
91 
92  HAL_DMA_IRQHandler(uSdHandle.hdmatx);
93 
94  DKFPRINTF(0x02, "end\n");
95 
96  if(flg_sd_cmp != 0) {
97  DKFPRINTF(0x02, "event wakeup dma_tx_evt\n");
98  flg_sd_cmp = 0;
99  event_wakeup_ISR(sp, &dma_tx_evt, 0);
100  }
101 }
102 
103 static void inthdr_sd(unsigned int intnum, void *sp)
104 {
105  DKFPRINTF(0x02, "intnum=%d\n", intnum);
106 
107  HAL_SD_IRQHandler(&uSdHandle);
108 
109  DKFPRINTF(0x02, "end\n");
110 
111  if(flg_dma_rx_cmp != 0) {
112  flg_dma_rx_cmp = 0;
113  DKFPRINTF(0x02, "event wakeup dma_rx_evt\n");
114  event_wakeup_ISR(sp, &dma_rx_evt, 0);
115  } else {
116  flg_sd_cmp = 1;
117  }
118 
119  if(flg_dma_tx_cmp != 0) {
120  flg_dma_tx_cmp = 0;
121  DKFPRINTF(0x02, "event wakeup dma_tx_evt\n");
122  event_wakeup_ISR(sp, &dma_tx_evt, 0);
123  } else {
124  flg_sd_cmp = 1;
125  }
126 }
127 #endif //ENABLE_SDMMC_DMA
128 
129 static int sdmmc_register(struct st_device *dev, char *param)
130 {
131  unsigned char stat;
132 
133  stat = BSP_SD_Init();
134 
135  if(stat != HAL_OK) {
136  SYSERR_PRINT("SD/MMC Initialize error(%d)\n", (int)stat);
137  return -1;
138  }
139 
140 #ifdef ENABLE_SDMMC_DMA
141  //BSP_SD_ITConfig();
142 
143  eventqueue_register_ISR(&dma_rx_evt, "sddmarx", 0, 0, 0);
144  HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, 0, 0); // 割り込みプライオリティは最低(0)
145  register_interrupt(IRQ2VECT(SD_DMAx_Rx_IRQn), inthdr_sdmmc_dma_rx);
146 
147  eventqueue_register_ISR(&dma_tx_evt, "sddmatx", 0, 0, 0);
148  HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, 0, 0); // 割り込みプライオリティは最低(0)
149  register_interrupt(IRQ2VECT(SD_DMAx_Tx_IRQn), inthdr_sdmmc_dma_tx);
150 
151  HAL_NVIC_SetPriority(SDMMC_IRQn, 0, 0); // 割り込みプライオリティは最低(0)
152  register_interrupt(IRQ2VECT(SDMMC_IRQn), inthdr_sd);
153 #endif //ENABLE_SDMMC_DMA
154 
155  return 0;
156 }
157 
158 static int sdmmc_unregister(struct st_device *dev)
159 {
160 #ifdef ENABLE_SDMMC_DMA
161  unregister_interrupt(IRQ2VECT(SD_DMAx_Rx_IRQn));
162  unregister_interrupt(IRQ2VECT(SD_DMAx_Tx_IRQn));
163  unregister_interrupt(IRQ2VECT(SDMMC_IRQn));
164 #endif //ENABLE_SDMMC_DMA
165 
166  return 0;
167 }
168 
169 static int sdmmc_open(struct st_device *dev)
170 {
171  DKFPRINTF(0x01, "dev=%p\n", dev);
172 
173  return 0;
174 }
175 
176 static int sdmmc_close(struct st_device *dev)
177 {
178  DKFPRINTF(0x01, "dev=%p\n", dev);
179 
180  return 0;
181 }
182 
183 static uint32_t sdbuf[BLOCKSIZE];
184 
185 static int sdmmc_block_read(struct st_device *dev, void *data, unsigned int sector, unsigned int blkcount)
186 {
187  unsigned char res;
188 #ifdef ENABLE_SDMMC_DMA
189  uint32_t alignedAddr;
190  int tout;
191 #endif
192 
193  DKFPRINTF(0x01, "dev=%p, data=%p, sector=%u, blkcount=%u\n", dev, data, sector, blkcount);
194 
195 #ifdef ENABLE_SDMMC_DMA
196  if((unsigned int)data & 0x3) {
197  DKFPRINTF(0x08, "data=%p\n", data);
198  /*
199  4のN倍アドレス以外のメモリアドレスにDMAで書き込みを行うとデータ化けが起きる
200  暫定対策として、DMAではSRAMに転送してからSDRAMにコピーする
201  */
202  int i;
203  for(i=0; i<blkcount; i++) {
204  flg_dma_rx_cmp = 0;
205  flg_sd_cmp = 0;
206  res = BSP_SD_ReadBlocks_DMA((uint32_t *)sdbuf, sector+i, 1);
207  if(res != MSD_OK) {
208  SYSERR_PRINT("BSP_SD_ReadBlocks_DMA(%d)\n", res);
209  goto rd_error;
210  }
211 
212  tout = event_wait(&dma_rx_evt, 0, SD_TIMEOUT);
213  if(tout == 0) {
214  SYSERR_PRINT("event_wait dma_rx_evt timeout(res = %d)\n", res);
215  }
216 
217  res = BSP_SD_GetCardState();
218  if(res == SD_TRANSFER_OK) {
219  alignedAddr = (uint32_t)sdbuf & ~0x1F;
220  SCB_InvalidateDCache_by_Addr((uint32_t *)alignedAddr, BLOCKSIZE + ((uint32_t)sdbuf - alignedAddr));
221  memorycopy(data, (const void *)sdbuf, BLOCKSIZE);
222  data += BLOCKSIZE;
223  res = MSD_OK;
224  } else {
225  SYSERR_PRINT("BSP_SD_GetCardState error(%d)\n", res);
226  res = MSD_ERROR;
227  break;
228  }
229  }
230  } else {
231  flg_dma_rx_cmp = 0;
232  flg_sd_cmp = 0;
233 
234  res = BSP_SD_ReadBlocks_DMA((uint32_t *)data, sector, blkcount);
235  if(res != MSD_OK) {
236  SYSERR_PRINT("BSP_SD_ReadBlocks_DMA(%d)\n", res);
237  goto rd_error;
238  }
239 
240  tout = event_wait(&dma_rx_evt, 0, SD_TIMEOUT);
241  if(tout == 0) {
242  SYSERR_PRINT("event_wait dma_rx_evt timeout(res = %d)\n", res);
243  }
244 
245  res = BSP_SD_GetCardState();
246  if(res == SD_TRANSFER_OK) {
247  alignedAddr = (uint32_t)data & ~0x1F;
248  SCB_InvalidateDCache_by_Addr((uint32_t *)alignedAddr, blkcount * BLOCKSIZE + ((uint32_t)data - alignedAddr));
249  } else {
250  SYSERR_PRINT("BSP_SD_GetCardState error(%d)\n", res);
251  res = MSD_ERROR;
252  }
253  }
254 rd_error:
255 #else
256  disable_interrupt(); /// @todo 割込を禁止しないと SDMMC_FLAG_RXOVERR エラーとなる。解析する。
257  res = BSP_SD_ReadBlocks((uint32_t *)data, sector, blkcount, SD_TIMEOUT);
258  enable_interrupt();
259 #endif
260 
261  if(res == MSD_OK) {
262  KXDUMP(0x04, data, blkcount * BLOCKSIZE);
263  return blkcount;
264  } else {
265  SYSERR_PRINT("Block read(data=%p, sector=%u, size=%d) error %u\n", data, sector, blkcount, res);
266  return 0;
267  }
268 }
269 
270 static int sdmmc_block_write(struct st_device *dev, const void *data, unsigned int sector, unsigned int blkcount)
271 {
272  unsigned char res = 0;
273 #ifdef ENABLE_SDMMC_DMA
274  int tout;
275 #endif
276 
277  DKFPRINTF(0x01, "dev=%p, data=%p, sector=%u, blkcount=%u\n", dev, data, sector, blkcount);
278 
279 #ifdef ENABLE_SDMMC_DMA
280  flg_dma_tx_cmp = 0;
281  flg_sd_cmp = 0;
282 
283  res = BSP_SD_WriteBlocks_DMA((uint32_t *)data, sector, blkcount);
284 
285  tout = event_wait(&dma_tx_evt, 0, SD_TIMEOUT);
286  if(tout == 0) {
287  SYSERR_PRINT("event_wait dma_tx_evt timeout(res = %d)\n", res);
288  }
289 
290  tout = get_kernel_time() + SD_TIMEOUT;
291  while(tout > get_kernel_time()) {
292  res = BSP_SD_GetCardState();
293  if(res == SD_TRANSFER_OK) {
294  break;
295  }
296  }
297  if(res != SD_TRANSFER_OK) {
298  SYSERR_PRINT("BSP_SD_GetCardState error(%d)\n", res);
299  }
300 #else
301  if((unsigned int)data & 0x3) {
302  DKFPRINTF(0x10, "data=%p\n", data);
303  int i, j;
304  for(j=0; j<blkcount; j++) {
305  unsigned char *sp = (unsigned char *)data + (j * BLOCKSIZE);
306  unsigned char *dp = (unsigned char *)sdbuf;
307  for(i=0; i<BLOCKSIZE; i++) {
308  *dp = *sp;
309  dp ++;
310  sp ++;
311  }
312  disable_interrupt();
313  res = BSP_SD_WriteBlocks(sdbuf, sector+j, 1, SD_TIMEOUT);
314  enable_interrupt();
315 
316  while(BSP_SD_GetCardState() != SD_TRANSFER_OK) {
317  ;
318  }
319  }
320  } else {
321  disable_interrupt();
322  res = BSP_SD_WriteBlocks((uint32_t *)data, sector, blkcount, SD_TIMEOUT);
323  enable_interrupt();
324 
325  while(BSP_SD_GetCardState() != SD_TRANSFER_OK) {
326  ;
327  }
328  }
329 #endif
330 
331  if(res == SD_TRANSFER_OK) {
332  return blkcount;
333  } else {
334  SYSERR_PRINT("Block write(data=%p, sector=%u, size=%d) error %u\n", data, sector, blkcount, res);
335  return 0;
336  }
337 }
338 
339 static int sdmmc_ioctl(struct st_device *dev, unsigned int com, unsigned int arg, void *param)
340 {
341  HAL_SD_CardInfoTypeDef cardInfo;
342  int rt = 0;
343 
344  DKFPRINTF(0x01, "dev=%p, com=%08x, arg=%08x, param=%p\n", dev, com, arg, param);
345 
346  BSP_SD_GetCardInfo(&cardInfo);
347 
348  DKPRINTF(0x02, "CardType = %u\n", cardInfo.CardType);
349  DKPRINTF(0x02, "CardVersion = %u\n", cardInfo.CardVersion);
350  DKPRINTF(0x02, "Class = %u\n", cardInfo.Class);
351  DKPRINTF(0x02, "RelCardAdd = %u\n", cardInfo.RelCardAdd);
352  DKPRINTF(0x02, "BlockNbr = %u\n", cardInfo.BlockNbr);
353  DKPRINTF(0x02, "BlockSize = %u\n", cardInfo.BlockSize);
354  DKPRINTF(0x02, "LogBlockNbr = %u\n", cardInfo.LogBlockNbr);
355  DKPRINTF(0x02, "LogBlockSize = %u\n", cardInfo.LogBlockSize);
356 
357  switch(com) {
359  {
360 #if FF_MAX_SS != FF_MIN_SS
361  rt = (int)cardInfo.BlockNbr;
362 #else
363  rt = (int)cardInfo.LogBlockNbr;
364 #endif
365  }
366  break;
367 
369  {
370 #if FF_MAX_SS != FF_MIN_SS
371  rt = (int)cardInfo.BlockSize;
372 #else
373  rt = (int)cardInfo.LogBlockSize;
374 #endif
375  }
376  break;
377 
379  {
380  rt = (int)cardInfo.BlockSize;
381  }
382  break;
383 
384  default:
385  SYSERR_PRINT("Unknow command %08lX arg %08lX\n", com, arg);
386  return 0;
387  }
388 
389  return rt;
390 }
391 
392 static int sdmmc_sync(struct st_device *dev)
393 {
394  return 0;
395 }
396 
397 static int sdmmc_suspend(struct st_device *dev)
398 {
399  int rt = 0;
400 
401  return rt;
402 }
403 
404 static int sdmmc_resume(struct st_device *dev)
405 {
406  int rt = 0;
407 
408  return rt;
409 }
410 
411 
412 const struct st_device sdmmc_device = {
414  .explan = "STM32F7xxx SD/MMC Storage",
415  .register_dev = sdmmc_register,
416  .unregister_dev = sdmmc_unregister,
417  .open = sdmmc_open,
418  .close = sdmmc_close,
419  .block_read = sdmmc_block_read,
420  .block_write = sdmmc_block_write,
421  .ioctl = sdmmc_ioctl,
422  .sync = sdmmc_sync,
423  .suspend = sdmmc_suspend,
424  .resume = sdmmc_resume,
425 };
#define IOCMD_SD_GET_SECTOR_COUNT
セクタ数を取得する
Definition: sd_ioctl.h:17
#define IOCMD_SD_GET_BLOCK_SIZE
消去ブロックサイズを取得する
Definition: sd_ioctl.h:19
文字列処理
#define DEF_DEV_NAME_SD
標準ストレージデバイス名(MMC,SD等)
Definition: sd_ioctl.h:15
カーネルタイマ
void eventqueue_register_ISR(struct st_event *evtque, const char *name, void *args, unsigned int arg_size, int arg_count)
イベントキューを登録する
Definition: event.c:36
void event_wakeup_ISR(void *sp, struct st_event *evtque, void *arg)
イベントキューにイベントを登録し、イベント待ちタスクを起動する
Definition: task.c:923
#define IOCMD_SD_GET_SECTOR_SIZE
1セクタサイズを取得する
Definition: sd_ioctl.h:18
カーネル用機能限定printf
イベント
Definition: event.h:15
void * memorycopy(void *dest, const void *src, unsigned int count)
メモリコピー
Definition: str.c:760
システムコール
割り込みハンドラ
ストレージデバイスドライバ ioctl 用マクロ定義
unsigned long long get_kernel_time(void)
カーネル時間を取得する
Definition: timer.c:192
デバイスドライバAPI
デバイスドライバ構造体
Definition: device.h:25
カーネル、ドライバ(非タスク)デバッグ用マクロ
char name[MAX_DEVNAMELRN]
デバイス名文字列
Definition: device.h:26
int event_wait(struct st_event *evtque, void *argp, unsigned int timeout)
タスクをイベント待ち状態にする
Definition: syscall_api.c:364