CH592 蓝牙透传模块

设备架构

img

串口透传协议说明

模块通过串口和用户MCU相连,建立用户MCU 和 BLE 设备之间的双向通讯。
用户可以通过串口,使用指定的AT指令对串口波特率、BLE连接间隔,以及不同的发包间隔,模块将会有不同的数据吞吐能力。
串口默认配置为 115200bps。
模块的串口Rx一次最大可输入3K字节。
模块会根据蓝牙协议协商情况进行分包或者发送完整包。
BLE设备之间的通信,必须在对应的服务通道进行。当模块收到主机或从机发来的无线包后,会先从INT口输出低电平信号再从模块串口Tx端输出数据。
以“TTM:”开头且以“\r\n\0”结尾的字符串会被当成AT指令进行解析并执行,并返回执行结果(“TTM:OK\r\n\0”或者 “TTM:REP\r\n\0”等).不符合AT 指令规则的串口数据包,将被视为透传数据。

透传数据通道

透传数据通道【服务 UUID: 0xFFF0】

特征值UUID 可执行操作 字节数: 备注
FFF1 Notify 跟随MTU长度 从模块串口Rx输入的数据将会在此通道产生通知发给主机
FFF2 Write 跟随MTU长度 写入的数据将会从串口的 Tx输出。

BLE 数据转串口输出,主机端通过 “FFF2” 通道写操作后,数据将会从串口Tx 输出。串口输入转BLE数据输出,如果打开了“FFF1”通道的通知使能开关,串口Rx收到透传的数据
将会通过notify事件发送到

如何验证串口透传协议成功

  1. 蓝牙模块默认为从机模式
  2. 等待设备启动完成,使用AT指令 TTM:ADV-START 启动从机的广播功能。
  3. 在手机上连接蓝牙模块。
  4. 通过串口 发送 透传数据, 手机上面的 0xFFF1 通道能接收到 串口透传的数据
  5. 通过手机上 0xFFF2 通道 write 消息,在串口上能够打印出来。
  6. 使用 TTM:ADV-OFF 关闭广播功能, 手机上将不会扫描到 该蓝牙的信息。

ble_uart 说明文档

CH592 简单的串口透传:
特性:
1, 使用两个128bit uuid,
2, 两个uuid 分别是write without respone,和 notify 方式,分别对应串口收和发,可以在工程文件ble_uart_service/ble_uart_service.c中修改
3, 可以兼容 N* 家的 ble uart 的工程,
4, 支持MTU在20-247 中任意设置,自适适应当前的mtu
5, 默认在CH592上调试,串口使用的UART3,TXD3@PA5,RXD3@PA4,其他的串口需要修改代码
透传UART3口
img
6, ble 名称为"chCH592le_uart" 已经修改成 qf_ble_uart
7, 默认开启串口notify 成功回写,不需要需要可以去掉代码,在ble service 的回掉函数,BLE_UART_EVT_BLE_DATA_RECIEVED 事件中 屏蔽即可
8, 默认开启串口调试,使用串口1,PA9_TXD 115200.
DEBUG打印UART1口
img

一些参数修改:

见工程的config.h文件

1 修改mtu 长度,最大为251此时对应mtu是247,但是实际mtu是多少,要看central端连接时候协商的值
2 修改每个连接 最多传输多少个包数量
3,全局宏定义建议在mounriver stdio工程的properties>C/C++ General> Path and Symbols 的Symbols 标签下设置

代码分析

问题

extern const unit_8 VER_LIB[];应该在库里面

TMOS 常见的接口

bool tmos_memcmp(const void *src1, const void *src2, unit32_t len);
void tmos_memset( void * pDst, uint8_t Value, uint32_t len )
注册事件回调函数
tmosTasklD TMOS_ProcessEventRegister( pTaskEventHandIerFn eventCb )

厂商提供的BLE库(参考)

常见的数据结构

typedef struct tag_ble_clock_config {...} bleClockConfig_t; /*ble clock control config struct */
typedef struct tag_ble_pa_control_config {...} blePaControlConfig_t;
typedef struct {...} tmos_event_hdr_t;
#define VER_FILE  "CH59x_BLE_LIB_V1.2" // 版本号
struct tag_ble_config { 
    uint32_t MEMAddr;               // library memory start address  BLE蓝牙库的开始地址
                                    // MEM_BUF[BLE_MEMHEAP_SIZE / 4] 
                                    // -- MEM_BUF[1536]

