野火STM32第35章 SDIO读写测试 实验过程犯的错误:卡在while(SD_GetStatus() != SD_TRANSFER_OK);

发布时间 2023-06-06 23:05:38作者: FBshark

看完书,我自己重新写了一遍代码。

写代码过程中,对DMA以下标绿的部分很不以为意。

 1 void SD_DMA_TxConfig(uint32_t *DMA_Tx_Buf, uint32_t BufferSize)
 2 {
 3     DMA_InitTypeDef DMA_InitStruct;
 4     
 5     /*Clock Enable-----In GPIO Config*/
 6     
 7     /*Flag Clear----------------------------*/
 8     DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4);
 9     
10     /*!< DMA2 Channel4 disable */
11    DMA_Cmd(DMA2_Channel4, DISABLE);
12     
13     /*-------------- Reset DMA init structure parameters values ------------------*/
14   DMA_InitStruct.DMA_PeripheralBaseAddr = SD_FIFO_ADDR;
15   DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)DMA_Tx_Buf;
16   DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
17   DMA_InitStruct.DMA_BufferSize = BufferSize / 4;  //除以4,把字转成字节单位
18   DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
19   DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
20   DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
21   DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
22   DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
23   DMA_InitStruct.DMA_Priority = DMA_Priority_High;
24   DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
25     
26     DMA_Init(DMA2_Channel4,&DMA_InitStruct);
27     DMA_Cmd(DMA2_Channel4, ENABLE);
28 }
29 
30 
31 /**
32     *@brief: Config_SD_DMA_Rx Function
33     Src:SD_card
34     Des:Buf
35     *@params:None
36     *@retvals:None
37 */
38 void SD_DMA_RxConfig(uint32_t *DMA_Rx_Buf, uint32_t BufferSize)
39 {
40     DMA_InitTypeDef DMA_InitStruct;
41     
42     /*Clock Enable-----In GPIO Config*/
43     
44     /*Flags Clear----------------*/
45     DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4);//清除DMA标志位
46     
47     /*!< DMA2 Channel4 disable */
48     DMA_Cmd(DMA2_Channel4, DISABLE);    //SDIO为第四通道
49     
50     
51     /*-------------- Reset DMA init structure parameters values ------------------*/
52   DMA_InitStruct.DMA_PeripheralBaseAddr = SD_FIFO_ADDR;
    (代码同上,此处省略此处 DMA_InitStruct 结构体初始化......)
64     DMA_Init(DMA2_Channel4,&DMA_InitStruct);
65     DMA_Cmd(DMA2_Channel4, ENABLE);
66 }

 首先要分析的是这两个代码在哪里调用的?

在读单个块的函数中, SD_ReadBlock 通过下面的代码实现数据传输,其中第4行调用了SD_DMA_RxConfig()

1 #elif defined (SD_DMA_MODE)
2     SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);
3     SDIO_DMACmd(ENABLE);
4     SD_DMA_RxConfig((uint32_t *)readbuff, BlockSize);

//读多个块第4行为 SD_DMA_RxConfig((uint32_t *)readbuff, (NumberOfBlocks * BlockSize));

同理,在写单个块的函数 SD_WriteBlock 中,也有相同内容。

1 #elif defined (SD_DMA_MODE)
2   SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);
3   SD_DMA_TxConfig((uint32_t *)writebuff, BlockSize);
4   SDIO_DMACmd(ENABLE);

 

 

经过我的实验,上面代码下面这部分内容(DMA清楚标志)取掉也不会有影响。

但是为了程序的稳健性,最好还是加上。

 7     /*Flag Clear----------------------------*/
 8     DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4);

但是不能没有这行代码:

10     /*!< DMA2 Channel4 disable */
11    DMA_Cmd(DMA2_Channel4, DISABLE);

一种原因是:在  SD_SingleBlockTest(void) 中,一开始进行写,已经使能了DMA传输,当接下来进行读的时候,如果不先让DMA暂时停止(此时需要修改的DMA结构体参数还没改),那么可能导致数据传输的错乱。

因此一种推理可能是只要在读的部分的DMA( SD_DMA_TxConfig)中让DMA暂时停止就可以,写的部分的DMA没必要。

但是经过实验,写的部分的DMA(SD_DMA_TxConfig)如果不让DMA暂时停止, 会卡在while(SD_GetStatus() != SD_TRANSFER_OK);

因此都得加,并且也说明上述的猜想是错误的。