【前言】
最近入手纳芯微NS800开发板一块。准备连载一系列的相关文档。
【芯片介绍】
NS800RTx 芯片基于 ARM 指令架构的 Cortex M7 内核,集成 eMATH 数学加速核,适用于工业和汽车领域复杂 计算场景。借助 eMATH 数学加速器,NS800RTx 具备强大的快速环路计算能力。从运算周期对比来看,eMATH 在 执行如三角函数等运算时,运算周期与C2000 硬件加速器相近。且在支持更多复杂运算(如指数、对数、滤波 器以及矩阵运算)方面具有显著优势。尤其在电力系统的谐波分析中,需频繁进行复杂的矩阵运算和滤波算法, eMATH 加速器可高效完成这些运算,确保系统能快速、准确地分析谐波情况,保障电力系统稳定运行。 其外设资源丰富,详件下图:

【UART外设使用】
UART的相关的命名
NS系列的UART有两套命名:UART与SCIB(Serial Communication Interface B)
SCIB 是 TI 命名习惯(SCI = Serial Communication Interface,后缀 A/B/C 表示不同实例),SDK 封装为更通用的 UART* 名称,对开发者更友好。
但是为了通用,好象SDK将他又命名了UART1_4
UART1 — 对应 SCIA,板级调试串口(115200,GPIO_12/GPIO_13)
UART2 — 对应 SCIB,本工程示例(GPIO_38/GPIO_39,230400)
UART3 — 对应 SCIC
UART4 — 对应 SCID
在SDK 中使用:UART_TypeDef *uart = UART2; // 定义指向 UART2 的指针
寄存器结构体命名
每个 UART 实例的寄存器通过结构体访问,寄存器名均为大写:
uart->GLOBAL — 全局控制(偏移 0x08),含 RST 软件复位位 uart->BAUD — 波特率寄存器(偏移 0x10) uart->STAT — 状态寄存器(偏移 0x14) uart->CTRL — 控制寄存器(偏移 0x18) uart->DATA — 数据寄存器(偏移 0x1C) uart->MATCH — 地址匹配寄存器(偏移 0x20) uart->MODIR — 调制/红外寄存器(偏移 0x24) uart->FIFO — FIFO 控制寄存器(偏移 0x28) uart->WATER — FIFO 水位线寄存器(偏移 0x2C)
每个寄存器都有两种访问方式:
uart->BAUD.WORDVAL // 整体 32-bit 读写 uart->BAUD.BIT.SBR // 按位域读写(SBR = 波特率分频系数,13-bit)
API 函数命名规范
SDK 的 UART API 遵循统一前缀 UART_ + 动作 + 功能:
UART_功能: enableModule / disableModule — 同时使能收发 enableTxModule / disableTxModule — 只控发送 enableRxModule / disableRxModule — 只控接收 resetModule — 软件复位模块 setBaud — 设置波特率 setBitCountPerChar — 数据位长度(7/8/9/10) setParityMode — 校验模式(无/奇/偶) setStopBitCount — 停止位(1或2) setMSB — 位序 MSB/LSB enableTxFifo / disableTxFifo — TX FIFO 使能 enableRxFifo / disableRxFifo — RX FIFO 使能 resetTxFifo / resetRxFifo — FIFO 复位 setTxFifoWatermark — TX 水位线 setRxFifoWatermark — RX 水位线 writeChar / readChar — 8-bit 读写 writeChar9 / readChar9 — 9-bit 读写(含校验位) writeChar10 / readChar10 — 10-bit 读写 getStatusFlag — 读取状态标志 clearStatusFlag — 清除状态标志 clearErrorFlags — 批量清除错误标志 enableInterrupt / disableInterrupt — 中断源使能/关闭
GPIO 引脚命名
工程涉及的 GPIO 和复用功能命名:
RX 引脚: GPIO_39 — GPIO 编号(芯片引脚索引) GPIO_39_SCIB_RX — 复用功能名(将该引脚配置为 SCIB 的 RX) GPIO_DIR_MODE_IN — 方向:输入 GPIO_QUAL_SYNC — 输入同步采样(1次) TX 引脚: GPIO_38 — GPIO 编号 GPIO_38_SCIB_TX — 复用功能名(SCIB 的 TX) GPIO_DIR_MODE_OUT — 方向:输出 GPIO_DRV_MAX — 最大驱动能力 GPIO_PIN_TYPE_STD — 标准驱动(无上拉)
状态标志命名(STAT 寄存器位)
UART_FRAME_ERR — 帧错误(FE) UART_NOISE_DETECT — 噪声检测(NF) UART_PARITY_ERR — 校验错误(PF) UART_RX_OVERRUN — 接收溢出(OR) UART_IDLE_LINE_DETECT — 空闲线检测(IDLE) UART_TX_COMPLETE — 发送完成(TC) UART_TX_DATA_REG_EMPTY — 发送寄存器空(TDRE) UART_RX_DATA_REG_FULL — 接收寄存器满(RDRF) UART_RX_ACTIVE — 接收进行中(RAF)
命名体系与 STM32 HAL 风格接近,上下文清晰的缩写(如 TE=Transmitter Enable, RE=Receiver Enable)减少了长命名带来的冗余。
学习以上的一些知识后,开始配置工程。此次实验采用uart2来进行。因为uart1是日志打印。
【实现功能】
UART2 轮询(Polling)模式收发数据
波特率 230400,8N1(8数据位、无校验、1停止位)
收发各 10 字节随机数据,循环运行
【整体初始化流程】
int main(void)
{
Device_init();
// 1. 初始化设备时钟和外设
Device_unlockPeriphReg();
// 2. 解锁外设寄存器锁
Board_init();
// 3. 初始化板级资源(LED、按键、串口引脚等)
uart_init(uart);
// 4. UART2 初始化
...
}Device_init()
系统级外设初始化,具体实现位于 SDK 内部 CMSIS 层,负责时钟管理和外设使能。
Device_unlockPeriphReg()
NS800RT7P65 某些外设寄存器有锁保护,调用此函数解除锁定后才能配置。
Board_init()
板级初始化,在 board.c 中定义,会依次调用:
PinMux_init() — 配置引脚复用 LED_init() — 初始化 LED(GPIO_68 / GPIO_69) Switch_init() — 初始化按键(GPIO_41) SerialCOM_init() — 初始化调试串口(UART1,波特率 115200)
【UART2 引脚配置】
NS800RT7P65 的 UART2(SCIB)使用两组引脚,本工程选用:

