nRF5 SDK is not maintained anymore
More Info: Consider nRF Connect SDK for new designs
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

NRF_ERROR_BUSY at TWI embedded code

Hello,

Now I am making an original ISP4520(nRF52832) application using ISP4520-examples.

I'm trying to embed LM75B sample code from nRF5_SDK_16.0.0_98a08e2 to Class_A.emProject.

I paste my source code below. To find out where the error occurred, unrelated code is commented out.

// Standards
#include <stdbool.h>
#include <stdint.h>
#include <string.h>

// nRF
#include "nrf.h"
#include "app_error.h"
#include "app_timer.h"
#include "app_scheduler.h"
#include "nrf_delay.h"
#include "nrf_drv_clock.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_drv_twi.h" // Add

// LoRa
#include "board.h"

//logs
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

// LoRaMac
#include "loramachelper.h"

#define SCHED_MAX_EVENT_DATA_SIZE   APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE            60                              /**< Maximum number of events in the scheduler queue. */

#define LORAWAN_APP_PORT            2       /**< LoRaWAN application port, do not use 224. It is reserved for certification */
#define LORAWAN_APP_DATA_BUFF_SIZE  64      /**< Size of the data buffer. */  
#define LORAWAN_APP_TX_DUTYCYCLE    10000   /**< Defines the application data transmission duty cycle. 10s, value in [ms]. */  

// --- TWI START ---
/* TWI instance ID. */
#define TWI_INSTANCE_ID     0

/* Common addresses definition for temperature sensor. */
#define LM75B_ADDR         (0x90U >> 1)
#define LM75B_REG_TEMP      0x00U
#define LM75B_REG_CONF      0x01U
#define LM75B_REG_THYST     0x02U
#define LM75B_REG_TOS       0x03U

/* Mode for LM75B. */
#define LM75B_MODE_NORMAL   0U

/* Indicates if operation on TWI has ended. */
static volatile bool m_xfer_done = false;

/* TWI instance. */
static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);

/* Buffer for samples read from temperature sensor. */
static uint8_t m_sample;
// --- TWI END ---

// Foward declaration
static void lmh_rx_data_handler(lmh_app_rx_data_t *app_data);
static void lmh_evt_handler(lmh_evt_type_t type, void *data);

APP_TIMER_DEF(lora_tx_timer_id);                                                    ///< LoRa tx timer instance.
static uint8_t m_lora_rx_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];                   ///< LoRa user application rx data buffer.
static lmh_app_rx_data_t m_lora_rx_data = {m_lora_rx_data_buffer, 0 ,0, 0, 0};      ///< LoRa user application rx data structure.
static uint8_t m_lora_tx_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];                   ///< LoRa user application tx data buffer.
static lmh_app_tx_data_t m_lora_tx_data = {m_lora_tx_data_buffer, 0 ,0, 0, 0};      ///< LoRa user application tx data structure.

/**@brief Structure containing LoRaWan callback functions, needed for lmh_init()
*/
static lmh_callback_t lora_callbacks = {    BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed,
                                            lmh_rx_data_handler, lmh_evt_handler};



/**@brief Function for handling event from the LMH layer
 *
 * @param[in] type  event type 
 * @param[in] data  event data
 */
static void lmh_evt_handler(lmh_evt_type_t type, void *data)
{
    switch(type)
    {
        case LHM_EVT_NWK_JOINED:
        {
#if (OVER_THE_AIR_ACTIVATION != 0)
            NRF_LOG_INFO("Network Joined");
#endif
        } 
        break;

        case LHM_EVT_RX_ACK:
        {
            NRF_LOG_INFO("Acknowledge received");
        } 
        break;

        case LHM_EVT_CLASS_CHANGED:
        {
            int new_class = *(int *)data; 
            NRF_LOG_INFO("Device class changed to %c", "ABC"[new_class]);
        }
        break;

        default:
            break;
    }
}

/**@brief Function for handling LoRaWan received data from the server
 *
 * @param[in] app_data  Pointer to rx data
 */
