nordic开发经验

1,nordic和stm32不一样,应用程序和协议栈要分开来下载,步骤明确,要先下载BLE协议栈代码。

是的,你的理解完全正确。

Nordic 协议栈架构

┌─────────────────────────────────────────┐
│  nRF52840/5340 Flash 布局               │
├─────────────────────────────────────────┤
│  0x0000_0000 - 0x0002_6000 (152KB)      │
│  ┌─────────────────────────────────┐    │
│  │  SoftDevice (S140 v7.x)         │    │
│  │  • BLE 协议栈(不可修改)         │    │
│  │  • 烧录到固定地址,只读           │    │
│  │  • Nordic 提供 hex/bin 文件       │    │
│  └─────────────────────────────────┘    │
├─────────────────────────────────────────┤
│  0x0002_6000 - 0x000F_8000 (848KB)      │
│  ┌─────────────────────────────────┐    │
│  │  Application Code (你的代码)      │    │
│  │  • main.c                       │    │
│  │  • SPI 驱动                      │    │
│  │  • CCC OOB 协议实现              │    │  ← 只改这里
│  │  • UWB 参数协商逻辑               │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

关键要点

项目 说明
SoftDevice 地址 固定 0x0000_0000,不可更改
SoftDevice 是否可修改 ❌ 不可修改,Nordic 封闭源码
Application 起始地址 由 SoftDevice 头文件自动配置(通常是 0x26000
你需要编写的代码 仅 Application 层
UWB 参数协商 在 Application 中实现,通过 API 调用 SoftDevice

代码结构示意

// 你的代码(Application)- 需要编写
#include "nrf_sdh.h"           // SoftDevice 头文件(Nordic 提供)
#include "nrf_sdh_ble.h"       // BLE API(调用 SoftDevice)
#include "ble_gap.h"           // GAP API

// UWB 参数协商 - 你的实现
void ccc_uwb_negotiation(void) {
    // 1. 调用 SoftDevice API 发送 BLE 数据
    sd_ble_gattc_write(conn_handle, &write_params);
    
    // 2. 处理收到的 UWB 配置(你的解析逻辑)
    parse_uwb_config(notification_data);
    
    // 3. 通过 SPI 上报 STM32(你的驱动)
    spi_send_to_stm32(uwb_config);
}

开发流程

1. 下载 SoftDevice hex 文件到 0x0000_0000
   (使用 nRF Connect Programmer 或 J-Link)
   
2. 编写你的 Application 代码
   
3. 编译链接,生成 Application hex
   (起始地址自动从 0x26000 开始)
   
4. 下载 Application 到 0x0002_6000
   
5. 运行:SoftDevice 初始化 → 跳转到 Application

一句话总结

SoftDevice 是固定烧录的"黑盒子",你只需编写 Application 代码,通过 Nordic 提供的 API 调用 BLE 功能,UWB 参数协商完全在 Application 中实现。

2,开发环境搭建
https://blog.csdn.net/qq_36347513/article/details/103531213

清风电子社区
http://www.qfv8.com/forum.php?mod=forumdisplay&fid=53

SPI从机调试
nodic52832提供作为SPI从机的能直接跑通的代码了吗
有,Nordic 官方 SDK 里已经带了可直接编译跑通的 SPI 从机(SPIS)示例,nRF52832 可以直接用。

1. 官方示例位置(nRF5 SDK)

以常用的 nRF5 SDK v17.1.0 为例:

examples/peripheral/spis/
  • 工程:pca10040(nRF52832 DK)
  • 编译:Keil / GCC / SES 均可直接编译
  • 依赖:开启 SPIS_ENABLEDSPIS0_ENABLED,无需其他外设

2. 极简可直接跑通代码(基于 SDK)

#include "nrf_drv_spis.h"
#include "nrf_log.h"
#include "app_error.h"

#define SPIS_INSTANCE 0
static const nrf_drv_spis_t m_spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);

// 缓冲区(必须全局/静态,RAM)
static uint8_t m_tx_buf[16] = {0x11,0x22,0x33,0x44};
static uint8_t m_rx_buf[16];

// 事件回调:传输完成
static void spis_event_handler(nrf_drv_spis_event_t event)
{
    if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
    {
        NRF_LOG_INFO("RX: %d bytes", event.rx_amount);
        // 重新设置缓冲区,准备下一次传输
        APP_ERROR_CHECK(nrf_drv_spis_buffers_set(
            &m_spis, m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_rx_buf)));
    }
}

// SPI从机初始化
static void spis_init(void)
{
    nrf_drv_spis_config_t cfg = NRF_DRV_SPIS_DEFAULT_CONFIG;
    cfg.csn_pin  = 4;   // CSN
    cfg.miso_pin = 5;   // MISO
    cfg.mosi_pin = 6;   // MOSI
    cfg.sck_pin  = 7;   // SCK
    cfg.mode     = NRF_DRV_SPIS_MODE_0; // 与主机一致
    cfg.bit_order = NRF_DRV_SPIS_BIT_ORDER_MSB_FIRST;

    APP_ERROR_CHECK(nrf_drv_spis_init(&m_spis, &cfg, spis_event_handler));

    // 第一次设置缓冲区
    APP_ERROR_CHECK(nrf_drv_spis_buffers_set(
        &m_spis, m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_rx_buf)));
}

