- #include <stdio.h>
- #include <stm32f4xx.h>
- #include <string.h>
- #define USE_DMA
- int fputc(int ch, FILE *fp)
- {
- if (fp == stdout)
- {
- if (ch == '\n')
- {
- while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
- USART_SendData(USART1, '\r');
- }
- while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
- USART_SendData(USART1, ch);
- }
- return ch;
- }
- int main(void)
- {
- char *src = "01234567890123456789012345678901"; // 32个字符
-
- #ifdef USE_DMA
- DMA_InitTypeDef dma;
- #else
- uint8_t i;
- #endif
- GPIO_InitTypeDef gpio;
- SDIO_InitTypeDef sdio;
- SDIO_DataInitTypeDef sdio_data;
- USART_InitTypeDef usart;
-
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO | RCC_APB2Periph_USART1, ENABLE);
-
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);
-
- gpio.GPIO_Mode = GPIO_Mode_AF;
- gpio.GPIO_OType = GPIO_OType_PP;
- gpio.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
- gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
- gpio.GPIO_Speed = GPIO_High_Speed;
- GPIO_Init(GPIOA, &gpio);
-
- gpio.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
- GPIO_Init(GPIOC, &gpio);
- gpio.GPIO_Pin = GPIO_Pin_2;
- GPIO_Init(GPIOD, &gpio);
-
- USART_StructInit(&usart);
- usart.USART_BaudRate = 115200;
- USART_Init(USART1, &usart);
- USART_Cmd(USART1, ENABLE);
- printf("STM32F407VE DMA\n");
- printf("strlen=%d\n", strlen(src));
-
- SDIO_SetPowerState(SDIO_PowerState_ON);
- SDIO_StructInit(&sdio);
- sdio.SDIO_BusWide = SDIO_BusWide_4b;
- sdio.SDIO_ClockDiv = 255;
- //sdio.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Enable;
- SDIO_Init(&sdio);
- SDIO_ClockCmd(ENABLE);
- //SDIO_SetSDIOOperation(ENABLE);
-
- #ifdef USE_DMA
- dma.DMA_BufferSize = 8;
- dma.DMA_Channel = DMA_Channel_4;
- dma.DMA_DIR = DMA_DIR_MemoryToPeripheral;
- dma.DMA_FIFOMode = DMA_FIFOMode_Enable;
- dma.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
- dma.DMA_Memory0BaseAddr = (uint32_t)src;
- dma.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
- dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
- dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
- dma.DMA_Mode = DMA_Mode_Normal;
- dma.DMA_PeripheralBaseAddr = (uint32_t)&SDIO->FIFO;
- dma.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;
- dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
- dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- dma.DMA_Priority = DMA_Priority_VeryHigh;
- DMA_Init(DMA2_Stream3, &dma);
- //DMA_FlowControllerConfig(DMA2_Stream3, DMA_FlowCtrl_Peripheral);
- DMA_Cmd(DMA2_Stream3, ENABLE);
- #endif
-
- sdio_data.SDIO_DataBlockSize = SDIO_DataBlockSize_32b;
- sdio_data.SDIO_DataLength = 32;
- sdio_data.SDIO_DataTimeOut = 1000000;
- sdio_data.SDIO_DPSM = SDIO_DPSM_Enable;
- sdio_data.SDIO_TransferDir = SDIO_TransferDir_ToCard;
- sdio_data.SDIO_TransferMode = SDIO_TransferMode_Block;
- SDIO_DataConfig(&sdio_data);
-
- #ifdef USE_DMA
- SDIO_DMACmd(ENABLE);
- #else
- for (i = 0; i < 8; i++)
- {
- while (SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) == RESET);
- SDIO_WriteData(*(uint32_t *)(src + 4 * i));
- }
- #endif
-
- while (1)
- {
- if (DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_HTIF3) == SET)
- {
- DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_HTIF3);
- printf("Half transfer! remaining=%d\n", DMA_GetCurrDataCounter(DMA2_Stream3));
- }
-
- if (DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_TCIF3) == SET)
- {
- DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_TCIF3);
- printf("Transfer complete! remaining=%d\n", DMA_GetCurrDataCounter(DMA2_Stream3));
- }
-
- if (DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_FEIF3) == SET)
- {
- DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_FEIF3);
- printf("FIFO error! remaining=%d\n", DMA_GetCurrDataCounter(DMA2_Stream3));
- }
-
- if (DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_DMEIF3) == SET)
- {
- DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_DMEIF3);
- printf("Direct mode error!\n");
- }
-
- if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) == SET)
- {
- SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
- printf("SDIO data CRC failed!\n");
- }
-
- if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) == SET)
- {
- SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
- printf("SDIO data timeout!\n");
- }
-
- if (SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) == SET)
- {
- SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);
- printf("SDIO data underrun! DCOUNT=%d, NDT=%d\n", SDIO_GetDataCounter(), DMA_GetCurrDataCounter(DMA2_Stream3));
- }
- }
- }
复制代码
|
STM32F407VE DMA
strlen=32
SDIO data timeout!
(或SDIO data CRC failed!)
但如果使用DMA方式(定义了USE_DMA),则会输出:
STM32F407VE DMA
strlen=32
Half transfer! remaining=4
SDIO data underrun! DCOUNT=16, NDT=4
也就是说,DMA在还有16字节的时候就停止工作了。这是怎么回事?
也就是说,必须由SDIO来控制DMA的数据传输量。
程序运行结果为:
STM32F407VE DMA
strlen=32
Transfer complete! remaining=65527
FIFO error! remaining=65527
SDIO data CRC failed!
成功触发了TCIF中断,且(65535-65527)×4=32字节。
同时还触发了FEIF中断,提示FIFO error。
STM32F4xx_DSP_StdPeriph_Lib_V1.8.0标准外设库里面有一个SD卡的例程程序stm324x7i_eval_sdio_sd.c,其中处理DMA中断的SD_ProcessDMAIRQ函数实现如下:
看了一下STM32F4的参考手册,里面有这两段话:
If the DMEIFx or the FEIFx flag is set due to an overrun or underrun condition, the faulty
stream is not automatically disabled and it is up to the software to disable or not the stream
by resetting the EN bit in the DMA_SxCR register. This is because there is no data loss
when this kind of errors occur.
When a FIFO overrun or underrun condition occurs, the data are not lost because the
peripheral request is not acknowledged by the stream until the overrun or underrun
condition is cleared. If this acknowledge takes too much time, the peripheral itself may
detect an overrun or underrun condition of its internal buffer and data might be lost.
所以,FIFO error错误的产生原因是DMA本身的FIFO暂时出现了underrun/overrun的错误,此时DMA不会对SDIO的DMA请求发出确认,这是一个可自恢复的、不会影响数据传输的错误。