杰理 SDK 文档中心
首页
首页
  • 概述与入门

    • 项目概述与芯片平台
    • 环境搭建与工具链安装
    • 编译与烧录指南
    • 工程结构总览
  • 应用层与公共模块

    • GP MCU 主应用入口
    • AT 指令与调试模块
    • 电池检测与电源管理
    • EEPROM 与参数存储
    • 按键与 USB 设备驱动
    • 音频解码与 APA 语音播报
  • 外设驱动与示例

    • 高精度 ADC(HADC)
    • 通用 ADC 与定时器
    • UART / SPI / IIC 通信外设
    • MCPWM 与电机控制
    • RTC 与低功耗唤醒
    • 段码 LCD 驱动
    • NOR Flash 与红外编解码组件
  • 显示与 UI 系统

    • LCD 驱动与字库引擎
    • UI 平台与控件绘制
    • UI 工程与资源生成工具
  • 系统底层与芯片平台

    • cd09 芯片平台与预编译库
    • GPIO 与 IIC 底层驱动
    • 系统文件系统与设备模型
  • 启动引导与固件升级

    • UBOOT 引导工程
    • 固件升级机制
  • 开发工具与资源

    • 编译脚本与命令行工具
    • 音频文件转换工具
    • 硬件资料与文档资源

UART / SPI / IIC 通信外设

AC82N(BR 系列)MCU SDK 中三大串行通信外设的统一参考:UART(通用异步收发)、SPI(串行外设接口)与 IIC(I²C 两线接口)的驱动 API、数据结构、工作模式与典型用法。

Purpose and Scope

本页面系统介绍 AC82N_GP-MCU_SDK 中 UART、SPI、IIC 三类通信外设的驱动层接口与使用方式,涵盖:

  • UART:uart_v2.h 定义的设备句柄、配置结构体、DMA 接收、事件回调、硬件流控与单线半双工模式;
  • SPI:spi.h 定义的四种工作模式(1/2/4 位半双工与全双工)、主/从角色、阻塞/中断/DMA 三类传输接口;
  • IIC:iic_api.h 定义的软件 IIC(GPIO 模拟)与硬件 IIC 两套实现,以及基于 _IIC_USE_HW 宏的统一接口抽象。

以下内容属于兄弟页面范畴,不在本页展开:具体外设器件驱动(如 LCD 的 lcd_spi_st7735 等 SPI 屏驱动、EEPROM 的 iic_eeprom.c)、GPIO 基本输入输出、UART 日志系统(uart_log.c)与 UBOOT 阶段串口。本页聚焦于驱动 API 本身的设计与使用;如需查看器件级应用,可参考 sdk/cpu/demo/uart_demo.c、sdk/cpu/demo/spi_demo.c、sdk/cpu/demo/iic_demo.c 三个示例工程。

Overview

三类外设是嵌入式系统中最基础的数据通路:UART 用于异步点对点通信(调试、AT 指令、低速率传感),SPI 用于高速同步通信(Flash、LCD、SD 卡),IIC 用于低速多设备总线(EEPROM、传感器、PMIC)。AC82N SDK 对它们的抽象层级一致:

  1. API 头文件(include_lib/driver/cpu/periph/ 与 include_lib/driver/cpu/)暴露全部对外接口;
  2. 实现文件(sdk/cpu/cd09/、sdk/cpu/)完成寄存器级操作;
  3. 设备框架(UART 通过 device/device.h 与 generic/ioctl.h 集成到设备子系统)与 OS 抽象(信号量/互斥锁可切换为 RTOS 或裸机实现)。

三个外设的设计哲学各有侧重:

  • UART 以"配置结构体 + 事件回调 + 环形缓冲"为中心,把 DMA、超时帧检测、校验错误等全部收敛到 uart_dma_config 中,并提供 UT_Semaphore/UT_mutex 的 OS 双实现(见 uart_v2.h),使同一套 API 既可用于 RTOS 环境也可用于裸机。
  • SPI 以 spi_platform_data 描述引脚与时序(CPOL/CPHA),通过 spi_open 打开通道后,按阻塞(字节级)、DMA(块级)、中断(ISR 内逐字节/逐缓冲)三档接口递进,主从机共用中断接口。
  • IIC 通过 _IIC_USE_HW 编译宏在软件 IIC(任意 GPIO 模拟,频率不精确)与硬件 IIC(精确时序、可中断、支持从机)之间切换,上层统一使用 i2c_master_read_nbytes_from_device_reg 这类"寄存器地址 + 数据"的语义化接口。

Architecture

