The SPIM3 module of the nrf52840 causes the app_timer to fail to trigger after communication, and this issue only affects timers that are triggered once. Timers that are triggered repeatedly are not affected;

If I call app_timer_stop(ble_recv_timeout_id) before starting the timer, the system will crash after running at most 7 times:

#include "spim_app.h"
// #include "all_file_header.h"
#include "nrfx_spim.h"
#include "nrf_spim.h"
#include "nrf_drv_spi.h"
#include "nrf_qspi.h"
#include "nrf_gpio.h"
#include "nrf_gpiote.h"
#include "gpio_app.h"

#include "app_util_platform.h"
#include "nrf_drv_gpiote.h"
#include "nrf_delay.h"
#include "nrf_soc.h"
#include "app_error.h"
#include <stdbool.h>
#include <string.h>

#include "gh_demo.h"

/*log打印的头文件*/
#include "nrf_log.h"
#include "nrf_drv_ppi.h"
#include "uart_app.h"
#include "app_sys.h"
#include "app_task_id.h"
#include "gh_demo_config.h"

#define SPIM_PIN_INIT(_pin) nrf_gpio_cfg((_pin),                        \
                                         NRF_GPIO_PIN_DIR_OUTPUT,       \
                                         NRF_GPIO_PIN_INPUT_DISCONNECT, \
                                         NRF_GPIO_PIN_NOPULL,           \
                                         NRF_GPIO_PIN_H0H1,             \
                                         NRF_GPIO_PIN_NOSENSE)

/**************************************************************************/
#define SPIM_TX_BUF_LEN (1024 * 2)
#define SPIM_RX_BUF_LEN (1024 * 3)

uint8_t SPIM_TX_BUF[SPIM_TX_BUF_LEN] = {0};
uint8_t SPIM_RX_BUF[SPIM_RX_BUF_LEN] = {0};

/*SPIM3可以达到32M,840只有SPIM3支持外部扩展功能,就是外部DCX控制功能*/
static nrfx_spim_t m_spim = NRFX_SPIM_INSTANCE(3);
static volatile bool g_spim_xfer_done = false;

/*同时设置TX和RX的buffer*/
// nrfx_spim_xfer_desc_t m_buffer = NRFX_SPIM_XFER_TRX(SPIM_TX_BUF, SPIM_TX_BUF_LEN, SPIM_RX_BUF, SPIM_RX_BUF_LEN);

/**
 * @brief SPI user event handler.
 * @param event
 */
void spim_event_handler(nrfx_spim_evt_t const *p_event,
                        void *p_context)
{
    if (p_event->type == NRFX_SPIM_EVENT_DONE)
    {
        g_spim_xfer_done = true;
    }
}

void spim_hal_init(void)
{
    /*不能使用低频引脚,还要配置为高驱*/
    nrfx_spim_config_t spim_config = NRFX_SPIM_DEFAULT_CONFIG;

    spim_config.ss_pin = DVC_SPIM_PIN_CS;
    spim_config.miso_pin = DVC_SPIM_PIN_MISO; // 如果是刷屏可以不使用MISO数据pin脚,可以设置为 NRFX_SPIM_PIN_NOT_USED
    spim_config.mosi_pin = DVC_SPIM_PIN_MOSI;
    spim_config.sck_pin = DVC_SPIM_PIN_CLK;

    // 配置SPI参数
    spim_config.irq_priority = APP_IRQ_PRIORITY_LOW_MID;
    spim_config.frequency = NRF_SPIM_FREQ_16M;            // SPI时钟频率
    spim_config.ss_active_high = false;                   ///< Polarity of the Slave Select pin during transmission.
    spim_config.mode = NRF_SPIM_MODE_0;                   // SPI模式0 (CPOL=0, CPHA=0)
    spim_config.bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST; // 高位在前

    SPIM_PIN_INIT(DVC_SPIM_PIN_RESET);
    SPIM_PIN_INIT(DVC_SPIM_PIN_CS);
    SPIM_PIN_INIT(DVC_SPIM_PIN_CLK);
    SPIM_PIN_INIT(DVC_SPIM_PIN_MOSI);
    // SPIM_PIN_INIT(DVC_SPIM_PIN_DCX);
    // SPIM_PIN_INIT(DVC_SPIM_PIN_MISO);

    APP_ERROR_CHECK(nrfx_spim_init(&m_spim, &spim_config, spim_event_handler, NULL));

    /*初始化用户需要的引脚*/
    nrf_gpio_cfg_output(DVC_SPI_PIN_USER_CS);
    nrf_gpio_pin_write(DVC_SPI_PIN_USER_CS, 1); // 默认拉高

    /*PWOER PIN*/
    nrf_gpio_cfg_output(DVC_POWER_PIN_USER);
    nrf_gpio_pin_write(DVC_POWER_PIN_USER, 1); // 默认拉高

    LOG("SPIM init end.");
}