int main(void)
{
    // 初始化日志、时钟等
    NRF_LOG_INIT(NULL);
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    spis_init();

    while (1)
    {
        __WFE(); // 休眠,等待SPI传输
    }
}

3. 关键配置(sdk_config.h)

#define SPIS_ENABLED 1
#define SPIS0_ENABLED 1
#define NRF_LOG_ENABLED 1

4. 常见坑(直接能跑的前提)

  1. 缓冲区必须全局/静态(不能栈上),否则 DMA 会硬fault。
  2. 模式/位序与主机一致(CPOL/CPHA、MSB/LSB)。
  3. SoftDevice 不影响 SPIS:S112/S113/S132 均可同时用 SPIS。
  4. DK 引脚:PCA10040 上默认 SPI 引脚是 4/5/6/7,可直接用。

5. 要不要我给你整理一份“nRF52832 SPI 主机+从机”的可直接编译工程包(含 Keil 工程、sdk_config、引脚分配),你直接下载就能烧录测试?

image

蓝牙协商UWB的参数,使用GATT时,UUID是蓝牙的标准SIG中的UUID,还是用户自定义的UUID ?

结论:不是蓝牙 SIG 标准 UUID,必须使用用户自定义 UUID

核心依据

  1. 标准 UUID 定义:查阅蓝牙 SIG 官方《Assigned Numbers》文档,0x2A020x2A030x2A04 均属于 GAP(通用访问配置文件)的标准特征 UUID。

    • 0x2A02:Peripheral Privacy Flag(外设隐私标志)
    • 0x2A03:Reconnection Address(重连接地址)
    • 0x2A04:Peripheral Preferred Connection Parameters(外设首选连接参数)
      这些标准特征是蓝牙协议预留的,用于固定的底层连接管理,绝不能被挪作 UWB 参数协商这种应用层功能,否则会导致协议栈异常。
  2. 行业实践:所有 UWB 相关的蓝牙通信方案(如室内定位、测距配置),在 GATT 层定义服务和特征时,全部使用厂商自定义的 128-bit UUID
    例如,常见的自定义 UUID 格式为 6E4000xx-B5A3-F393-E0A9-E50E24DCCA9E 等厂商特定格式。

正确做法

你需要为你的 UWB 配置服务和特征分配唯一的 128-bit UUID,并确保通信双方的定义一致。

代码示例

// 自定义服务 UUID (示例)
#define UUID_UWB_SERVICE 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
                         0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00

// 自定义特征 UUID (示例)
#define UUID_UWB_CHAR_CONFIG  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
                              0x00, 0x00, 0x00, 0x00, 0xAA, 0x01, 0x00, 0x00
#define UUID_UWB_CHAR_CONTROL 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
                              0x00, 0x00, 0x00, 0x00, 0xAA, 0x02, 0x00, 0x00
#define UUID_UWB_CHAR_RANGING 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
                              0x00, 0x00, 0x00, 0x00, 0xAA, 0x03, 0x00, 0x00

总结

使用标准 UUID 会破坏蓝牙协议栈的正常逻辑,导致设备无法被正确识别或连接异常。请务必使用自定义 UUID 来实现 UWB 参数协商功能

要不要我给你提供一份基于 nRF SDK 的完整 UWB 服务 GATT 初始化代码模板,包含自定义 UUID、属性读写权限和通知配置?

为什么 ble_uuid_t 能同时表示 16-bit 和 128-bit UUID
image

nordic在SPI的读写是怎么实现的 ?和stm32的区别是什么 ?

Nordic(nRF52832)的 SPI 读写,核心是硬件 SPIM/SPIS + EasyDMA + 任务/事件驱动;而 STM32 是SPI 外设 + 独立 DMA + 状态寄存器轮询/中断,两者在寄存器模型、DMA 集成、CS 管理和低功耗适配上差异很大。


一、Nordic SPI 读写实现(nRF52832)

1. 硬件模块:SPI / SPIM / SPIS

  • SPI:基础主机,无 DMA,适合小数据、阻塞式。
  • SPIM:主机 + EasyDMA(核心),自动搬移 RAM ↔ 外设,CPU 只需触发任务、等待事件。
  • SPIS:从机 + EasyDMA,支持双向缓冲。
  • 引脚:SCK、MOSI、MISO、CS(可任意 GPIO 映射)。

