【AT-START-F425测评】+ 串口空闲中断与DMA
[复制链接]
0、前言
上节使用串口空闲中断和接收中断实现了串口不定长数据接收,本文使用DMA的方式接收串口数据。
1、两种方式特点分析
串口接收中断的特点:每接收一个数据,需要进一次中断,会不断打断正常程序的执行,在接收数据期间,cpu会不断切换上下文,消耗cpu的时间。
使用DMA接收的优势:配置好DMA之后,让DMA控制器去接收,不需要cpu参与,节省了cpu的时间,提高了cpu的利用率。
2、如何判断串口数据接收完成
这里使用空闲中断,当产生空闲中断的时候,就认为是一帧数据传输完成了。
3、关于AT32F425的DMA
可以看出有1个DMA控制器,支持7个通道;
支持8位、16位、32位数据宽度;
最大支持65535个数据传输;
DMA支持的外设ADC、I2C、SPI、TIME、USART等。
4、DMA通道配置
可以看出,任何一个通道的请求来源,都可以弹性配置,而不是固定的几个,这也是AT32F425的DMA的一个特色之处。
5、代码实现
(1)缓冲区定义
#define UART_MAX_BUFF_LEN 255
uint8_t UartBuff[UART_MAX_BUFF_LEN];
uint8_t UartIdle=0;
uint8_t UartLen=0;
(2)串口初始化
void UartInit(void)
{
gpio_init_type gpio_init_struct;
crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
/* enable the usart1 and gpio clock */
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
gpio_default_para_init(&gpio_init_struct);
/* configure the usart1 tx/rx pin */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = GPIO_PINS_6 | GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
/* config usart1 iomux */
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE6, GPIO_MUX_0);
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE7, GPIO_MUX_0);
/* config usart1 nvic interrupt */
nvic_irq_enable(USART1_IRQn, 3, 0);
/* configure usart1 param */
usart_init(USART1, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
usart_parity_selection_config(USART1, USART_PARITY_NONE);
usart_hardware_flow_control_set(USART1,USART_HARDWARE_FLOW_NONE);
usart_transmitter_enable(USART1, TRUE);
usart_receiver_enable(USART1, TRUE);
usart_dma_receiver_enable(USART1, TRUE);
usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE);
usart_enable(USART1, TRUE);
void UartDmaRxInit(void);
UartDmaRxInit();
}
(3)串口1接收DMA配置
这里传输方向是外设到内存,外设就是串口,内存是数据缓冲区;
接收到数据后要保存起来,因此内存每次自增。
void UartDmaRxInit(void)
{
dma_init_type dma_init_struct;
/* enable dma1 clock */
crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
dma_reset(DMA1_CHANNEL1);
dma_default_para_init(&dma_init_struct);
dma_init_struct.buffer_size = UART_MAX_BUFF_LEN;
dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_base_addr = (uint32_t)UartBuff;
dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
dma_init_struct.memory_inc_enable = TRUE;
dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
dma_init_struct.peripheral_inc_enable = FALSE;
dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
dma_init_struct.loop_mode_enable = FALSE;
dma_init(DMA1_CHANNEL1, &dma_init_struct);
/* config flexible dma for usart1 rx */
dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_UART1_RX);
dma_channel_enable(DMA1_CHANNEL1, TRUE);
}
(4)串口中断
这里只用到了空闲中断,产生空闲中断后,读取接收到的数据长度。
void USART1_IRQHandler(void)
{
if(usart_flag_get(USART1,USART_IDLEF_FLAG)!= RESET)
{
UartDmaRxData();
usart_data_receive(USART1);
}
}
(5)串口DMA接收
void UartDmaRxData(void)
{
dma_channel_enable(DMA1_CHANNEL1, FALSE); //先暂时关闭dma
dma_flag_clear(DMA1_FDT1_FLAG);
UartLen=UART_MAX_BUFF_LEN-dma_data_number_get(DMA1_CHANNEL1); //获取接收的长度
dma_data_number_set(DMA1_CHANNEL1, UART_MAX_BUFF_LEN); //重新设置长度
UartIdle=1; //一帧数据接收完成标志
}
(6)应用层处理
void UartPro(void)
{
if(UartLen&&UartIdle)
{
printf("Recv:%d,[",UartLen);
UartSend(UartBuff,UartLen);
printf("]\r\n");
UartLen=0;
UartIdle=0;
dma_channel_enable(DMA1_CHANNEL1, TRUE); //重新打开DMA
}
}
(7)其他代码
void UartSend(uint8_t *data,uint8_t len)
{
for(uint8_t i=0; i<len;i++)
{
while (RESET == usart_flag_get(USART1, USART_TDC_FLAG));
usart_data_transmit(USART1, data[i]);
}
}
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
while(usart_flag_get(USART1, USART_TDC_FLAG) == RESET);
usart_data_transmit(USART1, (uint8_t) ch);
return ch;
}
6、测试
|