CSR8675 使用串口 UART 收发功能
CSR8675 实现 UART 功能有两种方式,一种是托管连接,另一种是直接连接。
托管连接:不直接操作 Stream,通过 VM 层创建 Source 和 Sink 来实现数据传输,由库进行处理,实现比较方便。
直接连接:直接操作 Stream ,源是一个存储区域,通过对内存进行操作实现数据传输,处理数据传输效率更高。
此处暂时先用 托管连接 的方式来介绍,后面有空再更新 直接连接。
1、使用 RAW 传输
在工程属性下,将 Transport 属性改为 RAW。
2、打开调试宏
在 sink_debug.h 中加入调试宏
3、编辑串口代码,实现 loopback 功能
主要实现4个函数
- 消息处理函数
- 串口初始化函数
- 串口接收函数
- 串口发送函数
<sink_uart.h>
#ifndef __UART_H_
#define __UART_H_
void UARTStreamMessageHandler (Task pTask, MessageId pId, Message pMessage);
void uart_data_stream_rx_data(Source src);
void uart_data_stream_tx_data(const uint8 *data, uint16 length);
void uart_data_stream_init(void);
#endif /* __UART_H_ */
<sink_uart.c>
#include <stream.h>
#include <sink.h>
#include <source.h>
#include <string.h>
#include <panic.h>
#include <message.h>
#include <app/uart/uart_if.h>
#include <stdio.h>
#include <string.h>
#include "uart.h"
#include "sink_debug.h"
#ifdef DEBUG_UART
#define UART_DEBUG(x) DEBUG(x)
#else
#define UART_DEBUG(x)
#endif
typedef struct
{
TaskData task;
Sink uart_sink;
Source uart_source;
}UARTStreamTaskData;
UARTStreamTaskData theUARTStreamTask;
void uart_data_stream_init(void)
{
/* Assign task message handler */
theUARTStreamTask.task.handler = UARTStreamMessageHandler;
/* Configure uart settings */
StreamUartConfigure(VM_UART_RATE_38K4, VM_UART_STOP_ONE, VM_UART_PARITY_NONE);
/* Get the sink for the uart */
theUARTStreamTask.uart_sink = StreamUartSink();
if(theUARTStreamTask.uart_sink != 0)
PanicNull(theUARTStreamTask.uart_sink);
/* Get the source for the uart */
theUARTStreamTask.uart_source = StreamUartSource();
if(theUARTStreamTask.uart_source != 0)
PanicNull(theUARTStreamTask.uart_source);
/* Register uart source with task */
MessageSinkTask(StreamSinkFromSource(theUARTStreamTask.uart_source),&theUARTStreamTask.task);
}
void uart_data_stream_tx_data(const uint8 *data, uint16 length)
{
uint16 offset = 0;
uint8 *dest = NULL;
/* Claim space in the sink, getting the offset to it */
offset = SinkClaim(theUARTStreamTask.uart_sink, length);
if(offset == 0xFFFF) Panic();
/* Map the sink into memory space */
dest = SinkMap(theUARTStreamTask.uart_sink);
PanicNull(dest);
/* Copy data into the claimed space */
memcpy(dest+offset, data, length);
/* Flush the data out to the uart */
PanicZero(SinkFlush(theUARTStreamTask.uart_sink, length));
}
void uart_data_stream_rx_data(Source src)
{
uint16 length = 0;
const uint8 *data = NULL;
/* Get the number of bytes in the specified source before the next packet boundary */
if(!(length = SourceBoundary(src)))
return;
/* Maps the specified source into the address map */
data = SourceMap(src);
PanicNull((void*)data);
/* Transmit the received data */
uart_data_stream_tx_data(data, length);
UART_DEBUG(("UART: Rx: length = %d\n",length));
/* Discards the specified amount of bytes from the front of the specified source */
SourceDrop(src, length);
}
void UARTStreamMessageHandler (Task pTask, MessageId pId, Message pMessage)
{
switch (pId)
{
case MESSAGE_MORE_DATA:
uart_data_stream_rx_data(((MessageMoreData *)pMessage)->source);
break;
default:
break;
}
}
4、调用函数,实现 loopback
修改PSKey
01EA UART_BITRATE 改为38400
01C2 UART_CONFIG_USR 改为 0880
在 main 函数中,MessageLoop()之前,调用串口初始化函数。
按F5下载到开发板上。
接上串口,打开串口工具,串口号在电脑的设备管理器查看,波特率设置为38400,数据位为8,停止位为1,奇偶校验位为none。
但是存在一个小问题,发了10个数据,在接收函数中打印一下数据长度,会发现进入了2次接收函数,第一次接收了1个字节,第二次将剩余的字节全部接收。
操作多几次验证,发现一个规律,就是第一次总是接收1个字节,然后剩下的数据接收的长度会随机改变,原因可能是底层库通过流的方式实现,此处用的是异步串口,没有硬件流控,而且CSR8675本身的串口 buffer 空间不大,才会导致接收的时候将数据截断。
因此,在使用异步串口过程中,需要根据实际情况,对接收的数据增加拼接的处理,同时加入自定义的协议,增加帧头、帧尾、数据长度、数据校验等信息,才能够保证接收到的内容是正确的。
来源:https://blog.csdn.net/qq_29225913/article/details/102775806