flowchart TD
    subgraph sg_App["应用层"]
        App["用户代码 / demo 工程<br/>uart_demo / spi_demo / iic_demo"]
    end

    subgraph sg_API["外设 API 层 (头文件)"]
        UART_API["uart_v2.h<br/>uart_init / uart_dma_init"]
        SPI_API["spi.h<br/>spi_open / spi_dma_send"]
        IIC_API["iic_api.h<br/>i2c_master_read/write_nbytes"]
    end

    subgraph sg_IMPL["实现层 (cpu 目录)"]
        UART_IMPL["cpu/cd09 串口实现<br/>+ uart_log.c"]
        SPI_IMPL["cpu/cd09/spi_hw_v2.c"]
        IIC_IMPL["cpu/iic_api.c + iic_soft.c<br/>(软 IIC 与硬 IIC 两套)"]
    end

    subgraph sg_HW["硬件外设"]
        UART_HW["UART 控制器<br/>DMA / FIFO / 流控"]
        SPI_HW["SPI 控制器<br/>SPI0 / SPI1 / SPI2"]
        IIC_HW["IIC 控制器 或 GPIO 模拟<br/>SCL / SDA"]
    end

    App -->|"调用 API"| UART_API
    App -->|"调用 API"| SPI_API
    App -->|"调用 API"| IIC_API
    UART_API --> UART_IMPL --> UART_HW
    SPI_API --> SPI_IMPL --> SPI_HW
    IIC_API --> IIC_IMPL --> IIC_HW

架构说明

  • API 层与实现层分离:头文件位于 sdk/include_lib/driver/cpu/(对外发布),实现位于 sdk/cpu/(内部编译)。这使驱动可独立升级、应用代码无需关心寄存器细节。
  • IIC 的双实现是唯一"一 API 两实现"的外设:iic_soft.c 用 GPIO 位翻转模拟时序(任意引脚、无硬件限制、频率不准),iic_api.c + iic_hw_v2.h 走硬件控制器(精确时序、可配置滤波与中断、支持从机)。宏 _IIC_USE_HW 决定 iic_init 等符号最终映射到哪一套。
  • UART 的 OS 抽象:CONFIG_ENABLE_UART_OS_SEM 开启时信号量/互斥锁映射到 os_sem_*/os_mutex_*;关闭时退化为带 wdt_clear() 与 asm("idle") 的自旋实现(见 uart_v2.h),保证裸机环境下同样可阻塞等待。

UART 深入解析

UART 驱动以"设备号 + 配置结构体"为核心。设备句柄类型为 typedef const int uart_dev,uart_num = -1 时由驱动自动分配串口号,返回值 >= 0 表示实际分配的串口号(见 uart_v2.h)。

配置结构体与设计意图

struct uart_config {
    u32 baud_rate;
    u16 tx_pin; //不使用时配0xffff
    u16 rx_pin; //不使用时配0xffff,当rx_pin == tx_pin 的时候为单线半双工通讯模式
    enum uart_parity parity;//uart_v2有效
    u8 tx_wait_mutex;//1:不支持中断调用,互斥,0:支持中断,不互斥
};

struct uart_dma_config {
    cbuffer_t cbuf;
    u32 rx_timeout_thresh;//us, 需大于1byte时间
    u32 frame_size;//一般配置=rx_cbuffer_size
    u32 rx_cbuffer_size;
    void *rx_cbuffer;
    void (*irq_callback)(uart_dev uart_num, enum uart_event);      //推送到调用者的线程执行
    enum uart_event event_mask;
    UT_Semaphore uart_rx;
    u8 irq_priority;//中断优先级
};

struct uart_flow_ctrl {
    u16 cts_pin;      //不使用时配0xffff
    u16 rts_pin;      //不使用时配0xffff
    u8 cts_idle_level;     //0:cts空闲电平为低; 1:cts空闲电平为高
    u8 rts_idle_level;     //0:rts空闲电平为低; 1:rts空闲电平为高
    u8 rx_thresh;         // 0~100 %
};

来源:uart_v2.h

要点:

  • tx_pin/rx_pin 用 0xffff 表示"不使用":可只配 TX(只发)或只配 RX(只收);当 rx_pin == tx_pin 时自动进入单线半双工模式,这是很多低引脚数传感与调试协议(如单线总线)的常用形态。
  • tx_wait_mutex 是并发安全开关:置 1 时发送前会取互斥锁(不支持在中断里调用发送),置 0 时不做互斥、允许中断上下文直接发送。设计意图是让用户按自己的调用场景在"数据完整性"与"可中断性"之间取舍。
  • DMA 配置把"数据搬运"与"事件通知"绑定在一起:rx_cbuffer 是接收环形缓冲,irq_callback 由中断推送到调用者线程执行,event_mask 决定哪些事件会上报,uart_rx 信号量用于阻塞式等待接收。