    uint16_t MEMLen;                // library memory size    库的内存大小
                                    // -- 1024 * 6
    uint32_t SNVAddr;               // SNV flash start address( if NULL,bonding information will not be saved )                         ? SNV flash 开始地址
    uint16_t SNVBlock;              // SNV flash block size ( default 256 )  ??
    uint8_t SNVNum;                 // SNV flash block number ( default 1 )  ??
    uint8_t BufNumber;              // Maximum number of sent and received packages cached by the controller( default 5 )         controller 缓存的 最大的发送和接收包的数量 默认为 5
                                    //  -- 5
                                    // Must be greater than the number of connections.
    uint16_t BufMaxLen;             // Maximum length (in octets) of the data portion of each HCI data packet( default 27 )            8进制格式的 HCI data 的 数据部分的 最大长度  默认 27
                                    //  -- 27 
                                    // SC enable,must be greater than 69  SC使能时,必须大于69
                                    // ATT_MTU = BufMaxLen-4,Range[23,ATT_MAX_MTU_SIZE]
                                    // ATT_MTU = 
    uint8_t TxNumEvent;             // Maximum number of TX data in a connection event ( default 1 ) -- 1
    uint8_t RxNumEvent;             // Maximum number of RX data in a connection event ( default equal to BufNumber )
    uint8_t TxPower;                // Transmit power level( default LL_TX_POWEER_0_DBM(0dBm) )
    uint8_t ConnectNumber;          // Connect number,lower two bits are peripheral number,followed by central number
    uint8_t WindowWidening;         // Wait rf start window(us)
    uint8_t WaitWindow;             // Wait event arrive window in one system clock
    uint8_t MacAddr[6];             // MAC address,little-endian
    pfnSrandCB srandCB;             // Register a program that generate a random seed
    pfnIdleCB idleCB;               // Register a program that set idle
    pfnTempSampleCB tsCB;           // Register a program that read the current temperature,determine whether calibration is need
    pfnLSICalibrationCB rcCB;       // Register a program that LSI clock calibration
    pfnLibStatusErrorCB staCB;      // Register a program that library status callback
    pfnFlashReadCB readFlashCB;     // Register a program that read flash
    pfnFlashWriteCB writeFlashCB;   // Register a program that write flash
} bleConfig_t 

TX POWER 定义

ERR_LIB_INIT lib初始化错误定义

#define ERR_LLE_IRQ_HANDLE              0x01  // 中断错误?
#define ERR_MEM_ALLOCATE_SIZE           0x02  // 内存分配的大小错误
#define ERR_SET_MAC_ADDR                0x03  //  MAC地址设置错误
#define ERR_GAP_ROLE_CONFIG             0x04  //   GAP_ROLE 配置错误
#define ERR_CONNECT_NUMBER_CONFIG       0x05  //   连接数量错误
#define ERR_SNV_ADDR_CONFIG             0x06  //  SNV 地址错误
#define ERR_CLOCK_SELECT_CONFIG         0x07   // 时钟选择错误

BLE_STATUS_VALUES BLE 默认的状态值

#define bleInvalidTaskID                INVALID_TASK  //!< Task ID isn't setup properly
#define bleEecKeyRequestRejected        0x06   //!< key missing
#define bleNotReady                     0x10   //!< Not ready to perform task
#define bleAlreadyInRequestedMode       0x11   //!< Already performing that task
#define bleIncorrectMode                0x12   //!< Not setup properly to perform that task
#define bleMemAllocError                0x13   //!< Memory allocation error occurred
#define bleNotConnected                 0x14   //!< Can't perform function when not in a connection
#define bleNoResources                  0x15   //!< There are no resource available
#define blePending                      0x16   //!< Waiting
#define bleTimeout                      0x17   //!< Timed out performing function
#define bleInvalidRange                 0x18   //!< A parameter is out of range
#define bleLinkEncrypted                0x19   //!< The link is already encrypted // link被加密了
#define bleProcedureComplete            0x1A   //!< The Procedure is completed
#define bleInvalidMtuSize               0x1B   //!< SDU size is larger than peer MTU. SDU size的大小比 MTU大

LINKDB

// Special case connection handles
#define INVALID_CONNHANDLE              0xFFFF // Invalid connection handle, used for no connection handle
#define LOOPBACK_CONNHANDLE             0xFFFE // Loopback connection handle, used to loopback a message
// Link state flags
#define LINK_NOT_CONNECTED              0x00   // Link isn't connected
#define LINK_CONNECTED                  0x01   // Link is connected
#define LINK_AUTHENTICATED              0x02   // Link is authenticated
#define LINK_BOUND                      0x04   // Link is bonded
#define LINK_ENCRYPTED                  0x10   // Link is encrypted
// Link Database Status callback changeTypes
#define LINKDB_STATUS_UPDATE_NEW        0      // New connection created
#define LINKDB_STATUS_UPDATE_REMOVED    1      // Connection was removed
#define LINKDB_STATUS_UPDATE_STATEFLAGS 2      // Connection state flag changed

