前言
DMA(Direct Memory Access:直接存储器存取)在无须 CPU 干预的情况下,可实现外设与存储器或存储器与存储器之间数据的直接传输,从而节省 CPU 资源来做其他操作。
以下例程以APM32F030x6x8为主控芯片,利用DMA接收和发送不定长的数据,其他ARM内核的单片机都大同小异。
一、串口初始化
void Uart1Init(u32 baud_rate)
{
GPIO_Config_T gpioConfig;
USART_Config_T usartConfigStruct;
/** Enable GPIO clock */
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
/** Enable COM1 or COM2 clock */
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
/** Connect PXx to USARTx_Tx */
GPIO_ConfigPinAF(GPIOA,GPIO_PIN_SOURCE_9,GPIO_AF_PIN1);
/** Connect PXx to USARRX_Rx */
GPIO_ConfigPinAF(GPIOA,GPIO_PIN_SOURCE_10,GPIO_AF_PIN1);
/** Configure USART Tx as alternate function push-pull */
gpioConfig.mode = GPIO_MODE_AF;
gpioConfig.pin = GPIO_PIN_9;
gpioConfig.speed = GPIO_SPEED_50MHz;
gpioConfig.outtype = GPIO_OUT_TYPE_PP;
gpioConfig.pupd = GPIO_PUPD_PU;
GPIO_Config(GPIOA, &gpioConfig);
/** Configure USART Rx as input floating */
gpioConfig.pin = GPIO_PIN_10;
GPIO_Config(GPIOA, &gpioConfig);
/** BaudRate baud */
usartConfigStruct.baudRate = baud_rate;
/** Receive and transmit enabled */
usartConfigStruct.mode = USART_MODE_TX_RX;
/** Hardware flow control disabled (RTS and CTS signals) */
usartConfigStruct.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
/** No parity */
usartConfigStruct.parity = USART_PARITY_NONE;
/** One Stop Bit */
usartConfigStruct.stopBits = USART_STOP_BIT_1;
/** Word Length = 8 Bits */
usartConfigStruct.wordLength = USART_WORD_LEN_8B;
/** USART_Config */
USART_Config(USART1, &usartConfigStruct);
/** Enable USART_Interrupt*/
USART_EnableInterrupt(USART1,USART_INT_IDLEIE);
NVIC_EnableIRQRequest(USART1_IRQn,2);
/** Enable USART */
USART_Enable(USART1);
}
以上代码将串口1初始化,并使能串口接收空闲中断。
二、DMA初始化
1.串口接收DMA初始化
void DMA_Rx_Init(uint32_t* RxBuf,uint32_t buf_size)
{
/** Enable DMA clock */
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);
/** DMA Configure */
DMA_Config_T dmaConfig;
/** size of buffer*/
dmaConfig.bufferSize = buf_size;
/** set memory Data Size*/
dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_BYTE;
/** Set peripheral Data Size*/
dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_BYTE;
/** Enable Memory Address increase*/
dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
/** Disable Peripheral Address increase*/
dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
/** Reset Circular Mode*/
dmaConfig.circular = DMA_CIRCULAR_DISABLE;
/** Disable M2M*/
dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
/** set priority*/
dmaConfig.priority = DMA_PRIORITY_LEVEL_HIGHT;
/** read from memory*/
dmaConfig.direction = DMA_DIR_PERIPHERAL;
/** Set memory Address*/
dmaConfig.memoryAddress = (uint32_t)RxBuf;
/** Set Peripheral Address*/
dmaConfig.peripheralAddress = (uint32_t)&USART1->RXDATA;
DMA_Config(DMA1_CHANNEL_3, &dmaConfig);
/** Clear DMA TF flag*/
DMA_ClearIntFlag(DMA1_INT_FLAG_TF3);
/** Enable DMA Interrupt*/
DMA_EnableInterrupt(DMA1_CHANNEL_3, DMA_INT_TFIE);
NVIC_EnableIRQRequest(DMA1_CH2_3_IRQn, 2);
USART_EnableDMA(USART1, USART_DMA_REQUEST_RX);
DMA_Enable(DMA1_CHANNEL_3);
}
2.串口发送DMA初始化
void DMA_Tx_Init(uint32_t* TxBuf)
{
/** Enable DMA clock */
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);
/** DMA Configure */
DMA_Config_T dmaConfig;
/** size of buffer*/
dmaConfig.bufferSize = 128;
/** set memory Data Size*/
dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_BYTE;
/** Set peripheral Data Size*/
dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_BYTE;
/** Enable Memory Address increase*/
dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
/** Disable Peripheral Address increase*/
dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
/** Reset Circular Mode*/
dmaConfig.circular = DMA_CIRCULAR_DISABLE;
/** Disable M2M*/
dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
/** set priority*/
dmaConfig.priority = DMA_PRIORITY_LEVEL_HIGHT;
/** read from memory*/
dmaConfig.direction = DMA_DIR_MEMORY;
/** Set memory Address*/
dmaConfig.memoryAddress = (uint32_t)TxBuf;
/** Set Peripheral Address*/
dmaConfig.peripheralAddress = (uint32_t)&USART1->TXDATA;
DMA_Config(DMA1_CHANNEL_2, &dmaConfig);
/** Clear DMA TF flag*/
DMA_ClearIntFlag(DMA1_INT_FLAG_TF2);
/** Enable DMA Interrupt*/
DMA_EnableInterrupt(DMA1_CHANNEL_2, DMA_INT_TFIE);
NVIC_EnableIRQRequest(DMA1_CH2_3_IRQn, 2);
USART_EnableDMA(USART1, USART_DMA_REQUEST_TX);
DMA_Disable(DMA1_CHANNEL_4);
}
3. 主程序代码
char UartRxBuf[128];
char UartTxBuf[128];
//DMA串口发送函数
void Uart_DMA_Tx(u8 *dat,u16 len)
{
memcpy(UartTxBuf,dat,len);
DMA_Disable(DMA1_CHANNEL_2);
DMA_SetDataNumber(DMA1_CHANNEL_2,len); //设置DMA传输的长度,只有在DMA disable的情况下才能设置
DMA_Enable(DMA1_CHANNEL_2);
}
//DMA串口接收函数
void Uart_DMA_Rx()
{
//将接收到数据,再次发送出来
//由于DMA的传输计数是递减式的,因此总数减去当前值,就是当前接收到的数量
Uart_DMA_Tx(UartRxBuf,128-DMA_ReadDataNumber(DMA1_CHANNEL_3));
memset(UartRxBuf,0,sizeof(UartRxBuf));
DMA_Disable(DMA1_CHANNEL_3);
DMA_SetDataNumber(DMA1_CHANNEL_3,128);
DMA_Enable(DMA1_CHANNEL_3);
}
//串口接收空闲中断
void USART1_IRQHandler(void)
{
USART_ClearStatusFlag(USART1, USART_FLAG_IDLEF);
Uart_DMA_Rx();
}
void main()
{
Uart1Init(115200);
DMA_Tx_Init((uint32_t*)UartTxBuf);
DMA_Rx_Init((uint32_t*)UartRxBuf);
while(1)
{
}
}
4. 实验结果
串口输入回环输出