事件与状态码

enum uart_event : u8 {
    UART_EVENT_RX_DATA = 1,       //接收缓冲区溢出
    UART_EVENT_RX_FIFO_OVF = 2,   //接收缓冲区溢出
    UART_EVENT_RX_TIMEOUT = 4,    //数据帧接收完成
    UART_EVENT_PARITY_ERR = 8,    //奇偶校验错误
    UART_EVENT_TX_DONE = 16,      //数据发送完成
};

来源:uart_v2.h

事件是位掩码(1/2/4/8/16),可组合赋给 uart_dma_config.event_mask。UART_EVENT_RX_TIMEOUT(帧接收完成)依赖 rx_timeout_thresh,用于把一帧不定长的数据包整体交付给上层——这是"接收超时判帧"的典型设计。

状态码 enum uart_state 从 UART_OK = 0 到 UART_ERROR_FLOWCTRL_IO = -13,依次覆盖:忙、设备已关闭、上下文错误、内存分配失败、缓冲未 4 字节对齐、超时、OS 对象创建失败、波特率非法、RX/TX 缓冲分配失败、硬件流控初始化失败/IO 错误等(见 uart_v2.h)。负值返回约定贯穿整个 SDK,调用方只需判断 < 0 即失败。

运行时接口

s32 uart_init(uart_dev uart_num, const struct uart_config *config);      // >=0:串口号, <0:失败
s32 uart_deinit(uart_dev uart_num);                                       // <0:error; 0:ok
s32 uart_dma_init(uart_dev uart_num, const struct uart_dma_config *dma_config);
void uart_dump();                                                         // 打印uart配置信息
s32 uart_set_baudrate(uart_dev uart_num, u32 baud_rate);                  // 返回实际波特率
s32 uart_set_rx_timeout_thresh(uart_dev uart_num, u32 timeout_thresh);

来源:uart_v2.h

uart_set_baudrate 返回实际波特率而非 0/1,体现"请求值 → 分频器取整 → 回读实际值"的闭环设计——对需要精确波特率(如 BLE 配对、红外载波)的场景至关重要。

SPI 深入解析

SPI 驱动以 hw_spi_dev 句柄 + spi_platform_data 配置为中心,支持三个硬件通道(SPI0/1/2)。

模式、角色与时序配置

enum spi_mode {
    SPI_MODE_BIDIR_1BIT,    //支持SPIx(x=0,1,2),全双工,di接收,do发送
    SPI_MODE_UNIDIR_1BIT,   //支持SPIx(x=0,1,2),半双工,do分时发送/接收
    SPI_MODE_UNIDIR_2BIT,   //支持SPIx(x=0,1,2),半双工,di & do共2bit分时发送/接收
    SPI_MODE_UNIDIR_4BIT,   //支持SPIx(x=1),半双工,di & do & wp & hold 共4bit分时发送/接收
};
enum spi_role {
    SPI_ROLE_MASTER,
    SPI_ROLE_SLAVE,
};

typedef struct spi_platform_data {
    u8 port[6];                //CLK, DO, DI, D2(wp), D3(hold), cs(只用于slave)
    enum spi_role role;        //master or slave
    enum spi_mode mode;        //模式,选项为enum spi_mode中的枚举常量
    enum spi_bit_mode bit_mode;
    u8 cpol: 1; //clk level in idle state:0:low,  1:high
    u8 cpha: 1; //sampling edge:0:first,  1:second
    u8 ie_en: 1; //ie enbale:0:disable,  1:enable
    u8 irq_priority: 5; //中断优先级
    void (*spi_isr_callback)(hw_spi_dev spi, enum hw_spi_isr_status sta);  //spi isr callback
    u32 clk;  //波特率
} spi_hardware_info;

来源:spi.h

要点:

  • port[6] 固定顺序:CLK、DO、DI、D2(wp)、D3(hold)、CS(CS 仅从机使用,主机 CS 由 HW_SPI_MASTER_CS_EN 宏控制开关,默认关闭,见 spi.h)。这与常见 MCU 的引脚复用表一一对应,配置时按此顺序填写 IO 编号。
  • 位域打包的时序参数:cpol(空闲时钟电平)、cpha(采样沿)、ie_en(中断使能)、irq_priority(5 bit 中断优先级)共用一个字节,spi_isr_callback 用于中断模式完成通知。
  • 模式演进反映 Flash/屏类器件的需求:BIDIR_1BIT 是标准 4 线全双工;UNIDIR_1BIT/2BIT/4BIT 分别对应 SPI NOR Flash 的 1-1-1、1-1-2、1-1-4 以及 QSPI 的 4 线模式(wp/hold 复用为数据线)。注意 4BIT 模式仅 SPI1 支持。

