五、USART0的printf实现和DMA实现
[复制链接]
本帖最后由 sonicfirr 于 2022-2-9 21:09 编辑
在下的GD32L233C-START专题测评:
一、开箱评测 https://bbs.eeworld.com.cn/thread-1192788-1-1.html
二、GD32L233C-START环境搭建https://bbs.eeworld.com.cn/thread-1193053-1-1.html
三、点灯案例与扩展https://bbs.eeworld.com.cn/thread-1193183-1-1.html
四、Demo工程的分析https://bbs.eeworld.com.cn/thread-1193279-1-1.html
昨天晚上搞了一下Demo,后来睡着了,今晚来发一篇
1、备份一个工程
本人在做教学工作时,习惯将一门课程的所有案例写在一个工程中,这样用着方便(也是给学生大爷们服务到位吧),这个习惯带到这里。
另外,再次提到GD官网的下载链接:http://www.gd32mcu.com/cn/download/0?kw=GD32L2,这里提供的固件库里面包含所有接口的Demo。
2、案例代码
1)先建立一个系统头文件,把其它头文件连接和测试函数声明放在这里。
#ifndef _AITA_SYS_H
#define _AITA_SYS_H
#include "gd32l23x.h"
#include "systick.h"
#include "gd32l233c_start.h"
#include <stdio.h>
#include <string.h>
extern uint8_t rx_buffer[256];
extern uint32_t nbr_data_to_read;
extern volatile uint32_t rx_counter;
#define AITA_EASYSHIELD_EN 1 //开启EasySheild扩展板,即增加多个LED的驱动
void aita_InitBSP(void);
void aita_InitLED(void);
void aita_InitUSART(void);
void aita_Flash(void);
void aita_RGB(void);
void aita_TestUSART(void);
void aita_InitDMAForU0(void);
#endif
2)main.c的代码——这里分成几段来展示,从上到下是完整的。点灯的代码之前测评帖子中有,这里就不在写出了。
//by author. DMA测试的定义和printf重定向
#include "aita_sys.h"
//DMA USART0 发送和接收寄存器地址
#define USART0_RDATA_ADDRESS (&USART_RDATA(USART0))
#define USART0_TDATA_ADDRESS (&USART_TDATA(USART0))
#define ARRAYNUM(arr_nanme) (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))
//DMA USART0 测试用到的内存缓存
__IO FlagStatus g_transfer_complete = RESET;
uint8_t rxbuffer[10];
uint8_t txbuffer[] = "\n\rUSART DMA interrupt receive and transmit example, please input 10 bytes:\n\r";
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart_data_transmit(EVAL_COM, (uint8_t) ch);
while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
return ch;
}
//by author. main函数之前做的功能写成了三个测试函数,aita_TestUSART()是串口收发的测试(非DMA方式)
//现在启用的是DMA收发的过程
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void) {
aita_InitBSP();
//aita_Flash();
//aita_RGB();
//aita_TestUSART();
/* waiting for the transfer to complete*/
while(RESET == g_transfer_complete) {
}
g_transfer_complete = RESET;
/* waiting for the transfer to complete*/
while(RESET == g_transfer_complete) {
}
printf("\n\r%s\n\r", rxbuffer);
while(1) {
}
}
//by author. 初始化部分
void aita_InitBSP(void) {
systick_config();
aita_InitLED();
aita_InitUSART();
aita_InitDMAForU0();
}
//by author. GPIO控制LED初始化和串口初始化(目前开启DMA,所以注释了后两句)
//串口初始化代码gd_eval_com_init(),Demo中写在了gd32l233c_start.c
void aita_InitLED(void) {
gd_eval_led_init(LED1);
gd_eval_led_init(LED2);
gd_eval_led_init(LED3);
gd_eval_led_init(LED4);
#if AITA_EASYSHIELD_EN
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_12 | GPIO_PIN_15 | GPIO_PIN_0);
gpio_output_options_set(
GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_12 | GPIO_PIN_15 | GPIO_PIN_0);
gpio_bit_reset(GPIOB, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_12 | GPIO_PIN_15 | GPIO_PIN_0);
#endif
}
void aita_InitUSART(void) {
/* configure EVAL_COM */
gd_eval_com_init(EVAL_COM);
/* USART interrupt configuration */
//nvic_irq_enable(USART0_IRQn, 0);
/* enable EVAL_COM receive interrupt */
//usart_interrupt_enable(EVAL_COM, USART_INT_RBNE);
}
//by author. 从固件库Demo移植过来,Demo中使用了U1,这里改成板子上的U0
//另外,这里本人分析L233提供了一个DMA矩阵,包含7个通道,应该是外设可以映射到任意通道来使用
//原Demo U1口使用了DMA_CH0和DMA_CH1,我改成U0口也可以使用
void aita_InitDMAForU0(void) {
dma_parameter_struct dma_init_struct;
/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA);
/*configure DMA interrupt*/
nvic_irq_enable(DMA_Channel0_IRQn, 0);
nvic_irq_enable(DMA_Channel1_IRQn, 0);
/* initialize DMA channel 0 */
dma_deinit(DMA_CH0);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_USART0_TX;
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr = (uint32_t)txbuffer;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = ARRAYNUM(txbuffer);
dma_init_struct.periph_addr = (uint32_t)USART0_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_CH0, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA_CH0);
dma_memory_to_memory_disable(DMA_CH0);
/* disable the DMAMUX_MUXCH0 synchronization mode */
dmamux_synchronization_disable(DMAMUX_MUXCH0);
/* USART DMA enable for transmission and reception */
usart_dma_transmit_config(USART0, USART_DENT_ENABLE);
/* enable DMA channel 0 transfer complete interrupt */
dma_interrupt_enable(DMA_CH0, DMA_INT_FTF);
/* enable DMA channel 0 */
dma_channel_enable(DMA_CH0);
/* initialize DMA channel 1 */
dma_deinit(DMA_CH1);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_USART0_RX;
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)rxbuffer;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = ARRAYNUM(rxbuffer);
dma_init_struct.periph_addr = (uint32_t)USART0_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(USART0, USART_DENR_ENABLE);
/* enable DMA channel 1 transfer complete interrupt */
dma_interrupt_enable(DMA_CH1, DMA_INT_FTF);
/* enable DMA channel 1 */
dma_channel_enable(DMA_CH1);
}
//by author. 非DMA方式的U0收发测试,开启了接收中断
void aita_TestUSART(void) {
uint16_t i=0;
while(1) {
if(rx_counter > 0) {
printf("get msg: \r\n%s\r\n", rx_buffer);
rx_counter = 0;
memset(rx_buffer, 0, 256);
}
if(i++ >= 500) {
i = 0;
printf("Hello from GD32L233C-START!\r\n");
}
delay_1ms(10);
}
}
3)中断函数——gd32l23x_it.c
//by author. 以下是文件修改和新增部分
//原U0接收中断,是接收固定数量字节,然后就关闭接收中断(注释掉部分)
//DMA中断暂时从固件库案例粘贴过来,没有做修改,测试功能也是案例中的发送一句话,并接收10个字节
#define BUFFER_SIZE 256
uint8_t rx_buffer[BUFFER_SIZE];
uint32_t nbr_data_to_read = BUFFER_SIZE;
volatile uint32_t rx_counter = 0;
/*!
\brief this function handles USART0 exception
\param[in] none
\param[out] none
\retval none
*/
void USART0_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) {
/* read one byte from the receive data register */
rx_buffer[rx_counter++] = (uint8_t)usart_data_receive(USART0);
// if(rx_counter >= nbr_data_to_read) {
// /* disable the USART0 receive interrupt */
// usart_interrupt_disable(USART0, USART_INT_RBNE);
// }
}
}
extern FlagStatus g_transfer_complete;
/*!
\brief this function handles DMA_Channel0_IRQHandler interrupt
\param[in] none
\param[out] none
\retval none
*/
void DMA_Channel0_IRQHandler(void)
{
if(RESET != dma_interrupt_flag_get(DMA_CH0, DMA_INT_FLAG_FTF)){
dma_interrupt_flag_clear(DMA_CH0, DMA_INT_FLAG_G);
g_transfer_complete = SET;
}
}
/*!
\brief this function handles DMA_Channel1_IRQHandler interrupt
\param[in] none
\param[out] none
\retval none
*/
void DMA_Channel1_IRQHandler(void)
{
if(RESET != dma_interrupt_flag_get(DMA_CH1, DMA_INT_FLAG_FTF)){
dma_interrupt_flag_clear(DMA_CH1, DMA_INT_FLAG_G);
g_transfer_complete = SET;
}
}
3、测试效果
有需要的朋友可以下载我的案例,放在“..\GD32L233C-START\GD32L233C_START_Demo_Suites\Projects”。
|