This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

BNO080 SH-2 over TWIM

Hi

Has anyone developed or worked with a BNO080 using Hilcrest's SH-2 Protocol over TWIM? I'm having real challenges getting consistent responses. I've developed (based on what I can find on the internet) the basics of a library. But every time I run even even the simplest of requests 50% I get NRF_ERROR_TIMEOUT. The other 50% of the time if receive NRFX_TWIM_EVT_DONE and NRFX_TWIM_XFER_TX.

My other question is related to my lack of experience. How do I know (without interrupt) that data is ready to be ready from TWIM?

bno080-twim.h

#define MPU_TWI_SCL_PIN 11
#define MPU_TWI_SDA_PIN 8

#define MPU_TWI_BUFFER_SIZE     	32
#define MPU_TWI_TIMEOUT 			15000
#define BNO080_TWI_ADDRESS          0x4B 
#define MPU_ADDRESS     			0x68
#define MPU_AK89XX_MAGN_ADDRESS     0x0C

//Registers
#define CHANNEL_COMMAND         0
#define CHANNEL_EXECUTABLE      1
#define CHANNEL_CONTROL         2
#define CHANNEL_REPORTS         3
#define CHANNEL_WAKE_REPORTS    4
#define CHANNEL_GYRO            5

//All the ways we can configure or talk to the BNO080, figure 34, page 36 reference manual
//These are used for low level communication with the sensor, on channel 2
#define SHTP_REPORT_COMMAND_RESPONSE 0xF1
#define SHTP_REPORT_COMMAND_REQUEST 0xF2
#define SHTP_REPORT_FRS_READ_RESPONSE 0xF3
#define SHTP_REPORT_FRS_READ_REQUEST 0xF4
#define SHTP_REPORT_PRODUCT_ID_RESPONSE 0xF8
#define SHTP_REPORT_PRODUCT_ID_REQUEST 0xF9
#define SHTP_REPORT_BASE_TIMESTAMP 0xFB
#define SHTP_REPORT_SET_FEATURE_COMMAND 0xFD

//All the different sensors and features we can get reports from
//These are used when enabling a given sensor
#define SENSOR_REPORTID_ACCELEROMETER 0x01
#define SENSOR_REPORTID_GYROSCOPE 0x02
#define SENSOR_REPORTID_MAGNETIC_FIELD 0x03
#define SENSOR_REPORTID_LINEAR_ACCELERATION 0x04
#define SENSOR_REPORTID_ROTATION_VECTOR 0x05
#define SENSOR_REPORTID_GRAVITY 0x06
#define SENSOR_REPORTID_GAME_ROTATION_VECTOR 0x08
#define SENSOR_REPORTID_GEOMAGNETIC_ROTATION_VECTOR 0x09
#define SENSOR_REPORTID_TAP_DETECTOR 0x10
#define SENSOR_REPORTID_STEP_COUNTER 0x11
#define SENSOR_REPORTID_STABILITY_CLASSIFIER 0x13
#define SENSOR_REPORTID_RAW_ACCELEROMETER 0x14
#define SENSOR_REPORTID_RAW_GYROSCOPE 0x15
#define SENSOR_REPORTID_RAW_MAGNETOMETER 0x16
#define SENSOR_REPORTID_PERSONAL_ACTIVITY_CLASSIFIER 0x1E

//Record IDs from figure 29, page 29 reference manual
//These are used to read the metadata for each sensor type
#define FRS_RECORDID_ACCELEROMETER 0xE302
#define FRS_RECORDID_GYROSCOPE_CALIBRATED 0xE306
#define FRS_RECORDID_MAGNETIC_FIELD_CALIBRATED 0xE309
#define FRS_RECORDID_ROTATION_VECTOR 0xE30B

//Command IDs from section 6.4, page 42
//These are used to calibrate, initialize, set orientation, tare etc the sensor
#define COMMAND_ERRORS 1
#define COMMAND_COUNTER 2
#define COMMAND_TARE 3
#define COMMAND_INITIALIZE 4
#define COMMAND_DCD 6
#define COMMAND_ME_CALIBRATE 7
#define COMMAND_DCD_PERIOD_SAVE 9
#define COMMAND_OSCILLATOR 10
#define COMMAND_CLEAR_DCD 11

#define CALIBRATE_ACCEL 0
#define CALIBRATE_GYRO 1
#define CALIBRATE_MAG 2
#define CALIBRATE_PLANAR_ACCEL 3
#define CALIBRATE_ACCEL_GYRO_MAG 4
#define CALIBRATE_STOP 5

#define MAX_PACKET_SIZE 28 // Size of TWi Buffer 32-4=28 for the header  //128 //Packets can be up to 32k but we don't have that much RAM.
#define MAX_METADATA_SIZE 9 //This is in words. There can be many but we mostly only care about the first 9 (Qs, range, etc)

