DMA的使用方式

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);            
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值