nRF52开发笔记

在GNU toolchain中更改UICR配置

SES环境使能CONFIG_NFCT_PINS_AS_GPIOS为例。仅仅在预编译宏中添加CONFIG_NFCT_PINS_AS_GPIOS宏定义是无效的。需要修改linker文件。

这里,我们需要在0x1000120C地址写入0xFFFFFFFE。首先在linker文件的MEMORY段中定义这个地址如下:

UICR_NFC_MEM (r) :  ORIGIN = 0x1000120C, LENGTH = 0x04

然后新建一个SECTIONS描述如下:

SECTIONS
{
  .uicr_nfc :
  {
    KEEP(*(.uicr_nfc))
  } > UICR_NFC_MEM
}

接下来我们在一个确定会编译的c文件中加入如下代码,一般我们放在main.c中:

#ifdef CONFIG_NFCT_PINS_AS_GPIOS
	volatile uint32_t UICR_ADDR_0x20C __attribute__((section("uicr_nfc"))) = 0xFFFFFFFE;
#endif

其中,变量名可以随意定义。宏定义也非必须。

最后,我们对芯片执行全部擦除,然后项目执行rebuild,之后再烧录就可以正常写入UICR配置了。


设置最大MTU与开启扩展广播

指定#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247宏开启最大MTU

advertising_init()中添加init.config.ble_adv_extended_enabled = true;配置即可直接使能扩展广播


nRF52从机发送缓冲区溢出报错

BLE从机发送缓冲区溢出会导致发送中断,并在下一次发送时发生断开。需要捕获和处理报错。

可以额外添加一级缓冲,并对超出缓冲区的部分做丢弃处理。


nRF52 广播包拼接

m_advertising.adv_data.adv_data.len与其中EIR长度之和不等时,发生的解析错误可能将相邻广播包连接起来。

其机制还需进一步分析了解。


nRF52 蓝牙更新广播信息

使用ble_advertising_advdata_update更新广播信息时。

在广播开启时,更改内容实时生效,更改广播长度在下一次开启广播时生效


nRF52连接间隔与通信带宽问题

  • CSW-V1上,在250ms连接间隔下,使用request方式通信只能达到2Hz左右的频率。
  • CSW-V1上,在250ms连接间隔下,使用command方式通信,延迟在1-2个连接间隔。
  • CSW-B5上,在250ms连接间隔下,使用command方式通信,延迟在几十ms之内,且在80ms内即返回了24个数据包。同时,测试功耗没有异常。

更改gap_conn_cfg.event_length16可实现每个连接间隔可返回20+个数据包

gap_conn_cfg.event_length默认值为3,其为一个以1.25ms为单位的窗口时间,每个连接间隔能够通信的时长由这个窗口的时间决定。


蓝牙在有效距离内易断开

断开原因为:0x08(timeout)

考虑调整晶振精度参数,降低精度要求:比如从20ppm改为50ppm

参考资料: https://devzone.nordicsemi.com/f/nordic-q-a/29786/ble_hci_connection_timeout-and-nrf_clock_lf_xtal_accuracy_xx_ppm/118161#118161


nRF52接仿真器能运行接电源不能运行

可能原因有:

  1. 软件使能了 DCDC,但硬件未有外部 DCDC 电路。关闭 DCDC 可修复。
  2. printf 重定向问题。Case ID: 207373

nRF52 FDS库在o2优化等级报错

问题: 在o2优化等级下,被写入的数据指针会有非 word 对齐的情况,此时会报错。

解决: 对需要使用 fds 写入的数据均使用强制 word 对齐。在 SES 中可使用__ALIGN(4)


nRF52 使用P0.21作为IO口

编译时更改

去掉CONFIG_GPIO_AS_PINRESET宏,重新完全编译。 使用nrfjrog -eraseuicr擦除 UICR 区域。因为使用 IDE 烧录是不会主动擦除 UICR 的,会导致 reset 引脚的配置没有改变。

发行后更改

使用如下函数可以禁用UICR中的reset引脚复位功能。

/** Function to disable pin reset by writing an invalid configuration (all 0) to PSELRESET[1] */
static void disable_pin_reset(void)
{
    // Only perform if needed (which is the first time this code runs)
    if (NRF_UICR->PSELRESET[1] != 0)
    {
        NRF_LOG_INFO("Disabling pin reset.");

        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}

        NRF_UICR->PSELRESET[1] = 0;

        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}

        // System reset is needed to update UICR registers.
        NVIC_SystemReset();
    }
}

nRF52 I2S驱动WS2812

参考: https://electronut.in/nrf52-i2s-ws2812

  • sck引脚功能被占据时,会导致除lrck引脚外的其他引脚输出异常。而lrck仍能正常输出时钟信号。
  • I2S 的驱动使用了双缓冲方式。在第二缓冲未设置时,会产生NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED事件回调。
  • 实现单次输出 WS2812 驱动波形的方式如下:
    1. i2s start
    2. 第一次会在输出第一个时钟周期时产生NEXT_BUFFER事件,在这里设置第二缓冲
    3. 当第一缓冲输出至最后一个时钟周期时,驱动自动切换至第二缓冲,此时会产生第二次NEXT_BUFFER事件,以此作为波形输出结束的标志。在此时关闭i2s输出
  • 在波形最后添加一个0x00000000的填充,就可以避免有效数据被剪切掉。
  • I2S输出高4位与低4位需要交换才能与 WS2812 的数据一致。
    • 如:I2S 写入 0x8888E888 则 WS2812 收到 0x80