TLSR8258——串口DMA通信功能
官方串口简介摘要:
官方TLSR8258串口相关说明
TLSR8258F1KET48A嵌入UART(通用异步接收机/发射机),通过UART TX和RX接口实现全双工传输和接收。TX和RX接口均为4层FIFO(先进先出)接口。
通过RTS和CTS支持硬件流控制。
UART模块还支持ISO7816协议,以实现与ISO/IEC 7816集成电路卡,特别是智能卡的通信。在这种模式下,通过共享的7816_TRX接口支持半双工通信(发送或接收)。
UART支持DMA模式,可以大大简化数据传输和接收过程。此外,DMA和MCU之间的并行性可以提高程序的效率。要使用DMA模式,除了相关配置外,发送的数据结构必须符合以下特定要求:
定义的发送或接收缓冲区需要4字节对齐,前4个字节是传输的数据包的长度。
DMA模式下Tx和Rx缓冲区格式的框图如下:
Len[0] | Len[1] | Len[2] | Len[3] | DATA[0] | DATA[1] | DATA[2] | … |
---|
串口TX和RX引脚表
TX | RX |
---|---|
PA2 | PA0 |
PB1 | PB0 |
PC2 | PC3 |
PD0 | PC5 |
PD3 | PB7 |
PD7 | PD6 |
本工程使用的引脚是RX->B0和TX->B1。
注意:
串口是DMA方式接收和发送,当连续发送多包数据时接收缓冲区是将多包数据一块接收,所以在解析接收数据时应对多包数据进行拆包处理后再进行逐一数据包发送。
串口函数 user_uart.c
/*
* user_uart.c
*
* Created on: 2023-10-13
* Author: ZJ
*/
#include "user_uart.h"
__attribute__((aligned(4))) unsigned char UART_RX_Buff[RX_Buff_Len] = {0};
__attribute__((aligned(4))) unsigned char UART_TX_Buff[RX_Buff_Len] = {0};
SUart_data_struct Uart_data;
//串口接收数据缓冲区
fifo_struct UART_RX_FIFO = {0};
//串口临时缓存区
frame_data_struct Uart_Rx_Data_Temp;
/**
* @brief 配置串口和射频结构体参数
*/
void Config_Uart_RF_parama(void)
{
memset(Uart_data.Rx_data,0,UART_DATA_LEN);
memset(Uart_data.Tx_Data,0,UART_DATA_LEN);
memset(Uart_data.buff,0,UART_DATA_LEN);
}
/**
* @brief 串口初始化
*/
void Uart_Init(void)
{
//注意:在进行任何其他uart初始化之前,必须先设置dma addr!
uart_recbuff_init( (unsigned char *)UART_RX_Buff, sizeof(UART_RX_Buff));
//设置 uart tx/rx pin
uart_gpio_set(UART_TX_PIN, UART_RX_PIN);
//每次使用UART时,最好都先调用复位函数,可以避免之前使用UART的操作对本次使用产生影响。
uart_reset();
//设置波特率
uart_init_baudrate(115200,CLOCK_SYS_CLOCK_HZ,PARITY_NONE, STOP_BIT_ONE);
//开启TX RX的DMA功能
uart_dma_enable(1, 1);
// uart_rx use dma_rx irq
irq_enable_type(FLD_IRQ_DMA_EN);
//uart Rx dma irq enable
dma_chn_irq_enable(FLD_DMA_CHN_UART_RX, 1);
//uart Tx dma irq enable
uart_mask_tx_done_irq_enable();
// 打开uart_errormask,当停止位错误或奇偶校验错误时,它将进入errorinterrupt。
uart_mask_error_irq_enable();
// uart_tx use uart_txdone irq
irq_enable_type(FLD_IRQ_UART_EN);
irq_enable();
}
/*
* @brief:将串口DMA缓冲区中数据搬移
* */
fifo_status_enum fifo_push(uint8_t *uart_rx_buff,fifo_struct *fifo_ptr)
{
if (fifo_ptr->buff_size >= FIFO_SIZE)
{
/* 缓存帧已满 */
return FIFO_FAILURE;
}
memcpy((void *)fifo_ptr->frame_repo[fifo_ptr->write_index].data,uart_rx_buff,uart_rx_buff[0]+4);
fifo_ptr->frame_repo[fifo_ptr->write_index].length = uart_rx_buff[0]+4;
/* 缓存帧数量增加1 */
fifo_ptr->buff_size++;
/* 缓存写入索引向前加1 */
fifo_ptr->write_index = (fifo_ptr->write_index + 1) % FIFO_SIZE;
return FIFO_SUCCESS;
}
/*
* @brief:将串口DMA缓冲区中数据提取使用
* */
fifo_status_enum fifo_pop(frame_data_struct *frame_pop, fifo_struct *fifo_ptr)
{
if (fifo_ptr->buff_size == 0)
{
/* 没有缓存的帧 */
return FIFO_FAILURE;
}
frame_pop->length = fifo_ptr->frame_repo[fifo_ptr->read_index].length;
memcpy((void *)frame_pop->data, (void *)fifo_ptr->frame_repo[fifo_ptr->read_index].data, fifo_ptr->frame_repo[fifo_ptr->read_index].length);
/* 缓存帧数量减少1 */
fifo_ptr->buff_size--;
/* 更新读索引 */
fifo_ptr->read_index = (fifo_ptr->read_index + 1) % FIFO_SIZE;
return FIFO_SUCCESS;
}
/*
* @brief:串口发送数据
* */
void UARTXSend(PUart_data_struct Uart_data,uint8_t lenth)
{
//TX DMA发送数据长度
UART_TX_Buff[0] = lenth;
//TX 数据搬移
memcpy(&UART_TX_Buff[4],&Uart_data->Tx_Data[0],lenth);
uart_send_dma((unsigned char *)UART_TX_Buff);
}
/**
* @brief 串口数据处理
* 将接收到的数据发送出来
*/
void Uart_Conduct(PUart_data_struct Uart_data)
{
uint8_t i;
//判断串口DMA缓冲区是否有数据缓存
if(FIFO_SUCCESS == fifo_pop(&Uart_Rx_Data_Temp, &UART_RX_FIFO))
{
//拆分串口DMA接收数据包,判断缓冲区有几包数据帧
if((Uart_Rx_Data_Temp.data[6]+(Uart_Rx_Data_Temp.data[7]<<8))+4 == Uart_Rx_Data_Temp.length-4)
{
memcpy(&Uart_data->Tx_Data[0],&Uart_Rx_Data_Temp.data[4],Uart_Rx_Data_Temp.length-4);
UARTXSend(Uart_data,Uart_Rx_Data_Temp.length-4);
}
else
{
//多包数据拆分处理
for(i = 4;i <= Uart_Rx_Data_Temp.length;i++)
{
if(Uart_Rx_Data_Temp.data[i] == 0xCD && Uart_Rx_Data_Temp.data[i+1] == 0x00)
{
memcpy(&Uart_data->Tx_Data[0],&Uart_Rx_Data_Temp.data[i],(Uart_Rx_Data_Temp.data[i+2]+(Uart_Rx_Data_Temp.data[i+3]<<8))+4);
UARTXSend(Uart_data,(Uart_Rx_Data_Temp.data[i+2]+(Uart_Rx_Data_Temp.data[i+3]<<8))+4);
sleep_ms(200);
}
}
}
}
else
{
printf("串口未接收到数据......");
sleep_ms(1000);
}
}
串口函数 user_uart.h
/*
* user_uart.h
*
* Created on: 2023-10-13
* Author: zhangjian
*/
#ifndef USER_UART_H_
#define USER_UART_H_
#include "app_config.h"
#include "types.h"
/************************ 宏定义声明*********************************/
#define UART_DATA_LEN 150 //串口通信长度
#define UART_TX_PIN UART_TX_PB1
#define UART_RX_PIN UART_RX_PB0
#define RX_Buff_Len 512
#define TX_Buff_Len 512
#define FIFO_SIZE 10
#define FRAME_SIZE 512
/************************ 结构体 声明*********************************/
typedef struct Uart //读写器串口数据结构体
{
uint8_t Rx_data[UART_DATA_LEN]; //串口接收结构体
uint8_t Tx_Data[UART_DATA_LEN]; //串口发送结构体
uint8_t lenth; //帧长度
uint8_t buff[UART_DATA_LEN];
} *PUart_data_struct,SUart_data_struct;
typedef struct
{
uint8_t data[FRAME_SIZE];
volatile uint16_t length;
}frame_data_struct;
typedef struct
{
volatile uint8_t write_index;
volatile uint8_t read_index;
volatile uint8_t buff_size;
frame_data_struct frame_repo[FIFO_SIZE];
}fifo_struct;
/************************ 枚举 声明*********************************/
typedef enum
{
FIFO_SUCCESS = 0,
FIFO_FAILURE
}fifo_status_enum;
/************************ 重定义声明*********************************/
extern SUart_data_struct Uart_data;
extern unsigned char UART_RX_Buff[RX_Buff_Len];
extern unsigned char UART_TX_Buff[RX_Buff_Len];
extern fifo_struct UART_RX_FIFO;
/************************ 函数声明**********************************/
fifo_status_enum fifo_push(uint8_t *uart_rx_buff,fifo_struct *fifo_ptr);
fifo_status_enum fifo_pop(frame_data_struct *frame_pop, fifo_struct *fifo_ptr);
void Config_Uart_RF_parama(void);
void Uart_Init(void);
void Uart_Conduct(PUart_data_struct Uart_data);
#endif /* USER_UART_H_ */
主函数 main.c
#include "app_config.h"
#include "calibration.h"
#include "user_uart.h"
_attribute_ram_code_sec_noinline_ void irq_handler(void)
{
if(reg_uart_status1 & FLD_UART_TX_DONE)
{
//gpio_toggle(LED2);
uart_clr_tx_done();
}
if(dma_chn_irq_status_get() & FLD_DMA_CHN_UART_RX)
{
//uart_send_dma((unsigned char *)RX_Buff);
//缓存搬移
fifo_push((unsigned char *)UART_RX_Buff,&UART_RX_FIFO);
dma_chn_irq_status_clr(FLD_DMA_CHN_UART_RX);
}
if(uart_is_parity_error())//when stop bit error or parity error.
{
uart_clear_parity_error();
}
}
/**
* @brief This is main function
* @param[in] none
* @return none
*/
int main (void) {
cpu_wakeup_init();
//Note: This function must be called, otherwise an abnormal situation may occur.
//Called immediately after cpu_wakeup_init, set in other positions, some calibration values may not take effect.
user_read_flash_value_calib();
gpio_init(0);
clock_init(SYS_CLK);
printf("测试开始\r\n");
Config_Uart_RF_parama();
Uart_Init();
while (1)
{
Uart_Conduct(&Uart_data);
}
return 0;
}