static void lmh_rx_data_handler(lmh_app_rx_data_t *app_data)
{
    NRF_LOG_DEBUG("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d", app_data->port, app_data->buffsize, app_data->rssi, app_data->snr);

    switch (app_data->port)
    {
        case LORAWAN_APP_PORT:
            // Take action on received data 
        break;
		
        default:
            break;
    }
}


// --- TWI START ---
/**
 * @brief Function for handling data from temperature sensor.
 *
 * @param[in] temp   Temperature in Celsius degrees read from sensor.
 */
__STATIC_INLINE void data_handler(uint8_t temp)
{
    NRF_LOG_INFO("Temperature: %d Celsius degrees.", temp);
}

/**
 * @brief TWI events handler.
 */
void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
    switch (p_event->type)
    {
        case NRF_DRV_TWI_EVT_DONE:
            switch (p_event->xfer_desc.type)
            {
                case NRF_DRV_TWI_XFER_TX:
                    NRF_LOG_INFO("TWI TX Done.");
                    break;
                case NRF_DRV_TWI_XFER_RX:
                    NRF_LOG_INFO("TWI RX Done.");
                    data_handler(m_sample);
                    break;
                default:
                    break;
            }
            m_xfer_done = true;
            break;
        default:
            break;
    }
}

/**
 * @brief TWI initialization.
 */
void twi_init(void)
{
    ret_code_t err_code;

    const nrf_drv_twi_config_t twi_config = {
       .scl                = PIN_TWI_SCL,
       .sda                = PIN_TWI_SDA,
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false,
       .hold_bus_uninit    = false
    };

    err_code = nrf_drv_twi_init(&m_twi, &twi_config, twi_handler, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi);
}

/**
 * @brief Function for setting active mode on LM75B temperature sensor.
 */
void LM75B_set_mode(void)
{
    ret_code_t err_code;

    /* Writing to LM75B_REG_CONF "0" set temperature sensor in NORMAL mode. */
    uint8_t reg[2] = {LM75B_REG_CONF, LM75B_MODE_NORMAL};
    err_code = nrf_drv_twi_tx(&m_twi, LM75B_ADDR, reg, sizeof(reg), false);
    APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);

    /* Writing to pointer byte. */
    reg[0] = LM75B_REG_TEMP;
    m_xfer_done = false;
    err_code = nrf_drv_twi_tx(&m_twi, LM75B_ADDR, reg, 1, false);
    APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);
}

/**
 * @brief Function for reading data from temperature sensor.
 */
static void read_sensor_data(void)
{
    m_xfer_done = false;

    /* Read 1 byte from the specified address - skip 3 bits dedicated for fractional part of temperature. */
    ret_code_t err_code = nrf_drv_twi_rx(&m_twi, LM75B_ADDR, &m_sample, sizeof(m_sample));
    APP_ERROR_CHECK(err_code);
}
// --- TWI END ---

/**@brief Function for handling a LoRa tx timer timeout event.
 */
static void tx_lora_periodic_handler(void * unused)
{
    uint32_t i = 0;

//    do
//    {
//        __WFE();
//    } while (m_xfer_done == false);

//    read_sensor_data();
//    NRF_LOG_FLUSH();

    m_lora_tx_data.port = LORAWAN_APP_PORT;
    m_lora_tx_data.buffer[i++] = 0x03; // 1byte Data Channel:3
    m_lora_tx_data.buffer[i++] = 0x67; // 1byte Data Type:Temperature Sensor
    m_lora_tx_data.buffer[i++] = 0x00; // 2byte 00FA -> 250 -> 25.0C
    m_lora_tx_data.buffer[i++] = 0xFA; //
    m_lora_tx_data.buffer[i++] = 0x05; // 1byte Data Channel:5
    m_lora_tx_data.buffer[i++] = 0x67; // 1byte Data Type:Temperature Sensor
    m_lora_tx_data.buffer[i++] = 0x01; // 2byte 0102 -> 258 -> 25.8C
    m_lora_tx_data.buffer[i++] = 0x02; //
    m_lora_tx_data.buffsize  = i;
    m_lora_tx_data.confirmed = 0;
    m_lora_tx_data.nb_trials = 8;
  
    lmh_send(&m_lora_tx_data);
}