传输接口分层

/*******************主机 阻塞接口*********************/
u8 spi_recv_byte(hw_spi_dev spi, int *err);
int spi_send_byte(hw_spi_dev spi, u8 byte);
u8 spi_send_recv_byte(hw_spi_dev spi, u8 byte, int *err);//全双工

int spi_dma_recv(hw_spi_dev spi, void *buf, u32 len);
int spi_dma_send(hw_spi_dev spi, const void *buf, u32 len);

来源:spi.h

阻塞接口按字节粒度工作:spi_recv_byte/spi_send_byte 用于单字节读写,spi_send_recv_byte 一次调用同时完成发送与接收(全双工),这对"读状态寄存器时需要先发命令字节"的器件操作很关键。spi_dma_recv/spi_dma_send 用于块传输,适合 LCD 帧缓冲、Flash 页编程等大数据量场景。

中断接口(spi_set_ie、hw_spix_irq_change_callback、spi_byte_transmit_for_isr、spi_buf_transmit_for_isr、spi_dma_transmit_for_isr,见 spi.h)统一为 rw 参数区分收发(rw:1-rx; 0-tx),主从机均可使用,不等待 pending、无 CS 控制——适用于在中断回调里推进的协议栈(如 DMA 乒乓、命令队列)。中断状态由 enum hw_spi_isr_status(WAITING_PND / TX_FINISH / RX_FINISH / PND_ERROR)与 hw_spix_get_isr_len(带符号长度:DMA 为负、字节为正)共同表达(见 spi.h)。

IIC 深入解析

IIC 是三者中抽象最特殊的一个:一份 API,两套实现,由宏 _IIC_USE_HW 决定编译期映射。

统一配置与状态

struct iic_master_config {
    enum iic_role role;     //软件只有IIC_MASTER
    int scl_io;
    int sda_io;
    enum gpio_mode io_mode;//上拉或浮空
    enum gpio_drive_strength hdrive;   //enum GPIO_HDRIVE 0:2.4MA, 1:8MA, 2:26.4MA, 3:40MA
    u32 master_frequency; //软件iic频率(hz 不准)
    u8 ie_en;     //中断使能
    u8 irq_priority;     //中断
    u8 io_filter; //BR50: 0:close filter; 1:<1*Tiic_baud_clk, ...
};

来源:iic_api.h

  • 软件 IIC 只支持 IIC_MASTER 角色,master_frequency 只是"请求值,实际不准"——因为 GPIO 位翻转受指令周期抖动影响,注释明确承认这一点;
  • io_mode 用于配置上拉/浮空(IIC 开漏总线通常需要上拉),hdrive 选择驱动强度(2.4~40mA),io_filter 按芯片型号不同语义:BR27/28/36 为 0/1 开关,BR50 为 0~3 级滤波深度。

语义化读写接口(核心用法)

//如果无reg_addr:reg_addr=NULL,reg_len=0
//return: <0:error,  =read_len:ok
int soft_i2c_master_read_nbytes_from_device_reg(soft_iic_dev iic,
        unsigned char dev_addr, //设备地址
        unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
        unsigned char *read_buf, int read_len);//缓存buf,读取长度

//如果无reg_addr:reg_addr=NULL,reg_len=0
//return: =write_len:ok, other:error
int soft_i2c_master_write_nbytes_to_device_reg(soft_iic_dev iic,
        unsigned char dev_addr,
        unsigned char *reg_addr, unsigned char reg_len,
        unsigned char *write_buf, int write_len);

来源:iic_api.h

hw_i2c_master_read_nbytes_from_device_reg / hw_i2c_master_write_nbytes_to_device_reg 签名与软 IIC 完全一致(见 iic_api.h),只是句柄类型换成 hw_iic_dev。reg_len 支持多字节寄存器地址(如 2 字节寻址的 EEPROM),reg_addr == NULL && reg_len == 0 表示无寄存器寻址的裸读写。返回值约定:读成功返回 read_len,写成功返回 write_len,其余为错误码。

宏抽象层:一套代码切换软/硬 IIC