RX 引脚配置(GPIO_39)
GPIO_setPinConfig(GPIO_39_SCIB_RX); // 配置为 SCIB_RX 复用功能 GPIO_setAnalogMode(GPIO_39, GPIO_ANALOG_DISABLED); // 关闭模拟功能(数字模式) GPIO_setPadConfig(GPIO_39, GPIO_PIN_TYPE_PULLUP); // 上拉电阻 GPIO_setQualificationMode(GPIO_39, GPIO_QUAL_SYNC); // 同步采样(1次) GPIO_setDirectionMode(GPIO_39, GPIO_DIR_MODE_IN); // 方向为输入
配置解释:
• GPIO_QUAL_SYNC:输入信号经过 1 次同步采样过滤噪声
• GPIO_PIN_TYPE_PULLUP:使能内部上拉,悬空时保持确定电平
【TX 引脚配置】
GPIO_setPinConfig(GPIO_38_SCIB_TX); // 配置为 SCIB_TX 复用功能 GPIO_setAnalogMode(GPIO_38, GPIO_ANALOG_DISABLED); // 关闭模拟功能 GPIO_setPadConfig(GPIO_38, GPIO_PIN_TYPE_STD); // 标准驱动(无上拉) GPIO_setDriveLevel(GPIO_38, GPIO_DRV_MAX); // 最大驱动强度 GPIO_setDirectionMode(GPIO_38, GPIO_DIR_MODE_OUT); // 方向为输出
配置解释:
• GPIO_DRV_MAX:TX 引脚使用最大驱动能力,确保长距离通信信号完整性
• GPIO_DIR_MODE_OUT:TX 为输出信号
【UART2 通信参数配置】
1、模块复位
UART_resetModule(uart); // 复位 UART2 模块
在配置波特率和其他参数之前,建议先复位模块,确保寄存器处于已知状态。
2、波特率设置
UART_setBaud(uart, 230400); // 波特率 230400 bps
SDK 通过内部算法根据系统时钟自动计算 BAUD 寄存器的分频系数。
3、数据位长度
// 无校验时(8N1) UART_setBitCountPerChar(uart, UART_8_BITS_PER_CHAR, false ); // 有校验时(8位数据 + 1位奇偶校验 = 9位) UART_setBitCountPerChar(uart, UART_8_BITS_PER_CHAR, true );
第二个参数 true 表示使能校验位传输(共 9 位),false 表示无校验(共 8 位)
4、 校验模式(条件编译)
#if ENABLE_PARITY UART_setParityMode(uart, UART_PAR_ODD); // 奇校验#else // 无校验模式#endif
本次 ENABLE_PARITY = 0,默认不使能校验。
5、停止位
UART_setStopBitCount(uart, UART_ONE_STOP_BIT); // 1 位停止位
可选 UART_TWO_STOP_BIT(2 位停止位)。
6 、位序(MSB/LSB)
UART_setMSB(uart, false); // false = LSB 先发,true = MSB 先发
默认 LSB 低位优先,符合大多数 UART 通信习惯。
7、 FIFO 配置(条件编译)
#if ENABLE_FIFO UART_enableTxFifo(uart); UART_resetTxFifo(uart); UART_setTxFifoWatermark(uart, UART_FIFO_TX6); // 6/16 深度触发中断 UART_enableRxFifo(uart); UART_resetRxFifo(uart); UART_setRxFifoWatermark(uart, UART_FIFO_RX6); UART_setRxIdleCharacter(uart, UART_IDLE_CHARACTER_CNT1); #endif
本次 ENABLE_FIFO = 0,不使能 FIFO,采用直接寄存器收发。
8 、收发使能
UART_enableTxModule(uart); // 使能发送器 UART_enableRxModule(uart); // 使能接收器
【轮询模式数据收发】
1、 接收函数 UART_receiveDataPolling()
1. UART_resetRxFifo(uart) // 清空接收 FIFO/Buffer 2. UART_clearErrorFlags(...) // 清除错误标志(溢出、噪声、帧错误、校验错误) 3. UART_enableRxModule(uart) // 使能接收器 4. 循环等待 UART_FIFO_RX0 变为非空(RX FIFO 有数据) 5. UART_readChar(uart) // 读取一个字节 6. 检查各类错误标志,异常时退出 7. 返回 0 表示成功,返回 1 表示失败
关键状态标志检查:
• UART_FRAME_ERR — 帧错误(停止位不符)
• UART_NOISE_DETECT — 噪声检测
• UART_PARITY_ERR — 校验错误
• UART_RX_OVERRUN — 接收溢出(数据覆盖)
2、 发送函数 UART_sendDataPolling()
1. UART_resetTxFifo(uart) // 清空发送 FIFO 2. UART_enableTxModule(uart) // 使能发送器 3. 循环 length 次: a. 等待 UART_TX_DATA_REG_EMPTY(非空表示发送寄存器有空间) b. UART_writeChar(uart, array[i]) // 写入一个字节 4. 等待 UART_TX_COMPLETE(发送完毕) 5. UART_disableTxModule(uart) // 关闭发送器节省功耗
【测试代码】
/**
* @file main.c
* @author yangjun
* @brief main function file for NS800RT7xxx.
*
* <h2><center>© Copyright (c) 2024 Novosense Limited.
* All rights reserved.</center></h2>
*/
#include "main.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define DELAY_1S (1000UL)
#define UART_DATA_LENGTH (10UL)
#define ENABLE_PARITY (0UL)
#define ENABLE_FIFO (0UL)
#define STATUS_NO_ERROR (0xFF)
/*******************************************************************************
* Variables
******************************************************************************/
UART_TypeDef *uart = UART2;
uint8_t txBuff[UART_DATA_LENGTH];
uint8_t rxBuff[UART_DATA_LENGTH];
/*******************************************************************************
* Functions Declaration
******************************************************************************/
static void uart_init(UART_TypeDef *uart);
static uint32_t UART_receiveDataPolling(UART_TypeDef* uart, uint8_t *const array, uint16_t length);
static void UART_sendDataPolling(UART_TypeDef* uart, const uint8_t *array, uint16_t length);
/*******************************************************************************
* Functions
******************************************************************************/
/**
* @brief Main function
* @return int Force return 0
*/
int main(void)
{
/* Initialize device clock and peripherals */
Device_init();
/* Disable peripheral register locks */
Device_unlockPeriphReg();
/* Board Initialization
Setup LED pins, Key pins and Serial Communication Interface pins
*/
Board_init();
/* UART Initialization */
uart_init(uart);
/* Debug information printing */
printf("UART ex1 send and receive data by polling mode!\n");
/* Loop indefinitely */
while (1)
{
printf("UART receive data :\n");
// UART_readCharArray(uart, rxBuff, UART_DATA_LENGTH);
if (UART_receiveDataPolling(uart, rxBuff, UART_DATA_LENGTH) == 0)
{
printf("receive success: ");
for (uint32_t i = 0U; i < UART_DATA_LENGTH; i++)
{
printf("0x%02X, ", rxBuff[i]);
}
printf("\n");
}
else
{
printf("receive fail!\n");
}
printf("UART will transmit data :\n");
for (uint32_t i = 0U; i < UART_DATA_LENGTH; i++)
{
txBuff[i] = (uint8_t)rand();
printf("0x%02X, ", txBuff[i]);
}
printf("\n");
// UART_writeCharArray(uart, txBuff, UART_DATA_LENGTH);
UART_sendDataPolling(uart, txBuff, UART_DATA_LENGTH);
}
}
/**
* @brief Initialize uart function
*/
static void uart_init(UART_TypeDef *uart)
{
/* UART2 RX pinmux control */
GPIO_setPinConfig(GPIO_39_SCIB_RX);
GPIO_setAnalogMode(GPIO_39, GPIO_ANALOG_DISABLED);
GPIO_setPadConfig(GPIO_39, GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode(GPIO_39, GPIO_QUAL_SYNC);
GPIO_setDirectionMode(GPIO_39, GPIO_DIR_MODE_IN);
/* UART2 TX pinmux control */
GPIO_setPinConfig(GPIO_38_SCIB_TX);
GPIO_setAnalogMode(GPIO_38, GPIO_ANALOG_DISABLED);
GPIO_setPadConfig(GPIO_38, GPIO_PIN_TYPE_STD);
GPIO_setDriveLevel(GPIO_38, GPIO_DRV_MAX);
GPIO_setDirectionMode(GPIO_38, GPIO_DIR_MODE_OUT);
/* Reset uart before configure it */
UART_resetModule(uart);
/* Set baudrate */
UART_setBaud(uart, 230400);
#if ENABLE_PARITY
/* Set the number of bits per char in UART controller */
UART_setBitCountPerChar(uart, UART_8_BITS_PER_CHAR, true);
/* Sets the type of parity */
UART_setParityMode(uart, UART_PAR_ODD);
#else
/* Set the number of bits per char in UART controller */
UART_setBitCountPerChar(uart, UART_8_BITS_PER_CHAR, false);
#endif
/* Set the number of stop bits */
UART_setStopBitCount(uart, UART_ONE_STOP_BIT);
/* Set MSB bit reverses the order of the bits */
UART_setMSB(uart, false);
#if ENABLE_FIFO
/* Config tx fifo */
UART_enableTxFifo(uart);
UART_resetTxFifo(uart);
UART_setTxFifoWatermark(uart, UART_FIFO_TX6);
/* Config rx fifo */
UART_enableRxFifo(uart);
UART_resetRxFifo(uart);
UART_setRxFifoWatermark(uart, UART_FIFO_RX6);
UART_setRxIdleCharacter(uart, UART_IDLE_CHARACTER_CNT1);
#endif
/* Enable transmitter */
UART_enableTxModule(uart);
/* Enable receiver */
UART_enableRxModule(uart);
}
/**
* @brief Receive multiple bytes of data using polling method.
* @return Return 0 if reception is successful, 1 if reception fails.
*/
uint32_t UART_receiveDataPolling(UART_TypeDef* uart, uint8_t *const array, uint16_t length)
{
uint16_t i;
uint32_t status = STATUS_NO_ERROR;
uint32_t retval = 0;
/* Flush receive FIFO/Buffer */
UART_resetRxFifo(uart);
/* Clear the error flags */
UART_clearErrorFlags(uart, UART_STAT_OR_M | UART_STAT_NF_M | UART_STAT_FE_M | UART_STAT_PF_M);
/* Enable receiver */
UART_enableRxModule(uart);
for (i = 0; i < length; i++)
{
/* Wait until a character is available in UART receiver */
while (UART_getRxFifoStatus(uart) == UART_FIFO_RX0);
/* Read a character from UART receiver */
array[i] = UART_readChar(uart);
if (UART_getStatusFlag(uart, UART_FRAME_ERR))
{
status = UART_FRAME_ERR;
/* Disable the UART receiver */
UART_disableRxModule(uart);
/* Clear the flag */
UART_clearStatusFlag(uart, UART_FRAME_ERR);
}
if (UART_getStatusFlag(uart, UART_NOISE_DETECT))
{
status = UART_NOISE_DETECT;
/* Disable the UART receiver */
UART_disableRxModule(uart);
/* Clear the flag */
UART_clearStatusFlag(uart, UART_NOISE_DETECT);
}
if (UART_getStatusFlag(uart, UART_PARITY_ERR))
{
status = UART_PARITY_ERR;
/* Disable the UART receiver */
UART_disableRxModule(uart);
/* Clear the flag */
UART_clearStatusFlag(uart, UART_PARITY_ERR);
}
if (UART_getStatusFlag(uart, UART_RX_OVERRUN))
{
status = UART_RX_OVERRUN;
/* Disable the UART receiver */
UART_disableRxModule(uart);
/* Clear the flag */
UART_clearStatusFlag(uart, UART_RX_OVERRUN);
}
if (status != 0xFF)
{
break;
}
}
if ((i == length) && ((status == UART_RX_OVERRUN) || status == STATUS_NO_ERROR))
{
retval = 0;
/* Disable the UART receiver */
UART_disableRxModule(uart);
}
else
{
retval = 1;
}
/* Read dummy to clear RDRF flag */
while (UART_getStatusFlag(uart, UART_RX_DATA_REG_FULL))
{
(void)UART_readChar(uart);
}
return retval;
}
/**
* @brief Send out multiple bytes of data using polling method.
*/
void UART_sendDataPolling(UART_TypeDef* uart, const uint8_t *array, uint16_t length)
{
/* Flush transmit FIFO/Buffer */
UART_resetTxFifo(uart);
/* Enable the UART transmitter */
UART_enableTxModule(uart);
for (uint16_t i = 0; i < length; i++)
{
/* Wait until space is available in UART transmitter */
while (!UART_getStatusFlag(uart, UART_TX_DATA_REG_EMPTY));
/* Send a character to UART transmitter */
UART_writeChar(uart, array[i]);
}
/* Wait until transmission completes */
while (!UART_getStatusFlag(uart, UART_TX_COMPLETE));
/* Disable the UART transmitter */
UART_disableTxModule(uart);
}【测试】
使用一个TTL转USB接到开发板的GPIO38 GPIO39,打开串口助手:

可以看到通过UART2一次发送10字符,在UART1上打印,并回传给UART2。
我要赚赏金
