DMA可以将数据在占用用CPU资源的同时进行数据传输
GD32DMA
DMA配置
我们将DMA配置分为几个部分
DMA的传输方向
从RAM到flash
从RAM到外设缓冲地址
从外设缓冲到RAM
从RAM到RAM
DMA传输数据最大数量
DMA传输起始地址
配置源地址是固定还是增长
DMA传输目的地址
配置目的地址是固定还是增长
如果目的是外设寄存器那么目的地址就不需要增长
如果目的地址是一个数组地址就需要增长
传输数据位数
8位,16为,32位
配置DMA数据通道优先级
DMA的作用
在单片机开发过程中我们会进行通讯,数据的转存等操作,在传输数据时我们如果不使用DMA传输数据就会导致在接受数据和发送数据 导致CPU长时间的等待造成CPU资源的浪费。
串口发送DMA例程
每过一秒串口发送一次
#define USART0_DATA_ADDRESS (uint32_t)&USART_DATA(USART0)
uint8_t welcome[100] = "hi,this is a example: RAM_TO_USART by DMA !\r\n";
__IO uint32_t transfer_flag = 0;
FlagStatus g_transfer_complete = RESET;
void nvic_config(void);
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
dma_single_data_parameter_struct dma_init_struct;
systick_config(); /* 设置时钟,168Mhz */
/* enable DMA1 clock */
rcu_periph_clock_enable(RCU_DMA1);
/* USART configure */
//gd_eval_com_init(EVAL_COM0);
drv_uart_init(115200);
/* initialize KEY */
/*configure DMA interrupt*/
nvic_config();
/* turn off LED2 */
printf("01\r\n");
/* initialize DMA1 channel7 */
dma_deinit(DMA1, DMA_CH7);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
dma_init_struct.memory0_addr = (uint32_t)welcome;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_init_struct.number = 100;//传输最数量
dma_init_struct.periph_addr = USART0_DATA_ADDRESS;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(DMA1, DMA_CH7, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA1, DMA_CH7);
dma_channel_subperipheral_select(DMA1, DMA_CH7, DMA_SUBPERI4);
/* enable DMA1 transfer complete interrupt */
dma_interrupt_enable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
/* enable DMA1 channel7 */
dma_channel_enable(DMA1, DMA_CH7);
/* USART DMA enable for transmission */
usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);
while(1)
{
delay_1ms(1000);
dma_channel_disable(DMA1, DMA_CH7);
/* USART DMA disable for transmission */
usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_DISABLE);
/* clear DMA HTF and FTF flag */
dma_flag_clear(DMA1, DMA_CH7,DMA_FLAG_FTF);
dma_flag_clear(DMA1, DMA_CH7,DMA_FLAG_HTF);
/* reconfigure transfer number for the next DMA transfer */
dma_transfer_number_config(DMA1, DMA_CH7, 100);//DMA发送使能
/* enable DMA1 channel7 */
dma_channel_enable(DMA1, DMA_CH7);
/* USART DMA enable for transmission */
usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);
}
}
/*!
\brief this function handles DMA1_Channel7_IRQHandler interrupt
\param[in] none
\param[out] none
\retval none
*/
void DMA1_Channel7_IRQHandler(void)
{
if(dma_interrupt_flag_get(DMA1, DMA_CH7, DMA_INT_FLAG_FTF)) {
/* toggle LED2 */
printf("DMA_INterrupt\r\n");
dma_interrupt_flag_clear(DMA1, DMA_CH7, DMA_INT_FLAG_FTF);//清除中断标志位
}
}
/*!
\brief configure DMA interrupt
\param[in] none
\param[out] none
\retval none
*/
void nvic_config(void)
{
nvic_irq_enable(DMA1_Channel7_IRQn, 0, 0);
}
DMA发送会发送设置的最大数据个数,比如设置了容量为100的数组,但是数组里只有50个数据,设置DMA最大发送个数为100,那么DMA会将100个数据全部发送出去
串口打印结果如下
68 69 2C 74 68 69 73 20 69 73 20 61 20 65 78 61 6D 70 6C 65 3A 20 52 41 4D 5F 54 4F 5F 55 53 41 52 54 20 62 79 20 44 4D 41 20 21 0D 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
串口接收DMA例程
#define USART0_DATA_ADDRESS ((uint32_t)&USART_DATA(USART0))
#define MAX_BUF_SIZE 512
static uint8_t s_rcv_data_buf[MAX_BUF_SIZE];
typedef struct
{
uint32_t uart_num;
rcu_periph_enum rcu_uart;
rcu_periph_enum rcu_gpio;
uint32_t gpio;
uint32_t af_num;
uint32_t tx_pin;
uint32_t rx_pin;
uint8_t irq;
uint32_t dma_num;
rcu_periph_enum rcu_dma;
dma_channel_enum dma_rx_ch;
dma_subperipheral_enum dma_sub_peri;
}UART_INFO_T;
static UART_INFO_T s_uart_info = {USART0, RCU_USART0, RCU_GPIOA, GPIOA, GPIO_AF_7, GPIO_PIN_9, GPIO_PIN_10, \
USART0_IRQn, DMA1, RCU_DMA1, DMA_CH5, DMA_SUBPERI4};
/**
***********************************************************
* @brief 串口引脚初始化
* @param
* @return
***********************************************************
*/
static void drv_uart_gpio_init(void)
{
rcu_periph_clock_enable(s_uart_info.rcu_gpio);
/* connect port to USARTx_Tx */
gpio_af_set(s_uart_info.gpio, s_uart_info.af_num, s_uart_info.tx_pin);
/* connect port to USARTx_Rx */
gpio_af_set(s_uart_info.gpio, s_uart_info.af_num, s_uart_info.rx_pin);
/* configure USART Tx as alternate function push-pull */
gpio_mode_set(s_uart_info.gpio, GPIO_MODE_AF, GPIO_PUPD_PULLUP, s_uart_info.tx_pin);
gpio_output_options_set(s_uart_info.gpio, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, s_uart_info.tx_pin);
/* configure USART Rx as alternate function push-pull */
gpio_mode_set(s_uart_info.gpio, GPIO_MODE_AF, GPIO_PUPD_PULLUP, s_uart_info.rx_pin);
gpio_output_options_set(s_uart_info.gpio, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, s_uart_info.rx_pin);
}
/**
***********************************************************
* @brief 串口配置初始化
* @param
* @return
***********************************************************
*/
static void dev_uart_config_init(uint32_t baudRate)
{
/* USART configure */
rcu_periph_clock_enable(s_uart_info.rcu_uart);
usart_deinit(s_uart_info.uart_num);
usart_baudrate_set(s_uart_info.uart_num,baudRate);
usart_receive_config(s_uart_info.uart_num, USART_RECEIVE_ENABLE);
usart_transmit_config(s_uart_info.uart_num, USART_TRANSMIT_ENABLE);
/*DMA USART configure */
usart_interrupt_enable(s_uart_info.uart_num, USART_INT_IDLE); //使能空闲中断
nvic_irq_enable(s_uart_info.irq, 0, 0);
usart_enable(s_uart_info.uart_num);
}
/**
***********************************************************
* @brief 串口DMA配置初始化
* @param
* @return
***********************************************************
*/
static void dev_uart_dma_config_init(void)
{
dma_single_data_parameter_struct dma_init_struct;
/* enable DMA rcu*/
rcu_periph_clock_enable(s_uart_info.rcu_dma);
dma_single_data_para_struct_init(&dma_init_struct);
dma_deinit(s_uart_info.dma_num, s_uart_info.dma_rx_ch);
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY; //配置传输方向
dma_init_struct.memory0_addr = (uint32_t)s_rcv_data_buf; //配置数据目的地址
dma_init_struct.periph_memory_width = DMA_MEMORY_WIDTH_8BIT; //配置目的数据位宽
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; //配置目的地址是固定还是增长
dma_init_struct.periph_addr = USART0_DATA_ADDRESS; //配置数据源地址
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; //配置源地址是固定还是增长
dma_init_struct.number = MAX_BUF_SIZE; //配置数据传输最大个数
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; //配置DMA数据通道优先级
dma_single_data_mode_init(s_uart_info.dma_num, s_uart_info.dma_rx_ch, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(s_uart_info.dma_num, s_uart_info.dma_rx_ch);
dma_channel_subperipheral_select(s_uart_info.dma_num, s_uart_info.dma_rx_ch, s_uart_info.dma_sub_peri);
dma_interrupt_enable(s_uart_info.dma_num, s_uart_info.dma_rx_ch, DMA_CHXCTL_FTFIE);
/* 使能UART接受数据使用DMA 使能DMA通道*/
usart_dma_receive_config(s_uart_info.uart_num, USART_RECEIVE_DMA_ENABLE);
dma_channel_enable(s_uart_info.dma_num, s_uart_info.dma_rx_ch);
}
/**
***********************************************************
* @brief 串口初始化
* @param
* @return
***********************************************************
*/
void drv_uart_init(uint32_t baudRate)
{
drv_uart_gpio_init();
dev_uart_config_init(baudRate);
dev_uart_dma_config_init();
}
/**
***********************************************************
* @brief 串口0中断服务函数
* @param
* @return
***********************************************************
*/
void USART0_IRQHandler(void)
{
uint32_t recv_len = 0;
if (usart_interrupt_flag_get(s_uart_info.uart_num, USART_INT_FLAG_IDLE) != RESET)
{
usart_interrupt_flag_clear(s_uart_info.uart_num, USART_INT_FLAG_IDLE);
usart_data_receive(s_uart_info.uart_num);
/* DMA */
dma_channel_disable(s_uart_info.dma_num, s_uart_info.dma_rx_ch);
recv_len = MAX_BUF_SIZE - dma_transfer_number_get(s_uart_info.dma_num, s_uart_info.dma_rx_ch);
printf("%.*s\n",recv_len,s_rcv_data_buf);
memset(s_rcv_data_buf, 0, MAX_BUF_SIZE);
dma_flag_clear(s_uart_info.dma_num, s_uart_info.dma_rx_ch, DMA_FLAG_FTF);
dma_transfer_number_config(s_uart_info.dma_num, s_uart_info.dma_rx_ch, MAX_BUF_SIZE);
dma_channel_enable(s_uart_info.dma_num, s_uart_info.dma_rx_ch);
}
}