找回密码
 立即注册

使用微信账号登录

只需一步,快速开始

CSR8675 使用串口UART收发功能

2020-5-25 11:33| 发布者: csdn| 查看: 2783| 评论: 0|来自: CSDN

摘要: CSR8675 使用串口 UART 收发功能 CSR8675 实现 UART 功能有两种方式,一种是托管连接,另一种是直接连接。 托管

CSR8675 使用串口 UART 收发功能

CSR8675 实现 UART 功能有两种方式,一种是托管连接,另一种是直接连接

托管连接:不直接操作 Stream,通过 VM 层创建 Source 和 Sink 来实现数据传输,由库进行处理,实现比较方便。
直接连接:直接操作 Stream ,源是一个存储区域,通过对内存进行操作实现数据传输,处理数据传输效率更高。

此处暂时先用 托管连接 的方式来介绍,后面有空再更新 直接连接

1、使用 RAW 传输

在工程属性下,将 Transport 属性改为 RAW。

在这里插入图片描述

2、打开调试宏

在 sink_debug.h 中加入调试宏

在这里插入图片描述

3、编辑串口代码,实现 loopback 功能

主要实现4个函数

  1. 消息处理函数
  2. 串口初始化函数
  3. 串口接收函数
  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 空间不大,才会导致接收的时候将数据截断。
因此,在使用异步串口过程中,需要根据实际情况,对接收的数据增加拼接的处理,同时加入自定义的协议,增加帧头、帧尾、数据长度、数据校验等信息,才能够保证接收到的内容是正确的。
在这里插入图片描述


持续更新–2019.10.31

5、解决 UART 接收时数据分段出来的现象

MESSAGE_MORE_DATA 此 id 附带的 message,本质也是一个流,只要达到接收 buffer 上有数据,就会发送这个 MessageID。
但是,只要不对这个 buffer 进行 Drop,下一次的 MESSAGE_MORE_DATA 依然会将原来数据数据积累起来,在下一次的时候发送。
buffer 大小为4K,如果不及时 Drop,则会内存溢出挂掉
因此,只需要对收到的数据进行长度的判断:
长度足够 --> 处理收到的内容,并将其 Drop。
长度不够 --> return,退出函数,等待下一次消息。

串口数据协议可以自定义,暂时按照这种方式,可传输的数据最大为 255 Byte。可以根据需要增加 数据长度CRC校验

void uart_data_stream_rx_data(Source src)下面对接收函数进行修改,思路是如果收到正确的数据,则处理掉,否则检查数据完整性,并丢掉无效数据;如果长度不够,则跳过此次接收。

void uart_data_stream_rx_data(Source src)
{
    uint16 length = 0;
    uint16 length_drop = 0;
    const uint8 *data = NULL;

recheck:    
    if(!(length = SourceBoundary(src)))
        return;
    data = SourceMap(src);
    PanicNull((void*)data);

    UART_DEBUG(("rx source size = %d \n",SourceSize(src)));  
    
    /* 数据不够最小一帧,跳出,下次再处理 */
    if(length < UART_DATA_MINLEN)
    {
        return;
    }
    /* 第一个位帧头,开始解析 */
    else if(data[0] == UART_DATA_HEAD)
    {
        switch(data[1])
        {
            case UART_HIBY_LINK_DATA:

                /* 收到的数据长度不够,跳过不处理 */
                if(data[2] > length-COMMAND_LENGTH )
                {
                    UART_DEBUG(("HiBy Link command,length = %d ,rx len = %d,NOT enough\n",data[2],length));  
                    return;
                }
                /* 收到足够的数据,处理 */
                else 
                {
                    length_drop = data[2] + COMMAND_LENGTH ;
                    UART_DEBUG(("HiBy Link command length = %d , length = %d\n",data[2],length_drop));  

                    /* 检查帧尾是否正确 */
                    if(data[(length_drop - 1)] == UART_DATA_END)
                    {
                        /* send to spp */
                        UART_DEBUG(("HiBy Link data send : %x ... %x \n",data[3],data[2+data[2]]));  
                    }

                    SourceDrop(src, length_drop);
                    /* 如果还有数据,则在执行一次 */
                    if(length > length_drop )
                    {
                        goto recheck;
                    }
                }

                break;

            case UART_NOTIFICATION:
                if(data[2] == 1 && data[4] == UART_DATA_END)
                {
                    UART_DEBUG(("Notification command = %x \n",data[3]));  

                    SourceDrop(src, UART_DATA_MINLEN);
                    if(length > UART_DATA_MINLEN)
                    {
                        goto recheck;
                    }
                }
    

                break;

            case UART_STATUS:
                if(data[2] == 1 && data[4] == UART_DATA_END)
                {
                    UART_DEBUG(("Status command = %x \n",data[3]));  

                    SourceDrop(src, UART_DATA_MINLEN);
                    if(length > UART_DATA_MINLEN)
                    {
                        goto recheck;
                    }
                }
                break;

            case UART_ASK:
                if(data[2] == 1 && data[4] == UART_DATA_END)
                {
                    UART_DEBUG(("Ask command = %x \n",data[3]));  

                    SourceDrop(src, UART_DATA_MINLEN);
                    if(length > UART_DATA_MINLEN)
                    {
                        goto recheck;
                    }
                }
                break;

            default:
                UART_DEBUG(("commmon error, drop min length.\n"));  
                SourceDrop(src, UART_DATA_MINLEN);
                if(length > UART_DATA_MINLEN)
                {
                    goto recheck;
                }
                break;
        }
    }
    /* 第一个字节不是帧头,可能数据有误,查找帧头,并丢弃之前数据 */
    else
    {
        uint16 err_data_len = 0;
        while(err_data_len < length)
        {
            /* 找到帧头 */
            if(data[err_data_len] == UART_DATA_HEAD)
            {
                /* 判断是否真的是帧头 ,通过检测上一个字节是否帧尾 */
                if(data[err_data_len - 1] == UART_DATA_END )
                {
                    /* 保证下一字节不溢出,并且为命令字节 ,然后去掉前面错误的数据,将正确的数据保留下来,留给下一次处理*/
                    if( (err_data_len + 1) < length  &&
                    (data[err_data_len + 1] == UART_HIBY_LINK_DATA ||
                    data[err_data_len + 1] == UART_NOTIFICATION ||
                    data[err_data_len + 1] == UART_STATUS ||
                    data[err_data_len + 1] == UART_ASK))
                    {
                        UART_DEBUG(("Drop error data,and has find the real data.\n"));  
                        SourceDrop(src, err_data_len);
                        goto recheck;
                    }
                }
            }
            err_data_len ++;
        }
        SourceDrop(src, length);
        UART_DEBUG(("Drop data, without real data,drop all data.\n"));  
        return;
    }
}

来源:https://blog.csdn.net/qq_29225913/article/details/102775806
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

路过

雷人

握手

鲜花

鸡蛋

相关阅读

最新评论

小黑屋|手机版|我爱蓝牙网 - 52Bluetooth

GMT+8, 2024-4-23 14:10 , Processed in 0.090537 second(s), 18 queries , Gzip On, MemCached On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

返回顶部