// TWI (with transaction manager) initialization.
uint32_t twi_config(void);
uint32_t twi_scanner();
uint32_t bno080_init();

bno080-twim.c

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "nrf_log.h"
#include "nrfx_twim.h"
#include "nrf_delay.h"

#include "bno080-twim.h"

uint8_t sequenceNumber[6] = {0, 0, 0, 0, 0, 0}; //There are 6 com channels. Each channel has its own seqnum
uint8_t commandSequenceNumber = 0;				//Commands have a seqNum as well. These are inside command packet, the header uses its own seqNum per channel

//#define TWI_INSTANCE_ID             0
//#define MAX_PENDING_TRANSACTIONS    5
//NRF_TWI_MNGR_DEF(m_nrf_twi_mngr, MAX_PENDING_TRANSACTIONS, TWI_INSTANCE_ID);

static const nrfx_twim_t m_twi_instance = NRFX_TWIM_INSTANCE(0);
volatile static bool twi_tx_done = false;
volatile static bool twi_rx_done = false;

uint8_t twi_tx_buffer[MPU_TWI_BUFFER_SIZE];

static void twi_event_handler(nrfx_twim_evt_t const * p_event, void * p_context)
{
    switch(p_event->type)
    {
        case NRFX_TWIM_EVT_DONE:
            NRF_LOG_INFO("NRFX_TWIM_EVT_DONE");
            switch(p_event->xfer_desc.type)
            {
                case NRFX_TWIM_XFER_TX:
                    NRF_LOG_INFO("NRFX_TWIM_XFER_TX");
                    twi_tx_done = true;
                    break;
                case NRFX_TWIM_XFER_TXTX:
                    NRF_LOG_INFO("NRFX_TWIM_XFER_TXTX");
                    twi_tx_done = true;
                    break;
                case NRFX_TWIM_XFER_RX:
                    NRF_LOG_INFO("NRFX_TWIM_XFER_RX");
                    twi_rx_done = true;
                    break;
                case NRFX_TWIM_XFER_TXRX:
                    NRF_LOG_INFO("NRFX_TWIM_XFER_TXRX");
                    twi_rx_done = true;
                    break;
                default:
                    break;
            }
            break;
        case NRFX_TWIM_EVT_ADDRESS_NACK:
            break;
        case NRFX_TWIM_EVT_DATA_NACK:
            break;
        default:
            break;
    }
}

// TWI (with transaction manager) initialization.
uint32_t twi_config(void)
{
    uint32_t err_code;
    
    const nrfx_twim_config_t twi_mpu_config = {
        .scl                = MPU_TWI_SCL_PIN,
        .sda                = MPU_TWI_SDA_PIN,
        .frequency          = NRF_TWIM_FREQ_400K,
        .interrupt_priority = APP_IRQ_PRIORITY_HIGHEST,
        .hold_bus_uninit    = true
    };
    
    err_code = nrfx_twim_init(&m_twi_instance, &twi_mpu_config, twi_event_handler, NULL);
    if(err_code != NRF_SUCCESS) {return err_code;}

    nrf_delay_ms(1);
        
    nrfx_twim_enable(&m_twi_instance);
	
	return NRF_SUCCESS;

}

uint32_t twi_scanner()
{
    uint32_t err_code;
    uint8_t address;
    uint8_t sample_data;

    for (address = 1; address <= 127; address++)
    {
        err_code = nrfx_twim_rx(&m_twi_instance, address, &sample_data, sizeof(sample_data));
        if (err_code == NRF_SUCCESS)
        {
            NRF_LOG_INFO("TWI device detected at address 0x%x.", address);
        }
    }

    return NRF_SUCCESS;

}

uint32_t  bno080_init()
{
    uint32_t err_code;
    uint32_t timeout = MPU_TWI_TIMEOUT;

    uint16_t packetLength = 6;
    uint8_t * txbuffer = malloc(packetLength);       //setup the data paxket to send
    txbuffer[0] = packetLength & 0xFF;              //SHTP Header - Byte 0 - Packet Length LSB
    txbuffer[1] = packetLength >> 8;                //SHTP Header - Byte 1 - Packet Length MSB
    txbuffer[2] = CHANNEL_CONTROL;                    //SHTP Header - Byte 2 - Channel Number
    txbuffer[3] = sequenceNumber[CHANNEL_CONTROL]++;  //SHTP Header - Byte 3 - Sequence Number
    txbuffer[4] = SHTP_REPORT_PRODUCT_ID_REQUEST;   //SHTP Header - Byte 4 - SHTP_REPORT_PRODUCT_ID_REQUEST
    txbuffer[5] = 0x0;                              //SHTP Header - Byte 5 - Reserved
     
    // Setting up transfer
    nrfx_twim_xfer_desc_t xfer_desc;
    xfer_desc.address = BNO080_TWI_ADDRESS;
    xfer_desc.type = NRFX_TWIM_XFER_TX;
    xfer_desc.primary_length = packetLength;
    xfer_desc.p_primary_buf = txbuffer;

    // Transferring  
    err_code = nrfx_twim_xfer(&m_twi_instance, &xfer_desc, 0);

    while((!twi_tx_done) && --timeout);
    if(!timeout) return NRF_ERROR_TIMEOUT;
    twi_tx_done = false;

    return err_code;
}