#ifdef _IIC_USE_HW
#define iic_init(iic, config)               hw_iic_init(iic, config)
#define iic_start(iic)                      hw_iic_start(iic)
#define iic_stop(iic)                       hw_iic_stop(iic)
#define iic_tx_byte(iic, byte)              hw_iic_tx_byte(iic, byte)
#define iic_rx_byte(iic, ack)               hw_iic_rx_byte(iic, ack)
#define iic_read_buf(iic, buf, len)         hw_iic_read_buf(iic, buf, len)
#define iic_write_buf(iic, buf, len)        hw_iic_write_buf(iic, buf, len)
#define iic_suspend(iic)                    hw_iic_suspend(iic)
#define iic_resume(iic)                     hw_iic_resume(iic)
#else
#define iic_init(iic, config)               soft_iic_init(iic, config)
#define iic_start(iic)                      soft_iic_start(iic)
#define iic_stop(iic)                       soft_iic_stop(iic)
#define iic_tx_byte(iic, byte)              soft_iic_tx_byte(iic, byte)
#define iic_rx_byte(iic, ack)               soft_iic_rx_byte(iic, ack)
#define iic_read_buf(iic, buf, len)         soft_iic_read_buf(iic, buf, len)
#define iic_write_buf(iic, buf, len)        soft_iic_write_buf(iic, buf, len)
#define iic_suspend(iic)                    soft_iic_suspend(iic)
#define iic_resume(iic)                     soft_iic_resume(iic)
#endif

来源:iic_api.h

这一层宏让器件驱动(如 iic_eeprom.c)只需写一次 iic_start/iic_tx_byte 等原语,编译时自动绑定到软或硬实现——这是"策略在编译期决定"的典型手法,避免运行期分支开销,也保证裸机与 RTOS 下行为一致。底层原语之外还有 hw_iic_slave_polling_rx / hw_iic_slave_polling_tx 两个硬件从机轮询接口(见 iic_api.h),软件 IIC 不提供从机能力。

Core Flow

UART DMA 接收流程

sequenceDiagram
    participant App as 应用线程
    participant U as uart_init + uart_dma_init
    participant ISR as 串口中断
    participant CB as 环形缓冲 cbuffer_t

    App->>U: uart_init(num, config) 配置波特率/引脚
    App->>U: uart_dma_init(num, dma_config) 注册回调与事件掩码
    U->>CB: 建立 rx_cbuffer
    loop 数据持续到达
        ISR->>CB: 硬件中断把 RX 数据搬入环形缓冲
        ISR->>App: 推送 irq_callback(uart, event)
    end
    App->>CB: 按 event_mask 消费数据 / 等待 uart_rx 信号量
    App->>U: uart_deinit(num) 释放资源

设计意图:接收路径完全由中断驱动,环形缓冲解耦"硬件中断产生数据"与"应用线程消费数据";UART_EVENT_RX_TIMEOUT 事件让上层能按"帧"而非按"字节"处理不定长协议包;rx_timeout_thresh 需大于 1 字节传输时间,避免正常传输间隙被误判为帧结束。

SPI 主机一次完整事务

sequenceDiagram
    participant M as SPI Master
    participant D as 从设备 (Flash/LCD)

    M->>M: spi_open(spi, &info) 配置 mode/cpol/cpha/clk
    M->>D: spi_send_byte(命令字节)
    M->>D: spi_send_recv_byte(数据, 全双工交换)
    M->>D: spi_dma_send(buf, len) 大块数据 (DMA)
    M->>M: hw_spix_get_isr_status 查询完成状态
    M->>M: spi_deinit(spi) 释放通道

中断模式下 spi_byte_transmit_for_isr/spi_buf_transmit_for_isr/spi_dma_transmit_for_isr 可取代阻塞调用,在 spi_isr_callback 中推进状态机;hw_spix_clear_isr_len 必须在每包数据前调用,且注释警告"在通信中间调用会导致数据长不准"(见 spi.h)。

IIC 寄存器读流程(软/硬通用)

sequenceDiagram
    participant M as IIC Master (soft/hw)
    participant D as IIC 从设备 (EEPROM/传感器)

    M->>M: iic_init(iic, &config) 或 i2c_master_*_nbytes 直连
    M->>D: START + dev_addr(W)
    M->>D: reg_addr[0..reg_len-1] (多字节寄存器地址)
    M->>D: 重复 START + dev_addr(R)
    D-->>M: read_len 字节数据 + ACK/NACK
    M->>D: STOP

i2c_master_read_nbytes_from_device_reg 把上面的 START/地址/重复起始/STOP 时序全部封装在驱动内部,应用只提供设备地址、寄存器地址与长度即可,避免了手工维护总线时序的常见错误。

Usage Examples

示例一:UART 配置与 DMA 初始化

struct uart_config uart_cfg = {
    .baud_rate = 115200,
    .tx_pin = 0xffff,   // 只收不发
    .rx_pin = IO_PORTA_01,
    .parity = UART_PARITY_DISABLE,
    .tx_wait_mutex = 0, // 允许中断上下文发送
};
s32 uart_num = uart_init(-1, &uart_cfg);   // -1: 自动分配串口号