void spim_int_pin_cb(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    // user_hal_red_on();
    hal_gh3x2x_int_handler_call_back();
    app_sys_ppg_int_flag_set();
}

void spim_user_int_pin_init(void)
{
    gpio_app_init_pin(DVC_INT_PIN_USER_INT, GPIO_APP_LOTOHI_MODE, GPIO_APP_PULL_DOWN, spim_int_pin_cb);
    LOG("INT PIN init end");
}

void spim_user_reset_pin_init(void)
{
    nrf_gpio_cfg_output(DVC_SPI_PIN_USER_RESET);
    nrf_gpio_pin_write(DVC_SPI_PIN_USER_RESET, 1); // 默认拉高
    LOG("RESET PIN init end");
}

void spim_user_cs_write(uint8_t level)
{
    nrf_gpio_pin_write(DVC_SPI_PIN_USER_CS, level);
}
void spim_user_reset_write(uint8_t level)
{
    nrf_gpio_pin_write(DVC_SPI_PIN_USER_RESET, level);
}

// 等待直到SPIM空闲
void wait_until_spim_ready(void)
{
    // 等待传输完成,同时允许 SoftDevice 处理事件
    while (!g_spim_xfer_done)
    {
        sd_app_evt_wait();
    }
    g_spim_xfer_done = false;
}
// 发送单个字节函数
void spim_send_single_byte(uint8_t data)
{
    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_SINGLE_XFER(&data, 1, NULL, 0);

    // 执行SPI传输 (只发送,不接收)
    g_spim_xfer_done = false;
    nrfx_err_t err_code = nrfx_spim_xfer(&m_spim, &xfer_desc, 0);
    APP_ERROR_CHECK(err_code);
    wait_until_spim_ready();
}

// 发送多个连续字节函数
void spim_send_multiple_bytes(uint8_t *header, uint32_t h_len, uint8_t *data, uint32_t length)
{
    uint32_t idx = 0;

    // 检查数据长度是否超出缓冲区大小
    if ((h_len + length) > SPIM_TX_BUF_LEN)
    {
        LOG_D_ERR("Err Spi RL");
        return;
    }
    if (header != NULL && h_len > 0)
    {
        memcpy(&SPIM_TX_BUF[idx], header, h_len);
        idx += h_len;
    }

    // 将数据复制到发送缓冲区
    memcpy(&SPIM_TX_BUF[idx], data, length);

    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_SINGLE_XFER(SPIM_TX_BUF, length + h_len, NULL, 0);

    // wait_until_spim_ready();

    // 执行SPI传输
    g_spim_xfer_done = false;
    nrfx_err_t err_code = nrfx_spim_xfer(&m_spim, &xfer_desc, 0);
    APP_ERROR_CHECK(err_code);
    wait_until_spim_ready();
}

// 接收多个字节
uint8_t spim_read_multiple_bytes(uint8_t *rx_data, uint32_t length)
{
    if (length > SPIM_RX_BUF_LEN)
    {
        LOG_D_ERR("Err Spi TL");
        return 1;
    }

    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_SINGLE_XFER(NULL, 0, SPIM_RX_BUF, length);

    g_spim_xfer_done = false;
    nrfx_err_t err_code = nrfx_spim_xfer(&m_spim, &xfer_desc, 0);
    APP_ERROR_CHECK(err_code);

    wait_until_spim_ready();

    // 将接收到的数据复制到输出缓冲区
    memcpy(rx_data, SPIM_RX_BUF, length);
    return 0;
}

// 同时发送和接收多个字节(全双工)
void spim_transfer_full_duplex(uint8_t *tx_data, uint8_t *rx_data, uint32_t length)
{
    if (length > SPIM_TX_BUF_LEN || length > SPIM_RX_BUF_LEN)
    {
        return;
    }

    memcpy(SPIM_TX_BUF, tx_data, length);

    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_SINGLE_XFER(SPIM_TX_BUF, length, SPIM_RX_BUF, length);

    g_spim_xfer_done = false;
    nrfx_err_t err_code = nrfx_spim_xfer(&m_spim, &xfer_desc, 0);
    APP_ERROR_CHECK(err_code);

    wait_until_spim_ready();

    // 将接收到的数据复制到输出缓冲区
    memcpy(rx_data, SPIM_RX_BUF, length);
}

