K210_kendryte IDE_UART_DMA

K210_kendryte IDE_UART_DMA

本实验基于kendryte standalone SDK实现K210的C语言裸机开发。使用DMA的方式进行串口的发送与接收。下面将采用DMA与DMA中断两种方式实现功能。

一、实验环境

1、软件环境:

macOS 11.4
kendryte IDE
Kendryte Standalone SDK

2、硬件环境

SIPEED M1 AI MODULE

二、功能构思

实现简单的串口输出字符串信息。使用DMA实现串口简单指令接收,若接收为字符1(0x31)则LED点亮,若接收字符为0(0x30)则LED熄灭。

三、代码实现

1、FPIOA引脚绑定

详情可参考我的其他博客链接: link.

2、初始化外设

需要初始化的外设有GPIO、UART、(中断初始化)这几部分。由于比较基础这里就不再赘述。
详情可参考我的其他博客链接: link.

3、串口功能实现

(1)发送功能

在使用DMA串口发送时可直接使用SDK中提供的函数。DMA的优势在于可减少CPU读写操作的时间。使用DMA控制器直接将数据从内存传输到串口外设,中途不经过CPU,在需要大量数据传输时有较大的优势。函数具体如下。

函数原型
void uart_send_data_dma(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel, const uint8_t *buffer, size_t buf_len)
参数
参数名称描述输入输出
uart_channelUART 编号输入
dmac_channelDMA通道输入
buffer待发送数据输入
buf_len待发送数据的长度输入

DMA通道:

成员名称描述
DMAC_CHANNEL0DMA通道0
DMAC_CHANNEL1DMA通道1
DMAC_CHANNEL2DMA通道2
DMAC_CHANNEL3DMA通道3
DMAC_CHANNEL4DMA通道4
DMAC_CHANNEL5DMA通道5

发送部分代码:

void uart_send(char *tx_buffer) {
  uart_send_data_dma(UART_DEVICE_1, DMAC_CHANNEL0, (uint8_t *)tx_buffer,strlen(tx_buffer));
}

(2)非中断接收功能

在SDK中同样提供了使用DMA实现串口数据接收的函数。在大数据块传输时使用DMA进行接收可减轻CPU的负担。传输任务完全交给DMA控制器,当CPU需要处理数据时可直接访问内存地址即可访问数据。具体函数如下。

函数原型
void uart_receive_data_dma(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel, uint8_t *buffer, size_t buf_len)
参数
参数名称描述输入输出
uart_channelUART 编号输入
dmac_channelDMA通道输入
buffer接收数据输出
buf_len接收数据的长度输入
(3)中断接收功能

在SDK中提供了DMA中断方式的发送与接收函数。这里使用接收函数为例。DMA的存在使大数据传输时摆脱了CPU的干预,但是非中断的DMA接收方式依旧要使用CPU频繁的查询DMA传输的过程这样效率较低。中断的DMA接收方式最大程度的降低了CPU的依赖,数据接收时对于CPU是非阻塞的,数据接收完成时再响应中断。函数如下。注意此函数仅能中断一次。函数中一些中断相关参数可参考我的其他博客链接: link.

函数原型
void uart_receive_data_dma_irq(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel,uint8_t *buffer, size_t buf_len, plic_irq_callback_t uart_callback,void *ctx, uint32_t priority)
参数
参数名称描述输入输出
uart_channelUART 编号输入
dmac_channelDMA通道输入
buffer接收数据输出
buf_len接收数据的长度输入
uart_callbackDMA中断回调输入
ctx中断函数参数输入
priority中断优先级输入

中断回调子程序:

int uart1_receive_dma_callback(void *ctx) {
  switch (rx_buffer) {
    case '1':
      gpio_set_pin(0, GPIO_PV_LOW);
      uart_send(&rx_buffer);
      uart_send("Light is open!\n");
      break;
    case '0':
      gpio_set_pin(0, GPIO_PV_HIGH);
      uart_send(&rx_buffer);
      uart_send("Light is off!\n");
      break;
    default:
      break;
  }
  uart_receive_data_dma_irq(UART_DEVICE_1,DMAC_CHANNEL1,&rx_buffer,1,uart1_receive_dma_callback, NULL,1);  // 注册DMA接收中断回调函数 仅能完成一次中断!
}

4、整体代码

(1)非中断DMA方式
#include <gpio.h>
#include <sleep.h>
#include <stdio.h>
#include <string.h>
#include <uart.h>

char *string = {"hello world!\n"};
char rx_buffer;
void GPIO_init(void);
void UART_init(void);
void uart_send(char *tx_buffer);
int main(void) {
  GPIO_init();
  UART_init();
  msleep(5000);
  uart_send(string);
  while (1) {
    uart_receive_data_dma(UART_DEVICE_1, DMAC_CHANNEL1, (uint8_t *)&rx_buffer,
                          1);
    switch (rx_buffer) {
      case '1':
        gpio_set_pin(0, GPIO_PV_LOW);
        uart_send(&rx_buffer);
        break;
      case '0':
        gpio_set_pin(0, GPIO_PV_HIGH);
        uart_send(&rx_buffer);
        break;
      default:
        break;
    }
  }
}