GATT UUID

定义了很多功能的UUID 详细参考 CH59xBLE_LIB.h

MESSAGE ID

ATT MTU SIZE

/************************************ATT***************************************/
#define ATT_MTU_SIZE                    23   //!< Minimum ATT MTU size
#define ATT_MAX_MTU_SIZE                512  //!< Maximum ATT MTU size

ATT Methods

ATT Error Codes

PDU

GATT Attribute Access Permission Bit Fields

GATT Charateristic Properties Bit Fields

GAP ROLE 主从角色的定义

GAPBOND 匹配码的定义

在嵌入式编程中,节省代码空间和内存空间非常重要,特别是在资源受限的设备上。以下是一些常见的方法和技巧,可以帮助你优化代码,以节省代码空间和内存空间:

1. 使用高效的数据类型

选择适当的数据类型可以显著减少内存使用。

  • 选择合适的数据类型:例如,在可能的情况下使用 uint8_t 而不是 int,因为 uint8_t 只占用1个字节,而 int 通常占用4个字节。

  • 使用位字段:在结构体中使用位字段来节省空间。例如:

    struct Flags {
        uint8_t flag1 : 1;
        uint8_t flag2 : 1;
        uint8_t flag3 : 1;
        uint8_t flag4 : 1;
    };
    

2. 减少函数调用的开销

函数调用会带来一些开销,特别是对于小函数。

  • 内联函数:使用 inline 关键字提示编译器在调用点插入函数代码,而不是进行常规的函数调用。

    inline void myFunction() {
        // Function code
    }
    

3. 优化代码结构

通过优化代码结构,可以减少代码的重复和冗余。

  • 使用宏定义:用宏定义替换重复的代码段。

    #define MAX(a, b) ((a) > (b) ? (a) : (b))
    
  • 代码复用:将常用的代码提取为函数或宏,以减少代码重复。

4. 静态分配内存

在嵌入式系统中,动态内存分配(例如使用 mallocfree)可能会导致内存碎片和不必要的开销。

  • 使用静态分配:在编译时确定所有需要的内存,避免动态分配。

    int buffer[100]; // 静态分配
    

5. 优化编译器选项

使用编译器提供的优化选项来减少代码大小和内存使用。

  • 启用编译器优化:使用 -Os(针对代码大小优化)或 -O2(较高的优化级别,平衡代码大小和性能)。

    gcc -Os -o myProgram myProgram.c
    

6. 减少全局变量的使用

全局变量会占用内存,并且增加了代码的复杂性。

  • 使用局部变量:在可能的情况下,尽量使用局部变量。

7. 代码和数据存储在合适的存储器中

将代码和数据存储在合适的存储器中,以优化存储器使用。

  • 使用 const 关键字:将只读数据放入程序存储器(如 Flash),而不是 RAM。

    const char message[] = "Hello, World!";
    

8. 使用高效的算法和数据结构

选择合适的算法和数据结构,可以显著减少内存使用。

  • 简化算法:选择在空间和时间复杂度上更优的算法。
  • 压缩数据结构:例如,使用压缩树或图来存储稀疏数据。

9. 代码段和数据段合并

在某些情况下,可以将代码段和数据段合并,以减少内存浪费。

  • 合并数据段:将相似的常量数据合并到一个数据段中。

10. 使用链接器脚本优化内存布局

通过链接器脚本,可以精确控制程序和数据在内存中的布局。

  • 自定义链接器脚本:确保重要的代码和数据段放置在最合适的位置。
SECTIONS {
    .text : { *(.text) }
    .data : { *(.data) }
    .bss : { *(.bss) }
}

11. 使用外部存储器

如果设备支持,可以使用外部存储器来存放较大或次要的数据。

  • 外部 EEPROM/Flash:将不经常访问的大数据存储到外部存储器中。

12. 避免使用大型库

使用大型库会显著增加代码大小。

  • 选择小型库或自己实现:避免使用功能冗余的大型库,选择精简的库或者自己实现需要的功能。

通过结合以上这些方法,你可以显著减少嵌入式程序的代码空间和内存空间占用,确保在资源受限的设备上高效运行。

posted @ 2024-05-09 22:35  小飞Python  阅读(445)  评论(0编辑  收藏  举报