this is my timer code:

#include "timer_app.h"
#include "app_task_id.h"

/**
 _____    _____   _____        _____   _       ___  ___   _____   _____
|  _  \  |_   _| /  ___|      |_   _| | |     /   |/   | | ____| |  _  \
| |_| |    | |   | |            | |   | |    / /|   /| | | |__   | |_| |
|  _  /    | |   | |            | |   | |   / / |__/ | | |  __|  |  _  /
| | \ \    | |   | |___         | |   | |  / /       | | | |___  | | \ \
|_|  \_\   |_|   \_____|        |_|   |_| /_/        |_| |_____| |_|  \_\
*/

APP_TIMER_DEF(m_sorft_timer_tmr);
APP_TIMER_DEF(ble_recv_timeout_id);
APP_TIMER_DEF(ble_slow_send_timeout_id);

static nrf_drv_wdt_channel_id m_channel_id;

static uint8_t br_timer_cb_flag = 0;
static uint8_t bs_timer_cb_flag = 0;

/*******************/
/**
 *
 */
static void ble_recv_timer_handle(void *p_context)
{
    br_timer_cb_flag = 1;
    LOG_I_RTT("ble recv timeout\n");
}
static void ble_slow_send_timer_handle(void *p_context)
{
    bs_timer_cb_flag = 1;
}

static void app_sys_sorft_timer_cb(void *p_context)
{
    st_timer_tick_flag = 1;
}

/**@brief Function for initializing the timer module.
 */
void timers_init(void)
{
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
}

void timer_app_init(void)
{
    ret_code_t err_code;
    st_sorft_timer_init();
    timers_init();

    err_code = app_timer_create(&m_sorft_timer_tmr, APP_TIMER_MODE_REPEATED, app_sys_sorft_timer_cb);
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_create(&ble_recv_timeout_id, APP_TIMER_MODE_SINGLE_SHOT, ble_recv_timer_handle);
    APP_ERROR_CHECK(err_code);
    err_code = app_timer_create(&ble_slow_send_timeout_id, APP_TIMER_MODE_SINGLE_SHOT, ble_slow_send_timer_handle);
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_start(m_sorft_timer_tmr, APP_TIMER_TICKS(100), NULL);
    APP_ERROR_CHECK(err_code);

}

void timer_app_ble_data_recv_timeout_start(uint32_t time)
{
    app_timer_stop(ble_recv_timeout_id);

    app_timer_start(ble_recv_timeout_id, APP_TIMER_TICKS(time), NULL);

    LOG_I_RTT("ble recv timeout start:%d\n", APP_TIMER_TICKS(time));
}

void timer_app_ble_slow_send_timeout_start(uint32_t time)
{
    // app_timer_stop(ble_slow_send_timeout_id);
    app_timer_start(ble_slow_send_timeout_id, APP_TIMER_TICKS(time), NULL);
}

void timer_app_stop_all(void)
{
    // app_timer_stop(ble_recv_timeout_id);
    // app_timer_stop(ble_slow_send_timeout_id);
}

/**************************************************/
/****************  TIMER PROCESS ******************/
/**************************************************/

void timer_all_process(void)
{

    if (br_timer_cb_flag)
    {
        app_task_ble(0);
        br_timer_cb_flag = 0;
    }
    if (bs_timer_cb_flag)
    {
        bs_timer_handlw();
        bs_timer_cb_flag = 0;
    }
}

  • Hello,

    It's been a long time since nRF5 SDK , so it might be that you trigger an unknown issue here, if you start and stop timers very quickly, so you may need to try to avoid that. That said, you can try to set MAX_RTC_TASKS_DELAY 100 (instead of 47) in \components\libraries\timer\app_timer.c. I do remember that the default value was a bit too optimistic.

    I am not sure if you are using the APP_TIMER_CONFIG_USE_SCHEDULER, you can see if that helps.

    Also try to increase APP_TIMER_CONFIG_OP_QUEUE_SIZE in case that has an impact and enable APP_TIMER_KEEPS_RTC_ACTIVE.

    Kenneth

Related