struct uart_dma_config dma_cfg = {
    .rx_timeout_thresh = 2000,   // us, 需大于1byte时间
    .frame_size = 256,
    .rx_cbuffer_size = 256,
    .rx_cbuffer = rx_buf,
    .event_mask = UART_EVENT_RX_DATA | UART_EVENT_RX_TIMEOUT,
    .irq_priority = 2,
};
uart_dma_init(uart_num, &dma_cfg);

结构体字段取自 uart_v2.h,调用方式依据 uart_init/uart_dma_init 声明(uart_v2.h)。

示例二:SPI 通道打开与全双工收发

spi_hardware_info spi_info = {
    .port = {SPI_CLK_IO, SPI_DO_IO, SPI_DI_IO, 0xff, 0xff, 0xff},
    .role = SPI_ROLE_MASTER,
    .mode = SPI_MODE_BIDIR_1BIT,   // 标准全双工
    .cpol = 0,                     // 空闲低电平
    .cpha = 0,                     // 第一个沿采样
    .ie_en = 0,
    .clk = 10000000,               // 10MHz
};
int ret = spi_open(SPI0, &spi_info);
u8 cmd = 0x9F;                                   // 读 JEDEC ID 命令
u8 rsp = spi_send_recv_byte(SPI0, cmd, NULL);    // 全双工交换

字段定义见 spi.h,接口声明见 spi.h。

示例三:IIC 寄存器读写(软/硬件统一接口)

unsigned char dev_addr = 0xA0;                  // EEPROM 器件地址
unsigned char reg_addr[2] = {0x00, 0x10};       // 2字节寄存器地址
unsigned char wbuf[16], rbuf[16];

// 写:向寄存器写入 16 字节
int wr = i2c_master_write_nbytes_to_device_reg(0, dev_addr,
        reg_addr, sizeof(reg_addr), wbuf, sizeof(wbuf));
// 读:从寄存器读出 16 字节
int rd = i2c_master_read_nbytes_from_device_reg(0, dev_addr,
        reg_addr, sizeof(reg_addr), rbuf, sizeof(rbuf));
// 返回约定: wr == sizeof(wbuf) 成功; rd == sizeof(rbuf) 成功; 否则为负错误码

接口签名见 iic_api.h,宏映射见 iic_api.h。iic 参数为设备索引(软 IIC 为 soft_iic_dev,硬 IIC 为 hw_iic_dev)。

Configuration Options

UART 配置项(struct uart_config / struct uart_dma_config)

选项类型默认/典型值说明
baud_rateu32115200波特率;uart_set_baudrate 返回实际值
tx_pin / rx_pinu160xffff0xffff 表示不使用;tx_pin == rx_pin 时为单线半双工
parityenum uart_parityDISABLEDISABLE / all_0 / all_1 / EVEN / ODD
tx_wait_mutexu8—1:发送互斥(不可中断调用);0:不互斥(可中断调用)
rx_timeout_threshu32—帧超时阈值(us),需大于 1 字节时间
frame_size / rx_cbuffer_sizeu32相等DMA 帧长与接收环形缓冲大小
event_maskenum uart_event—RX_DATA(1)/RX_FIFO_OVF(2)/RX_TIMEOUT(4)/PARITY_ERR(8)/TX_DONE(16) 位或组合
irq_priorityu8—串口中断优先级
cts_pin/rts_pinu160xffff硬件流控引脚,0xffff 关闭
rx_threshu8—RTS 触发阈值(0~100%)

SPI 配置项(spi_platform_data)

选项类型说明
port[6]u8 数组固定顺序:CLK、DO、DI、D2(wp)、D3(hold)、CS(CS 仅从机)
roleenum spi_roleMASTER / SLAVE
modeenum spi_modeBIDIR_1BIT(全双工)/ UNIDIR_1BIT / UNIDIR_2BIT / UNIDIR_4BIT(仅 SPI1)
cpol / cphabit空闲电平(0 低/1 高)、采样沿(0 第一沿/1 第二沿)
ie_enbit中断使能
irq_priority5bit中断优先级
clku32波特率(Hz)

IIC 配置项(struct iic_master_config)

选项类型说明
roleenum iic_role软件 IIC 仅支持 IIC_MASTER
scl_io / sda_ioint总线引脚(GPIO 号)
io_modeenum gpio_mode上拉或浮空
hdriveenum gpio_drive_strength0:2.4MA / 1:8MA / 2:26.4MA / 3:40MA
master_frequencyu32请求频率;软件 IIC 实际不准
ie_en / irq_priorityu8中断使能与优先级
io_filteru8BR27/28/36:0/1 开关;BR50:0~3 级滤波

编译期开关