void GPIO_init(void) {
  gpio_init();  // enable the gpio clock
  gpio_set_drive_mode(0, GPIO_DM_OUTPUT);
  gpio_set_drive_mode(1, GPIO_DM_OUTPUT);
  gpio_set_drive_mode(2, GPIO_DM_OUTPUT);
  gpio_set_pin(0, GPIO_PV_HIGH);
  gpio_set_pin(1, GPIO_PV_HIGH);
  gpio_set_pin(2, GPIO_PV_HIGH);
}

void UART_init(void) {
  uart_init(UART_DEVICE_1);  // enable the uart device clock
  uart_set_work_mode(UART_DEVICE_1, UART_NORMAL);
  uart_configure(UART_DEVICE_1, 115200, UART_BITWIDTH_8BIT, UART_STOP_1,
                 UART_PARITY_NONE);
}

void uart_send(char *tx_buffer) {
  uart_send_data_dma(UART_DEVICE_1, DMAC_CHANNEL0, (uint8_t *)tx_buffer,
                     strlen(tx_buffer));
  // uart_send_data(UART_DEVICE_1, tx_buffer, strlen(tx_buffer));
  //*tx_buffer = '1';
  // uart_send_data(UART_DEVICE_1, tx_buffer, strlen(tx_buffer));
}

(2)中断DMA方式
#include <gpio.h>
#include <plic.h>
#include <sleep.h>
#include <stdio.h>
#include <string.h>
#include <sysctl.h>
#include <uart.h>

char *string = {"hello world!\n"};
char rx_buffer;
void GPIO_init(void);
void UART_init(void);
void uart_send(char *tx_buffer);
int uart1_receive_dma_callback(void *ctx);
int main(void) {
  plic_init();  // Enable PLIC external interrupt
  GPIO_init();
  UART_init();
  sysctl_enable_irq();  // Enable interrupt
  msleep(5000);
  uart_send(string);
  while (1) {
    gpio_set_pin(1, GPIO_PV_LOW);
    msleep(1000);
    gpio_set_pin(1, GPIO_PV_HIGH);
    msleep(1000);
  }
}

void GPIO_init(void) {
  gpio_init();  // enable the gpio clock
  gpio_set_drive_mode(0, GPIO_DM_OUTPUT);
  gpio_set_drive_mode(1, GPIO_DM_OUTPUT);
  gpio_set_drive_mode(2, GPIO_DM_OUTPUT);
  gpio_set_pin(0, GPIO_PV_HIGH);
  gpio_set_pin(1, GPIO_PV_HIGH);
  gpio_set_pin(2, GPIO_PV_HIGH);
}

void UART_init(void) {
  uart_init(UART_DEVICE_1);  // enable the uart device clock
  uart_set_work_mode(UART_DEVICE_1, UART_NORMAL);
  uart_configure(UART_DEVICE_1,115200,UART_BITWIDTH_8BIT,UART_STOP_1,UART_PARITY_NONE);
  uart_receive_data_dma_irq(UART_DEVICE_1,DMAC_CHANNEL1,&rx_buffer,1,uart1_receive_dma_callback, NULL,1);  // 注册DMA接收中断回调函数 仅能完成一次中断!
  uart_set_receive_trigger(UART_DEVICE_1, UART_RECEIVE_FIFO_1);
}

void uart_send(char *tx_buffer) {
  uart_send_data_dma(UART_DEVICE_1,DMAC_CHANNEL0(uint8_t*)tx_buffer,strlen(tx_buffer));
  // uart_send_data(UART_DEVICE_1, tx_buffer, strlen(tx_buffer));
  //*tx_buffer = '1';
  // uart_send_data(UART_DEVICE_1, tx_buffer, strlen(tx_buffer));
}

int uart1_receive_dma_callback(void *ctx) {
  switch (rx_buffer) {
    case '1':
      gpio_set_pin(0, GPIO_PV_LOW);
      uart_send(&rx_buffer);
      uart_send("Light is open!\n");
      break;
    case '0':
      gpio_set_pin(0, GPIO_PV_HIGH);
      uart_send(&rx_buffer);
      uart_send("Light is off!\n");
      break;
    default:
      break;
  }
  uart_receive_data_dma_irq(UART_DEVICE_1,DMAC_CHANNEL1,&rx_buffer,1,uart1_receive_dma_callback, NULL,1);  // 注册DMA接收中断回调函数 仅能完成一次中断!
}

四、实验效果

1、非中断程序效果

程序运行后5s后输出hello world!说明DMA发送成功。在上位机输入1发送,板子上的LED点亮,并且回传1。上位机输入0发送,板子上的LED熄灭,并且回传0。

2、中断程序效果

程序运行5s后输出hello world!说明DMA发送成功。板子上的LED1开始反复闪烁。在上位机输入1发送,板子上的LED0点亮,并且回传1,以及Light is open!。上位机输入0发送,板子上的LED0熄灭,并且回传0,以及Light is off!。串口的收发不会影响LED1的闪烁。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值