GD32L23X USART+DMA空闲中断收发数据
DMA+USART1收发数据
空闲中断函数以及宏定义
#define USART1_RDATA_ADDRESS (&USART_RDATA(USART1))
#define USART1_TDATA_ADDRESS (&USART_TDATA(USART1))
#define ARRAYNUM(arr_nanme) (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))
#define USART_TX_RX_BUFF_LEN 256
#define USART_DMA_IDLE 0
#define USART_DMA_BUSY 1
#pragma pack(1)
typedef struct
{
uint8_t dma_tx_buf[USART_TX_RX_BUFF_LEN];
uint8_t dma_rx_buf[USART_TX_RX_BUFF_LEN];
uint16_t dma_rev_cnt;
} USART_DataInfo;
USART_DataInfo usart_DataInfo;
static void com_usart_init(uint32_t baudrate);
static void dma_usart_init(void);
static dma_parameter_struct dma_init_struct;
uint8_t rxdata[USART_TX_RX_BUFF_LEN];
void USART1_Init(uint32_t baudrate)
{
// initialize the com
com_usart_init(baudrate);
// configure DMA ch0 and ch1
dma_usart_init();
}
void USART1_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE))
{
// clear flag
usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);
// disable channel
dma_channel_disable(DMA_CH1);
// read
usart_DataInfo.dma_rev_cnt = sizeof(usart_DataInfo.dma_rx_buf) - dma_transfer_number_get(DMA_CH1);
memcpy(rxdata, usart_DataInfo.dma_rx_buf, usart_DataInfo.dma_rev_cnt);
memset(usart_DataInfo.dma_rx_buf, 0, sizeof(usart_DataInfo.dma_rx_buf));
// reset DMA configure
dma_channel_enable(DMA_CH1);
}
}
USART1
配置 8N1 LSB 中断IRQ优先级0,无硬件流控制
硬件流控概念理解(需要多加两条线)
硬件流控制常用的有RTS/CTS流控制和DTR/DSR(数据终端就绪/数据设置就绪)流控制。
RTS (Require ToSend,发送请求)为输出信号,用于指示本设备准备好可接收数据,低电平有效,低电平说明本设备可以接收数据。
CTS (Clear ToSend,发送允许)为输入信号,用于判断是否可以向对方发送数据,低电平有效,低电平说明本设备可以向对方发送数据。
static void com_usart_init(uint32_t baudrate)
{
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART1);
/* enable COM GPIO clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* connect port to USART TX */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2);
/* connect port to USART RX */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_3);
/* configure USART TX as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2);
/* configure USART RX as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_3);
/* USART configure */
usart_deinit(USART1);
usart_baudrate_set(USART1, baudrate);
usart_word_length_set(USART1, USART_WL_8BIT);
usart_parity_config(USART1, USART_PM_NONE);
usart_stop_bit_set(USART1, USART_STB_1BIT);
usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE);
usart_data_first_config(USART1, USART_MSBF_LSB);
usart_receive_config(USART1, USART_RECEIVE_ENABLE);
usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
/*USART enable*/
usart_interrupt_enable(USART1, USART_INT_IDLE);
nvic_irq_enable(USART1_IRQn, 0);
usart_enable(USART1);
}
DMA
DMA直接存储器访问控制器
能够让外设与存储器之间直接进行数据传输,而不需要CPU的参与,在串口检测到有数据输入的时候,让DMA直接往我们定义好的存储器中搬收到的UART数据,在这个过程中,CPU还是在处理自己的事,最后,在一帧数据传输完成后,通过中断告诉主任务一帧数据已经传输完毕,主任务再对接收到的数据进行相应的处理。整个过程下来,程序代码只会触发一次中断,就是DMA搬移完数据后通知CPU的那一次中断,对比前一种方法,每接收到一个字节就需要进中断把数据读到自定的的FIFO中,第二种方法不论一帧数据的数据量有多大,我们都只会触发一次中断。
DMAMUX 基本功能
第一块,DMA请求路由器【Request Multiplexer】, 它的核心功能就是实现DMA请求的路由转发。其组成单元是DMA请求路由通道,请求路由器由多个请求路由通道组成。
第二块,DMA请求生成器【RequestGenerator】,它的核心功能,就是生成DMA请求。
相比于其他单片机GD32L23X有DMAMUX功能后,DMA不在与外设绑定
static void dma_usart_init(void)
{
dma_parameter_struct dma_init_struct;
/* initialize DMA channel 2 */
rcu_periph_clock_enable(RCU_DMA);
dma_deinit(DMA_CH2);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_USART1_TX;
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr = NULL;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = 0;
dma_init_struct.periph_addr = (uint32_t)USART1_TDATA_ADDRESS;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH2, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA_CH2);
dma_memory_to_memory_disable(DMA_CH2);
/* disable the DMAMUX_MUXCH2 synchronization mode */
dmamux_synchronization_disable(DMAMUX_MUXCH2);
/* USART DMA enable for transmission and reception */
usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
/* initialize DMA channel 1 */
dma_deinit(DMA_CH1);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_USART1_RX;
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)&usart_DataInfo.dma_rx_buf[0];
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = ARRAYNUM(usart_DataInfo.dma_rx_buf);
dma_init_struct.periph_addr = (uint32_t)USART1_RDATA_ADDRESS;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH1, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA_CH1);
dma_memory_to_memory_disable(DMA_CH1);
/* disable the DMAMUX_MUXCH1 synchronization mode */
dmamux_synchronization_disable(DMAMUX_MUXCH1);
/* USART DMA enable for reception */
usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
}
printf 重定义
在Xcom里换行尾部加 \ r\ n
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE* f)
{
usart_data_transmit(USART1, (uint8_t)ch);
while(RESET == usart_flag_get(USART1, USART_FLAG_TBE))
;
return ch;
}