宏作用
CONFIG_ENABLE_UART_OS_SEM1:UART 信号量/互斥锁映射到 RTOS(os_sem_*/os_mutex_*);0:退化为裸机自旋实现
_IIC_USE_HW1:iic_* 原语映射到硬件 IIC;0:映射到软件 IIC(GPIO 模拟)
HW_SPI_MASTER_CS_EN主机片选使能开关(0 关 / 1 开)

API Reference

UART

  • s32 uart_init(uart_dev uart_num, const struct uart_config *config) — 初始化串口;uart_num = -1 自动分配,返回 >=0 串口号,<0 失败。
  • s32 uart_deinit(uart_dev uart_num) — 关闭串口;返回 0 成功。
  • s32 uart_dma_init(uart_dev uart_num, const struct uart_dma_config *dma_config) — 配置 DMA 接收、回调与事件掩码。
  • s32 uart_set_baudrate(uart_dev uart_num, u32 baud_rate) — 动态改波特率;返回实际波特率(<0 错误)。
  • s32 uart_set_rx_timeout_thresh(uart_dev uart_num, u32 timeout_thresh) — 动态调整接收超时阈值。
  • void uart_dump(void) — 打印各串口配置信息(调试用)。

错误码区间:UART_OK(0),UART_ERROR_BUSY(-1) ~ UART_ERROR_FLOWCTRL_IO(-13),详见 uart_v2.h。

SPI

  • int spi_open(hw_spi_dev spi, spi_hardware_info *spi_info) — 按平台数据打开 SPI 通道(主/从)。
  • void spi_deinit(hw_spi_dev spi) / spi_suspend / spi_resume — 释放/挂起/恢复。
  • int spi_set_baud(hw_spi_dev spi, u32 baud) / u32 spi_get_baud(...) — 动态调整/读取波特率。
  • void spi_set_bit_mode(hw_spi_dev spi, enum spi_mode mode) — 运行期切换 1/2/4 位模式。
  • 阻塞:u8 spi_recv_byte(spi, int *err)、int spi_send_byte(spi, u8)、u8 spi_send_recv_byte(spi, u8, int *err)。
  • DMA:int spi_dma_recv(spi, void *buf, u32 len)、int spi_dma_send(spi, const void *buf, u32 len)。
  • 中断:spi_byte_transmit_for_isr / spi_buf_transmit_for_isr / spi_dma_transmit_for_isr(rw: 1-rx; 0-tx)、hw_spix_get_isr_status、hw_spix_get_isr_len、hw_spix_slave_get_dma_len。

IIC

  • int soft_i2c_master_read_nbytes_from_device_reg(soft_iic_dev, dev_addr, reg_addr, reg_len, read_buf, read_len) — 软 IIC 读;成功返回 read_len。
  • int soft_i2c_master_write_nbytes_to_device_reg(...) — 软 IIC 写;成功返回 write_len。
  • int hw_i2c_master_read_nbytes_from_device_reg(hw_iic_dev, ...) / hw_i2c_master_write_nbytes_to_device_reg(...) — 硬件 IIC 对应接口。
  • 原语(宏映射):iic_init / iic_start / iic_stop / iic_tx_byte / iic_rx_byte / iic_read_buf / iic_write_buf / iic_suspend / iic_resume / iic_reset / iic_deinit。
  • 从机:int hw_iic_slave_polling_rx(hw_iic_dev, u8 *rx_buf)、int hw_iic_slave_polling_tx(hw_iic_dev, u8 *tx_buf)。

错误码区间:IIC_OK(0),IIC_ERROR_INIT_FAIL(-1) ~ IIC_ERROR_RESLOCK_BUSY(-11),覆盖初始化失败、未初始化、挂起/恢复失败、忙、参数错误、设备地址/寄存器地址 ACK 错误、索引/频率错误、资源锁忙等(见 iic_api.h)。