TWI/TWIM Settings in SDK:


#define NRFX_TWIM_ENABLED 1
#define NRFX_TWIM0_ENABLED 1

#define NRFX_TWIS_ENABLED 0

#define NRFX_TWI_ENABLED 0

#define TWIS_ENABLED 0

#define TWI_ENABLED 1

#define NRF_TWI_SENSOR_ENABLED 0

#define NRF_TWI_MNGR_ENABLED 0

Thanks, been bogged down with this for a few days.

Parents
  • Hello,

    I suggest that you try to find a driver for the BMO080. Have you tried to analyze the TWI lines? Is there any data going on the lines? Does it correspond with what you'd expect to see?

    BR,

    Edvin

  • Hi

    I've stripped everything back and am using nrf_drv_twi for driving TWI, also removed all code from main.c so it just runs 'nrf_drv_mpu_init' and 'twi_scaner' (see .c below).

    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "bno080-nrf-twi.h"
    #include "nrf_drv_twi.h"
    
     #define TWI_ADDRESSES      127
    
    static const nrf_drv_twi_t m_twi_instance = NRF_DRV_TWI_INSTANCE(0);
    volatile static bool twi_tx_done = false;
    volatile static bool twi_rx_done = false;
    
    uint8_t twi_tx_buffer[MPU_TWI_BUFFER_SIZE];
    
    /**
     * @brief TWI Event Handler.
     * Just the usual way. Nothing special here
     */
    static void nrf_drv_mpu_twi_event_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:
                        twi_tx_done = true;
                        break;
                    case NRF_DRV_TWI_XFER_TXTX:
                        twi_tx_done = true;
                        break;
                    case NRF_DRV_TWI_XFER_RX:
                        twi_rx_done = true;
                        break;
                    case NRF_DRV_TWI_XFER_TXRX:
                        twi_rx_done = true;
                        break;
                    default:
                        break;
                }
                break;
            case NRF_DRV_TWI_EVT_ADDRESS_NACK:
                break;
            case NRF_DRV_TWI_EVT_DATA_NACK:
                break;
            default:
                break;
        }
    }
    
    
    /**
     * @brief TWI initialization.
     * Just the usual way. Nothing special here
     */
    uint32_t nrf_drv_mpu_init(void)
    {
        uint32_t err_code;
        
        const nrf_drv_twi_config_t twi_mpu_config = {
           .scl                = TWI_SCL_PIN,
           .sda                = TWI_SDA_PIN,
           .frequency          = NRF_TWI_FREQ_400K,
           .interrupt_priority = APP_IRQ_PRIORITY_HIGHEST,
           .clear_bus_init     = false
        };
        
        err_code = nrf_drv_twi_init(&m_twi_instance, &twi_mpu_config, nrf_drv_mpu_twi_event_handler, NULL);
        if(err_code != NRF_SUCCESS)
    	{
    		return err_code;
    	}
        
        nrf_drv_twi_enable(&m_twi_instance);
    
        NRF_LOG_INFO ("nrf_drv_mpu_init");
    	
    	return NRF_SUCCESS;
    }
    
    /**
     * @brief TWI Scanner.
     * Just the usual way. Nothing special here
     */
    uint32_t twi_scanner()
    {
    
        uint32_t err_code;
        uint8_t address;
        uint8_t sample_data;
        bool detected_device = false;
    
        NRF_LOG_INFO("twi_scanner");
    
        for (address = 1; address <= TWI_ADDRESSES; address++)
        {
            err_code = nrf_drv_twi_rx(&m_twi_instance, address, &sample_data, sizeof(sample_data));
            if (err_code == NRF_SUCCESS)
            {
                detected_device = true;
                NRF_LOG_INFO("TWI device detected at address 0x%x.", address);
            }
            NRF_LOG_FLUSH();
        }
    
        if (!detected_device)
        {
            NRF_LOG_INFO("No device was found.");
            return NRF_ERROR_INVALID_ADDR;
        }
    
        return NRF_SUCCESS;
    
    }

    I not get the TWI Scanner reporting its found a device at every address...I'm really confused.

  • Okay, I've worked out the Scanning issue:

    I have added in an event capture into the twi instance config:

    err_code = nrf_drv_twi_init(&m_twi_instance, &twi_mpu_config, nrf_drv_mpu_twi_event_handler, NULL);
    Therefore the scanner will always return success, and I will need to check "NRF_DRV_TWI_EVT_DONE"
    I'll continue to build from here!
Reply Children
No Data
Related