2. 读写流程(SPIM + EasyDMA,最常用)

  1. 配置:引脚、模式(CPOL/CPHA)、波特率、位序;注册TX/RX 缓冲区到 EasyDMA。
  2. 触发传输:写 TASKS_START,硬件自动发时钟、从 TXD 缓冲区逐位移出、同时将 MISO 数据移入 RXD 缓冲区。
  3. 完成通知:传输结束触发 EVENTS_END(中断或轮询),CPU 可直接处理 RXD 数据,无需干预移位。
  4. 停止:写 TASKS_STOP,触发 EVENTS_STOPPED

3. 关键寄存器(任务/事件模型)

  • TASKS_START:启动传输(写 1 触发)。
  • EVENTS_END:传输完成(读 1 表示完成)。
  • TXD.MAXCNT/RXD.MAXCNT:DMA 传输长度(1~255 字节)。
  • TXD.PTR/RXD.PTR:DMA 缓冲区地址(需 RAM 区)。

4. 代码示例(阻塞式读写)

nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0);
nrf_drv_spi_config_t cfg = NRF_DRV_SPI_DEFAULT_CONFIG;
cfg.sck_pin  = 5;
cfg.mosi_pin = 6;
cfg.miso_pin = 7;
cfg.cs_pin   = 8; // 硬件CS,或用软件GPIO
nrf_drv_spi_init(&spi, &cfg, NULL, NULL);

uint8_t tx[] = {0x01, 0x02};
uint8_t rx[2];
// 1次全双工传输:发tx、收rx
nrf_drv_spi_transfer(&spi, tx, 2, rx, 2);

二、与 STM32 SPI 的核心区别

1. 架构与模型

  • Nordic任务/事件驱动 + 内置 EasyDMA
    无状态寄存器轮询,CPU 只发“开始”、等“完成”,数据全由 DMA 自动搬移,低功耗友好(传输时 CPU 可休眠)。
  • STM32状态寄存器 + 独立 DMA 控制器
    需轮询 SPI_SR(TXE/RXNE/BSY)或开 DMA 中断;DMA 是独立外设,需额外配置映射、通道、优先级。

2. DMA 集成

  • Nordic EasyDMA
    • 无缝集成 SPI,无需额外 DMA 配置,只需指定缓冲区地址和长度。
    • 支持字节自动打包/解包,仅占用 1 个中断(传输完成)。
    • 限制:缓冲区必须在 RAM(不能是 Flash),长度 ≤255 字节。
  • STM32 DMA
    • 独立外设,需配置 DMA_CCRDMA_CPARDMA_CMAR 等。
    • 支持多通道、多外设共享,长度无严格限制(受内存约束)。
    • 中断多(TC/TE/HT),需手动处理中断标志。

3. 片选(CS/NSS)管理

  • Nordic
    • 硬件 CS:SPIM 可自动拉/拉低 CS,传输时序严格对齐。
    • 软件 CS:任意 GPIO,灵活但需手动控制时序。
  • STM32
    • 硬件 NSS:仅支持主模式下的从机选择输入(多主机),主机输出 NSS 需软件控制。
    • 常用软件 CS:GPIO 模拟,兼容性强但时序需手动保证。

4. 低功耗与中断

  • Nordic
    • 传输时 CPU 可进入 WFE/WFI 休眠,仅 DMA 工作,功耗极低
    • 单中断(EVENTS_END),中断开销小。
  • STM32
    • 传输时 CPU 通常需保持运行(轮询)或开 DMA 中断,休眠支持有限。
    • 中断源多(SPI + DMA),需手动清除标志,开销大。

5. 数据处理

  • Nordic:全双工同步完成,TX/RX 长度必须相等(或忽略 RX)。
  • STM32:支持非对称 TX/RX(如发 1 字节、收 4 字节),需分两次传输或用 DMA 链表。

三、核心差异对照表

维度 Nordic(nRF52832 SPIM) STM32(SPI + DMA)
驱动模型 任务/事件,无轮询 状态寄存器轮询/中断
DMA 内置 EasyDMA,零配置 独立 DMA 控制器,复杂配置
CS 管理 硬件自动/软件 GPIO 仅软件 GPIO(常用)
低功耗 传输时 CPU 可休眠 传输时 CPU 多为运行
中断开销 单中断(传输完成) 多中断(SPI + DMA)
数据长度 ≤255 字节(DMA 限制) 无严格限制(内存决定)
使用难度 简单(API 封装好) 较复杂(寄存器多、配置繁琐)

四、nRF52832 作为 SPI 从机(SPIS)

  • 支持 EasyDMA 双向缓冲,主机发时钟时自动收/发数据。
  • 初始化:nrf_drv_spis_init,配置 SCK、MOSI、MISO、CS(输入)。
  • 传输:主机拉 CS → 发时钟 → SPIS 自动从 TX 缓冲区发数据、收数据到 RX 缓冲区 → 触发 EVENTS_END

要不要我给你一份 nRF52832 作为 SPI 从机(SPIS)的完整初始化+读写代码,可直接编译运行?

posted @ 2026-04-16 18:20  wzm888  阅读(19)  评论(0)    收藏  举报