Failure Modes, Edge Cases & Concurrency

  • 返回值约定:三个外设统一"负值即失败";UART/IIC 的多数接口返回 0 表示成功或返回实际长度,判断时必须区分"成功返回的实际值"与"负数错误码",例如 IIC 读成功返回 read_len 而非 0。
  • UART 缓冲区溢出:UART_EVENT_RX_FIFO_OVF 上报 FIFO 溢出;UART_ERROR_CLOSE 注释为"接收缓冲区溢出"(历史命名,实际语义以枚举注释为准)。rx_cbuffer 必须 4 字节对齐,否则返回 UART_ERROR_BUF_ALIGN4。
  • 中断上下文限制:tx_wait_mutex = 1 时 UART 发送不可在中断中调用(会死锁);= 0 时允许。SPI 的中断接口明确"不等待 pnd、无 CS",调用者必须在 ISR 回调中自行管理包边界与片选。
  • SPI 长度计数:hw_spix_clear_isr_len 只能在每包数据前调用,通信中途调用会导致长度统计错误;hw_spix_get_isr_len 用符号区分 DMA(负)与字节(正)传输。
  • 软件 IIC 时序:master_frequency 仅为请求值,实际时序受指令抖动影响不准;软件 IIC 无硬件滤波(io_filter 仅硬件生效),长总线或高干扰环境应优先硬件 IIC 并开启滤波。
  • 单线半双工:UART rx_pin == tx_pin 时收发共用一根线,需应用层自行保证半双工时序(发送时禁止同时接收解析)。
  • 裸机并发:CONFIG_ENABLE_UART_OS_SEM = 0 时,信号量/互斥退化为 volatile u8 自旋 + wdt_clear() + asm("idle"),等待超时依赖 jiffies 换算(ut_msecs_to_jiffies 10ms 取整),短超时精度有限(见 uart_v2.h)。

Performance & Operational Considerations

  • DMA 优先:UART 大数据接收、SPI 大块传输都应走 DMA 路径(uart_dma_init / spi_dma_send/spi_dma_recv),字节级轮询只用于低频命令交互。
  • SPI 4 线模式带宽:SPI_MODE_UNIDIR_4BIT 仅 SPI1 支持,是读取高容量 Flash / 高分辨率屏的最高带宽选项;启用前需确认 port[] 中 D2/D3 引脚已分配。
  • UART 帧超时调参:rx_timeout_thresh 必须大于 1 字节传输时间(如 115200 波特率下约 87us),过小会拆帧、过大增加协议响应延迟;协议报文越长可适当调大。
  • IIC 总线负载:硬件 IIC 的 io_filter 在 BR50 上提供 1~3 个 Tiic_baud_clk 的滤波窗口,抗干扰与速率之间需权衡;软件 IIC 因位翻转慢,总线上挂多设备时需降低 master_frequency 请求值。
  • 调试手段:uart_dump() 可打印全部串口配置,用于核对初始化参数;SPI 中断状态通过 hw_spix_get_isr_status 的 SPI_PND_ERROR 排查异常。

Extension Points

  • 新增 UART 用途:uart_dma_config.irq_callback 是唯一的应用扩展钩子——在同一回调内根据 event_mask 分发到帧处理、错误统计、协议解析等逻辑,避免改动驱动。
  • SPI 从机协议栈:spi_isr_callback + spi_buf_transmit_for_isr/spi_dma_transmit_for_isr 可构建从机命令响应状态机;hw_spix_slave_get_dma_len 用于查询从机已接收长度。
  • IIC 器件驱动:基于 i2c_master_read/write_nbytes_from_device_reg 写新器件驱动即可自动兼容软/硬 IIC(编译期宏切换),如 iic_eeprom.c 的做法;若需更细粒度控制(如页写、重复起始),可下钻到 iic_start/iic_tx_byte 原语层。
  • OS 移植:UART 的 UT_Semaphore/UT_mutex 封装是唯一需要随 OS 变化的部分,新增 RTOS 时只需替换 uart_v2.h 中 CONFIG_ENABLE_UART_OS_SEM 分支的内联实现。

Related Links

  • UART 设备框架与类型:sdk/include_lib/driver/cpu/cd09/asm/uart_types.h、sdk/include_lib/driver/cpu/cd09/asm/uart_log.h
  • UART 实现与示例:sdk/cpu/cd09/uart_log.c、sdk/cpu/demo/uart_demo.c、sdk/UBOOT工程/cpu/cd09/user_uart.c
  • SPI 硬件层与示例:sdk/include_lib/driver/cpu/cd09/asm/spi_hw.h、sdk/cpu/cd09/spi_hw_v2.c、sdk/cpu/demo/spi_demo.c
  • SPI 屏驱动示例(器件级):sdk/apps/common/lcd/lcd_spi_st7735_128x128.c、lcd_spi_st7789_BOE1.54_update_240x240.c
  • IIC 实现与示例:sdk/cpu/iic_api.c、sdk/cpu/iic_soft.c、sdk/cpu/demo/iic_demo.c、sdk/include_lib/driver/cpu/periph/iic_soft.h、iic_hw_v2.h
  • IIC 器件级应用:sdk/apps/common/eeprom/iic_eeprom.c、sdk/apps/common/eeprom/iic_eeprom.h
  • 相关外设页面:GPIO 驱动(io_mode/hdrive 类型来源)、LCD 显示驱动、EEPROM 存储
Prev
通用 ADC 与定时器
Next
MCPWM 与电机控制