/**@brief Function for the Timer initialization.
 *
 * @details Initializes the timer module. This creates and starts application timers.
 */
static void timers_init(void)
{
    ret_code_t err_code;
	
    APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);

    // Initialize timer module.
    err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
	
    // Initialize timers
    err_code = app_timer_create(&lora_tx_timer_id, APP_TIMER_MODE_REPEATED, tx_lora_periodic_handler);
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for initializing the nrf log module.
 */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}


/**@brief Function for application main entry.
 */
int main(void)
 {	
    uint32_t err_code;
	
    // Initialize logs.
    log_init();
    NRF_LOG_INFO("LoRaWan Class A example started.");
	
    // Initialize clocks & power
    nrf_drv_clock_init();
    nrf_drv_clock_lfclk_request(NULL);
    nrf_pwr_mgmt_init();


    // Enable nRF52 DCDC
    NRF_POWER->DCDCEN = 1;

    // Initialize TWI
    twi_init();

    // Initialize LM75B
//    LM75B_set_mode();

    // Initialize Scheduler and timer
    timers_init();
		
    // Initialize LoRa chip.
    err_code = lora_hardware_init();
    APP_ERROR_CHECK(err_code);
	
    // Initialize LoRaWan
    err_code = lmh_init(&lora_callbacks);
    APP_ERROR_CHECK(err_code);  

    // Start Join procedure
    lmh_join(OVER_THE_AIR_ACTIVATION);
    app_timer_start(lora_tx_timer_id, APP_TIMER_TICKS(LORAWAN_APP_TX_DUTYCYCLE), NULL);

    // Enter main loop.
    for (;;)
    {
        lmh_process();

        app_sched_execute();

        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }		
    }
}

Then I got following output at J-LINK RTT Viewer.

<info> app: LoRaWan Class A example started.
<error> app: ERROR 17 [NRF_ERROR_BUSY] at C:\Users\xxx\mydrive\ISP4520\firmware\ISP4520-examples-master\src\lora\boards\ISP4520B-AS\spi-board.c:62
PC at: 0x0000AE35
<error> app: End of error report

It appears that some other function is interfering with the initialization of the TWI.

Is this error related to the spi-board.c shown with the error code?

Please let me know if you have any links to leading information.

tyro

  • Hi,

    One serial instance can only be used either as SPI or TWI peripheral at the same time. The GitHub library you linked are using SPI_INSTANCE 0 in the SPI init functions, while you are using the same instance 0 for your TWI_INSTANCE in above code:

    #define TWI_INSTANCE_ID     0
    
    ...
    
    /* TWI instance. */
    static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);

    You need to select a different instance in one of the codes, or make sure that SPI and TWI are not initialized at the same time.

    Best regards,
    Jørgen

  • Hi Jørgen,

    Thanks for your advice, I have verified that the program works correctly with the following modifications.

    /* TWI instance ID. */
    #define TWI_INSTANCE_ID     1

    As a beginner, I had read warnings on the blogs of my great predecessors to beware of duplicate instance IDs.

    However, I had let my guard down, thinking that it would not matter to me, as I do not set up complex programs.

    <info> app: LoRaWan Class A example started.
    <info> app: TWI TX Done.
    <info> app: TWI TX Done.
    <info> lmh: DevEui=70-B3-D5-7E-xx-xx-xx-xx
    <info> lmh: JoinEui=00-00-00-00-00-00-00-00
    <info> lmh: Send OTAA Join Request, status: OK
    <info> app: TWI RX Done.
    <info> app: Temperature: 29 Celsius degrees.
    <info> lmh: Send OTAA Join Request, status: OK
    <info> app: TWI RX Done.
    <info> app: Temperature: 29 Celsius degrees.
    <info> lmh: Send OTAA Join Request, status: Busy
    <info> app: TWI RX Done.
    <info> app: Temperature: 29 Celsius degrees.
    <info> lmh: Send OTAA Join Request, status: OK

    The more complex the program, the greater the opportunity to copy-paste sample code, but I would consider the possibility that the sample program reserves the ID.

    Thank you for your kind advice.

    Best regards,

    tyro

Related