- 使用DMA控制SDIO
上一节已经成功使用普通SDIO模式驱动起SD卡了,但是使用FreeRtos时,CubeMX会强制要求使用DMA模式。下面介绍以DMA模式驱动SDIO的方法。
- 首先,打开CubeMX配置好的文件STM32L476RGT6_SDIO.ioc。
- 到configuration选项卡中,打开SDMMC1,再到DMA Settings选项卡,这里我们添加DMA通道。
这里有三个选择:SDMMC1、SDMMC1_RX、SDMMC1_TX。如图所示,这里要稍微说一下,不同系列的芯片这里是不同的,例如F103系列,这里就只有一个选项SDIO。F4系列有两个选项SDMMC1_RX、SDMMC1_TX,这样怎么选呢?如果是F1系列,只有一个选项,代表这个DMA是发送接收复用的。如果是F4系列,代表DMA是RX、TX分开通道的。本例中使用的是L4系列,经过测试,复用和收发分开使用均可以。
文中只介绍收发DMA通道分开使用的方式,复用方式是只选SDMMC1这一个就够了,注意的是如果是收发复用通道,每次使用DMA收发函数之前都要重新配置DMA参数并初始化,主要配置DMA数据方向内存到外设还是外设到内存,相关函数可参考第三节的SD_DMAConfigRx和SD_DMAConfigTx函数内容。
配置好DMA后如图所示,注意红框中的部分。
3、打开SDMMC中断。如图所示。
4、打开NVIC选项卡配置中断。配置DMA通道低于SDIO的中断优先级。如图,配置DMA为2。
5、生成代码,打开工程。
打开“main.c”,找到测试代码,将原来的SD_Write_Read_Test(void)函数删除,替换为DMA模式,如下代码。也可以直接替换sd_status = HAL_SD_WriteBlocks_DMA(&hsd1,(uint8_t *)Buffer_Block_Tx,WRITE_READ_ADDRESS,NUMBER_OF_BLOCKS);
和
sd_status = HAL_SD_ReadBlocks_DMA(&hsd1,(uint8_t *)Buffer_Block_Rx,WRITE_READ_ADDRESS,NUMBER_OF_BLOCKS);语句。
/**
* 函数功能: SD卡读写测试
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void SD_Write_Read_Test(void)
{
int i,j = 0;
/* 填充数据到写缓存 */
Fill_Buffer(Buffer_Block_Tx,BLOCK_SIZE*NUMBER_OF_BLOCKS, 0x6666);
/* 往SD卡写入数据 */
sd_status = HAL_SD_WriteBlocks_DMA(&hsd1,(uint8_t *)Buffer_Block_Tx,WRITE_READ_ADDRESS,NUMBER_OF_BLOCKS);
printf("write status:%d\r\n",sd_status);
HAL_Delay(500);
/* 从SD卡读取数据 */
sd_status = HAL_SD_ReadBlocks_DMA(&hsd1,(uint8_t *)Buffer_Block_Rx,WRITE_READ_ADDRESS,NUMBER_OF_BLOCKS);
printf("read status:%d\r\n",sd_status);
/* 比较数据 */
test_status = Buffercmp(Buffer_Block_Tx, Buffer_Block_Rx, BLOCK_SIZE*NUMBER_OF_BLOCKS/4); //比较
if(test_status == PASSED)
{
printf("》读写测试成功!\r\n" );
for(i=0;i<BLOCK_SIZE*NUMBER_OF_BLOCKS/4;i++)
{
if(j==8)
{
printf("\r\n");
j=0;
}
printf("%08x ",Buffer_Block_Rx[i]);
j++;
}
printf("\r\n");
}
else
printf("》读写测试失败!\r\n " );
}
6、下载测试,实验成功。