NRF52 with MPU9255: magnetometer with easydma

Hello everyone,

I currently using this lib: GitHub - Martinsbl/nrf5-mpu-examples to read data from MPU9255, when I'm using the easydma for accelerometer and gyros its work normally but when I'm trying to read the data from the magnetometer it doesn't working. Anyone has an answer for me 

Thanks. Best Regard, 

Kyle.

  • Hello Kyle,

    We would like to know more information.

    1. Did you use these examples without modifications?

    2. Did you use Old SDK that the examples were written during building?

    3. How did you connect the sensor to nRF52? Did you use TWI or SPI?

    Thanks.

    BR

    Kazi Afroza Sultana

  • Hello Kazi,

    1. I have modified the output pin and changing the p_tx_buffer[1] to read the address of magnetometer.

    2. I'm using the latest SDK.

    3. I'm using 5 pins of sensor to connect with the nRF52 2 pins power, SDA, SCL and INT pin. I'm using the TWIM.

    Here is my main file: 

     /* 
      * This example is not extensively tested and only 
      * meant as a simple explanation and for inspiration. 
      * NO WARRANTY of ANY KIND is provided. 
      */
    
    #include <stdbool.h>
    #include <string.h>
    #include <stdio.h>
    #include "nrf_delay.h"
    #include "app_uart.h"
    #include "bsp.h"
    #include "app_error.h"
    #include "app_mpu9255.h"
    
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    
    /**@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();
    }
    
    
    /* Pins to connect MPU. Pinout is different for nRF51 DK and nRF52 DK
     * and therefore I have added a conditional statement defining different pins
     * for each board. This is only for my own convenience. 
     */
    
    #define MPU_TWI_SCL_PIN NRF_GPIO_PIN_MAP(0, 28)
    #define MPU_TWI_SDA_PIN NRF_GPIO_PIN_MAP(0, 29)
    #define MPU_INT_PIN     NRF_GPIO_PIN_MAP(0, 30)
    
    
    #define MPU_ADDRESS     		0x68 
    
    /* The buffer length, TWIM_RX_BUF_LENGTH, defines how many samples will fit in the buffer. Each sample
     * may contain accelerometer data and/or gyroscope data and/or temperature. What data to read is defined by 
     * TWIM_RX_BUF_WIDTH and reigster address in p_tx_data.*/
    #define TWIM_RX_BUF_LENGTH  10
    
    
    /* The buffer width, TWIM_RX_BUF_WIDTH, and tx buffer, p_tx_data, defines how much and what kind of data to read out for every sample. For example: 
     * A buffer width of 6 and register read address MPU_REG_ACCEL_XOUT_H will read out accelerometer data only. 
     * A buffer width of 14 and register read address MPU_REG_ACCEL_XOUT_H will read out all acceleromter, temperateure, and gyroscope data. 
     * A buffer width of 6 and register start address MPU_REG_GYRO_XOUT_H will read out gyroscope data only. */
    #define TWIM_RX_BUF_WIDTH   6   // Reading accelerometer only
    
    
    /* Define a type with a two dimensioanal array, TWIM_RX_BUF_WIDTH wide and TWIM_RX_BUF_LENGTH long, holding a list of MPU sensor data */
    typedef struct ArrayList
    {
        uint8_t buffer[TWIM_RX_BUF_WIDTH];
    }array_list_t;
    
    /* Declare an RX buffer to hold the sensor data in the MPU we want to read. 
     * TWIM_RX_BUF_LENGTH defines how many samples of accelerometer data and/or gyroscope data and/or temperature
     * data we want to read out. What kind of sensor values we read out is defined by the register address
     * held in p_tx_data and the buffer width TWIM_RX_BUF_WIDTH.  */
    array_list_t p_rx_buffer[TWIM_RX_BUF_LENGTH];
    
    /* Declare a simple TX buffer holding the first register in MPU we want to read from. */
    //uint8_t p_tx_buffer[1] = {MPU_REG_ACCEL_XOUT_H};  // Reading accelerometer only
    
    //uint8_t p_tx_buffer[1] = {MPU_REG_GYRO_XOUT_H}; // Reading gyros
    
    uint8_t p_tx_buffer[1] = {MPU_AK89XX_REG_HXL}; //  Reading mango
    
    /* Flag to indicate to the applications main context that TWIM_RX_BUF_LENGTH number of samples have been transferred from MPU */
    volatile bool twi_transfers_complete = false;
    
    
    
    /**
     * @brief Initialize the TWI Master module with PPI triggered
     * R/W operations started by a counter module
     */
    static void twi_with_easy_dma_setup()
    {
        // Disable the TWIM module while we reconfigure it
        NRF_TWIM0->ENABLE = TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos;
        NRF_TWIM0->SHORTS = 0;
        NVIC_DisableIRQ(SPI0_TWI0_IRQn);
        NVIC_ClearPendingIRQ(SPI0_TWI0_IRQn);
        
        // Configure a gpiote channel to generate an event on a polarity change from 
        // low to high generated the MPU interrupt pin.
        uint8_t gpiote_ch_mpu_int_event = 0;
        NRF_GPIOTE->CONFIG[gpiote_ch_mpu_int_event] = ( (GPIOTE_CONFIG_MODE_Event   << GPIOTE_CONFIG_MODE_Pos) | 
                                                        (MPU_INT_PIN                << GPIOTE_CONFIG_PSEL_Pos) | 
                                                        (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos));
        
        NRF_TWIM0->PSEL.SCL = MPU_TWI_SCL_PIN;
        NRF_TWIM0->PSEL.SDA = MPU_TWI_SDA_PIN;
        NRF_TWIM0->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K400;
        
        // Load TWI TX buffer into TWI module. Set number of bytes to write pr transfer, max count, to one. 
        // Disable the EasyDMA list functionality for TWI TX.
        NRF_TWIM0->TXD.PTR = (uint32_t)&p_tx_buffer;
        NRF_TWIM0->TXD.MAXCNT = 1;
        NRF_TWIM0->TXD.LIST = TWIM_TXD_LIST_LIST_Disabled << TWIM_TXD_LIST_LIST_Pos;
        
        // Point to TWI RX buffer. Set number of bytes to read pr transfer, max count, to TWIM_RX_BUF_WIDTH. 
        // Disable the EasyDMA list functionality for TWI TX
        NRF_TWIM0->RXD.PTR = (uint32_t)&p_rx_buffer;
        NRF_TWIM0->RXD.MAXCNT = TWIM_RX_BUF_WIDTH;
        NRF_TWIM0->RXD.LIST = TWIM_RXD_LIST_LIST_ArrayList << TWIM_RXD_LIST_LIST_Pos;
        
        // Make sure that MPU address is set
        NRF_TWIM0->ADDRESS = MPU_ADDRESS;
        // Enable shortcuts that starts a read right after a write and sends a stop condition after last TWI read
        NRF_TWIM0->SHORTS = (TWIM_SHORTS_LASTTX_STARTRX_Enabled << TWIM_SHORTS_LASTTX_STARTRX_Pos) | 
                            (TWIM_SHORTS_LASTRX_STOP_Enabled << TWIM_SHORTS_LASTRX_STOP_Pos);
        
        // Configure PPI channel
        // Use MPU interrupt pin as event
        // Start timer 0 on event to count number of transfers
        // Also start TWI transfers on event
        // Enable PPI channel
        NRF_PPI->CH[0].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[gpiote_ch_mpu_int_event];
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TIMER0->TASKS_COUNT;
        NRF_PPI->FORK[0].TEP = (uint32_t)&NRF_TWIM0->TASKS_STARTTX;
        
        // Enable the TWIM module
        NRF_TWIM0->ENABLE = TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos;
    }
    
    
    /**
     * @brief Initialize the counter in Timer 0 used to count number of 
     * TWI transfers from MPU 
     */
    void twi_transfer_counter_init()
    {
        // Disable and clear any pending Timer 0 interrupts
        NVIC_DisableIRQ(TIMER0_IRQn);
        NVIC_ClearPendingIRQ(TIMER0_IRQn);
        
        // Stop timer if running
        NRF_TIMER0->TASKS_STOP = 1;
        // Enabel shortcut to clear the compare register on a compare event
        NRF_TIMER0->SHORTS  = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
        // Use timer 0 as counter
        NRF_TIMER0->MODE    = TIMER_MODE_MODE_Counter << TIMER_MODE_MODE_Pos;
        // Set bit mode to 8 bit.
        NRF_TIMER0->BITMODE = TIMER_BITMODE_BITMODE_08Bit << TIMER_BITMODE_BITMODE_Pos;
        // Set compare register to length of RX buffer. This will trigger an event each time
        // the RX buffer is full
        NRF_TIMER0->CC[0]   = TWIM_RX_BUF_LENGTH;
        // Enable interrupts on counter compare
        NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
        
    }
    
    /**
     * @brief Start the transfers
     */
    void start_transfers(void)
    {
        // Enable timer interrupt
        NVIC_EnableIRQ(TIMER0_IRQn);
        // Start counter
        NRF_TIMER0->TASKS_START = 1;
        // Enable the PPI channel tying MPU interrupt pin to TWIM module
        NRF_PPI->CHEN = PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos;
    }
    
    /**
     * @brief Timer event handler triggered on counter compare, i.e. everytime
     * TWI RX buffer is full
     */
    void TIMER0_IRQHandler(void)
    {
        // Clear timer event
        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
        // Reset the TWIM RX pointer to initial address of RX buffer
        NRF_TWIM0->RXD.PTR = (uint32_t)&p_rx_buffer;
        // Toggle a LED for show
        nrf_gpio_pin_toggle(LED_1);
        // Set flag to notify main context of the new data available
        twi_transfers_complete = true;  
    }
    
    
    /**
     * @brief MPU initialization.
     * Just the usual way. Nothing special here
     */
    void mpu_init()
    {
        uint32_t err_code;
        
        // MPU setup
        err_code = app_mpu_init();
        APP_ERROR_CHECK(err_code); // Check for errors in return value
        app_mpu_config_t p_mpu_config = MPU_DEFAULT_CONFIG();
        p_mpu_config.smplrt_div = 19;
        p_mpu_config.accel_config.afs_sel = AFS_2G;
        p_mpu_config.gyro_config.fs_sel = GFS_250DPS;
        err_code = app_mpu_config(&p_mpu_config);
        APP_ERROR_CHECK(err_code); // Check for errors in return value
    
        	// Enable magnetometer
    	app_mpu_magn_config_t magnetometer_config;
    	magnetometer_config.mode = CONTINUOUS_MEASUREMENT_100Hz_MODE;
        err_code = app_mpu_magnetometer_init(&magnetometer_config);
        APP_ERROR_CHECK(err_code); // Check for errors in return value
        
        app_mpu_int_pin_cfg_t p_int_pin_cfg = MPU_DEFAULT_INT_PIN_CONFIG();
        p_int_pin_cfg.int_rd_clear = 1; // Read operation will clear the MPU interrupt
        err_code = app_mpu_int_cfg_pin(&p_int_pin_cfg);
        APP_ERROR_CHECK(err_code); // Check for errors in return value
        
        app_mpu_int_enable_t p_int_enable = MPU_DEFAULT_INT_ENABLE_CONFIG();
        p_int_enable.data_rdy_en = 1; // Enable interrupt on completed sample
        err_code = app_mpu_int_enable(&p_int_enable);
        APP_ERROR_CHECK(err_code); // Check for errors in return value
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        LEDS_CONFIGURE(LEDS_MASK);
        LEDS_OFF(LEDS_MASK);
        
        // Initialize.
        log_init();
    	NRF_LOG_INFO("\033[2J\033[;H"); // Clear screen
        
        mpu_init();
        
        // Start execution.
        NRF_LOG_INFO("MPU EasyDMA using GPIOTE and registers example.");
        
        
        // Initiate counter to count number of TWI transfers 
        twi_transfer_counter_init();
        // Reconfigure TWI to use PPI and easyDMA
        twi_with_easy_dma_setup();
        
        // Starting the transfers
        start_transfers();
        
        uint32_t sample_nr = 0; // Variable holding number of samples read from MPU
        accel_values_t acc_values; // Variable to temporarily hold MPU accelerometer data
        gyro_values_t gyro_values;
        magn_values_t magn_values;
        while (true)
        {
            if(NRF_LOG_PROCESS() == false)
            {
                nrf_gpio_pin_set(LED_4); // Turn LED OFF when CPU is sleeping
                // Wait for new available data 
                while(twi_transfers_complete == false)
                {
                    // Make sure any pending events are cleared
                    __SEV();
                    __WFE();
                    // Enter System ON sleep mode
                    __WFE();           
                }
                nrf_gpio_pin_clear(LED_4); // Turn LED ON when CPU is working
                // Print header with total number of samples received
                NRF_LOG_RAW_INFO("\033[3;1HSample %d:\r\n", TWIM_RX_BUF_LENGTH * sample_nr++);
                
                // THIS FOR LOOP ASSUMES THAT TWIM_RX_BUF_WIDTH IS 6 BYTES AND THAT ONLY ACCELEROMETER DATA IS SAMPLED
                // IF A WIDER BUFFER IS USED TO SAMPLE TEMPERATURE AND GYROSCOPE AS WELL YOU SHOULD CHANGE THIS LOOP
                // TO PRINT EVERYTHING
                uint8_t *data;
    
                // Itterate through entire RX buffer 
                for(uint8_t j = 0; j<TWIM_RX_BUF_LENGTH; j++)
                {
                    // Temporarily store each sensor data set found in buffer in accelerometer structure variable
                    data = (uint8_t*)&magn_values;
                    // Itterate through and store all data in each sensor set
                    for(uint8_t i = 0; i<TWIM_RX_BUF_WIDTH; i++)
                    {
                        *data = p_rx_buffer[j].buffer[5-i];
                        data++;
    
                    }
                    // Print sensor data set
    
                    //NRF_LOG_RAW_INFO("X %06d\r\nY %06d\r\nZ %06d\r\n\r\n", (int16_t)acc_values.x, (int16_t)acc_values.y, (int16_t)acc_values.z);
                    //NRF_LOG_RAW_INFO("X %06d\r\nY %06d\r\nZ %06d\r\n\r\n", (int16_t)gyro_values.x, (int16_t)gyro_values.y, (int16_t)gyro_values.z);
                    NRF_LOG_RAW_INFO("X %06d\r\nY %06d\r\nZ %06d\r\n\r\n", (int16_t)magn_values.x, (int16_t)magn_values.y, (int16_t)magn_values.z);
                    
                    // Small delay so not to overload the UART 
                    nrf_delay_ms(200); 
                }
                // Reset data ready flag
                twi_transfers_complete = false;
            }
        }
    }
    /** @} */
    

    Thanks.

    Best Regards,

    Kyle.

  • Hello,

    We need more information. Have you got any error code to show which is not working? MPU_AK89XX_REG_HXL is your magnetometer. Have you defined it correctly according to the datasheet of the device?

    Here we can see nrf5-mpu-examples/nrf_drv_mpu_twi.c at e2f654f27590388d3eb9a3730fe8fe8d510ff5d4 · Martinsbl/nrf5-mpu-examples (github.com) the address of magnetometer is 0x0C (#define MPU_AK89XX_MAGN_ADDRESS 0x0C). You have used the address of accelerometer as the address of magnetometer. So, it might not response.

    Thanks.

    BR

    Kazi

  • It's returned the value of magnetometer is 0. I had added the address for the magnetometer, but the result maintained. In the instruction, the status register MPU_AK89XX_REG_ST2 have to be read at the end maybe I'm missed this, but I don't know how to implement it, could you help me.

     /* 
      * This example is not extensively tested and only 
      * meant as a simple explanation and for inspiration. 
      * NO WARRANTY of ANY KIND is provided. 
      */
    
    #include <stdbool.h>
    #include <string.h>
    #include <stdio.h>
    #include "nrf_delay.h"
    #include "app_uart.h"
    #include "bsp.h"
    #include "app_error.h"
    #include "app_mpu9255.h"
    #include "boards.h"
    #include "nrf_drv_twi.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    
    /**@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();
    }
    
    
    /* Pins to connect MPU. Pinout is different for nRF51 DK and nRF52 DK
     * and therefore I have added a conditional statement defining different pins
     * for each board. This is only for my own convenience. 
     */
    
    #define MPU_TWI_SCL_PIN NRF_GPIO_PIN_MAP(0,28)
    #define MPU_TWI_SDA_PIN NRF_GPIO_PIN_MAP(0,29)
    #define MPU_INT_PIN     NRF_GPIO_PIN_MAP(0,30)
    
    
    #define MPU_ADDRESS     		0x68
    #define MPU_AK89XX_MAGN_ADDRESS     0x0C 
    
    
    /* The buffer length, TWIM_RX_BUF_LENGTH, defines how many samples will fit in the buffer. Each sample
     * may contain accelerometer data and/or gyroscope data and/or temperature. What data to read is defined by 
     * TWIM_RX_BUF_WIDTH and reigster address in p_tx_data.*/
    #define TWIM_RX_BUF_LENGTH  10
    
    
    /* The buffer width, TWIM_RX_BUF_WIDTH, and tx buffer, p_tx_data, defines how much and what kind of data to read out for every sample. For example: 
     * A buffer width of 6 and register read address MPU_REG_ACCEL_XOUT_H will read out accelerometer data only. 
     * A buffer width of 14 and register read address MPU_REG_ACCEL_XOUT_H will read out all acceleromter, temperateure, and gyroscope data. 
     * A buffer width of 6 and register start address MPU_REG_GYRO_XOUT_H will read out gyroscope data only. */
    #define TWIM_RX_BUF_WIDTH   6   // Reading accelerometer only
    
    
    /* Define a type with a two dimensioanal array, TWIM_RX_BUF_WIDTH wide and TWIM_RX_BUF_LENGTH long, holding a list of MPU sensor data */
    typedef struct ArrayList
    {
        uint8_t buffer[TWIM_RX_BUF_WIDTH];
    }array_list_t;
    
    /* Declare an RX buffer to hold the sensor data in the MPU we want to read. 
     * TWIM_RX_BUF_LENGTH defines how many samples of accelerometer data and/or gyroscope data and/or temperature
     * data we want to read out. What kind of sensor values we read out is defined by the register address
     * held in p_tx_data and the buffer width TWIM_RX_BUF_WIDTH.  */
    array_list_t p_rx_buffer[TWIM_RX_BUF_LENGTH];
    
    /* Declare a simple TX buffer holding the first register in MPU we want to read from. */
    //uint8_t p_tx_buffer[1] = {MPU_REG_ACCEL_XOUT_H};  // Reading accelerometer only
    
    //uint8_t p_tx_buffer[1] = {MPU_REG_TEMP_OUT_H};
    
    //uint8_t p_tx_buffer[1] = {MPU_REG_GYRO_XOUT_H}; // Reading gyros
    
    uint8_t p_tx_buffer[1] = {MPU_AK89XX_REG_HXL}; //  Reading mango
    
    /* Flag to indicate to the applications main context that TWIM_RX_BUF_LENGTH number of samples have been transferred from MPU */
    volatile bool twi_transfers_complete = false;
    
    static const nrf_drv_twi_t m_twi_instance = NRF_DRV_TWI_INSTANCE(0);
    
    
    /**
     * @brief Initialize the TWI Master module with PPI triggered
     * R/W operations started by a counter module
     */
    static void twi_with_easy_dma_setup()
    {
        // Disable the TWIM module while we reconfigure it
        NRF_TWIM0->ENABLE = TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos;
        NRF_TWIM0->SHORTS = 0;
        NVIC_DisableIRQ(SPI0_TWI0_IRQn);
        NVIC_ClearPendingIRQ(SPI0_TWI0_IRQn);
        
        // Configure a gpiote channel to generate an event on a polarity change from 
        // low to high generated the MPU interrupt pin.
        uint8_t gpiote_ch_mpu_int_event = 0;
        NRF_GPIOTE->CONFIG[gpiote_ch_mpu_int_event] = ( (GPIOTE_CONFIG_MODE_Event   << GPIOTE_CONFIG_MODE_Pos) | 
                                                        (MPU_INT_PIN                << GPIOTE_CONFIG_PSEL_Pos) | 
                                                        (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos));
        
        NRF_TWIM0->PSEL.SCL = MPU_TWI_SCL_PIN;
        NRF_TWIM0->PSEL.SDA = MPU_TWI_SDA_PIN;
        NRF_TWIM0->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K400;
        
        // Load TWI TX buffer into TWI module. Set number of bytes to write pr transfer, max count, to one. 
        // Disable the EasyDMA list functionality for TWI TX.
        NRF_TWIM0->TXD.PTR = (uint32_t)&p_tx_buffer;
        NRF_TWIM0->TXD.MAXCNT = 1;
        NRF_TWIM0->TXD.LIST = TWIM_TXD_LIST_LIST_Disabled << TWIM_TXD_LIST_LIST_Pos;
        
        // Point to TWI RX buffer. Set number of bytes to read pr transfer, max count, to TWIM_RX_BUF_WIDTH. 
        // Disable the EasyDMA list functionality for TWI TX
        NRF_TWIM0->RXD.PTR = (uint32_t)&p_rx_buffer;
        NRF_TWIM0->RXD.MAXCNT = TWIM_RX_BUF_WIDTH;
        NRF_TWIM0->RXD.LIST = TWIM_RXD_LIST_LIST_ArrayList << TWIM_RXD_LIST_LIST_Pos;
        
        // Make sure that MPU address is set
        NRF_TWIM0->ADDRESS = MPU_AK89XX_MAGN_ADDRESS;
        // Enable shortcuts that starts a read right after a write and sends a stop condition after last TWI read
        NRF_TWIM0->SHORTS = (TWIM_SHORTS_LASTTX_STARTRX_Enabled << TWIM_SHORTS_LASTTX_STARTRX_Pos) | 
                            (TWIM_SHORTS_LASTRX_STOP_Enabled << TWIM_SHORTS_LASTRX_STOP_Pos);
        
        // Configure PPI channel
        // Use MPU interrupt pin as event
        // Start timer 0 on event to count number of transfers
        // Also start TWI transfers on event
        // Enable PPI channel
        NRF_PPI->CH[0].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[gpiote_ch_mpu_int_event];
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TIMER0->TASKS_COUNT;
        NRF_PPI->FORK[0].TEP = (uint32_t)&NRF_TWIM0->TASKS_STARTTX;
        
        // Enable the TWIM module
        NRF_TWIM0->ENABLE = TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos;
    }
    
    
    /**
     * @brief Initialize the counter in Timer 0 used to count number of 
     * TWI transfers from MPU 
     */
    void twi_transfer_counter_init()
    {
        // Disable and clear any pending Timer 0 interrupts
        NVIC_DisableIRQ(TIMER0_IRQn);
        NVIC_ClearPendingIRQ(TIMER0_IRQn);
        
        // Stop timer if running
        NRF_TIMER0->TASKS_STOP = 1;
        // Enabel shortcut to clear the compare register on a compare event
        NRF_TIMER0->SHORTS  = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
        // Use timer 0 as counter
        NRF_TIMER0->MODE    = TIMER_MODE_MODE_Counter << TIMER_MODE_MODE_Pos;
        // Set bit mode to 8 bit.
        NRF_TIMER0->BITMODE = TIMER_BITMODE_BITMODE_08Bit << TIMER_BITMODE_BITMODE_Pos;
        // Set compare register to length of RX buffer. This will trigger an event each time
        // the RX buffer is full
        NRF_TIMER0->CC[0]   = TWIM_RX_BUF_LENGTH;
        // Enable interrupts on counter compare
        NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
        
    }
    
    /**
     * @brief Start the transfers
     */
    void start_transfers(void)
    {
        // Enable timer interrupt
        NVIC_EnableIRQ(TIMER0_IRQn);
        // Start counter
        NRF_TIMER0->TASKS_START = 1;
        // Enable the PPI channel tying MPU interrupt pin to TWIM module
        NRF_PPI->CHEN = PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos;
    }
    
    /**
     * @brief Timer event handler triggered on counter compare, i.e. everytime
     * TWI RX buffer is full
     */
    void TIMER0_IRQHandler(void)
    {
        // Clear timer event
        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
        // Reset the TWIM RX pointer to initial address of RX buffer
        NRF_TWIM0->RXD.PTR = (uint32_t)&p_rx_buffer;
        // Toggle a LED for show
        nrf_gpio_pin_toggle(LED_1);
        // Set flag to notify main context of the new data available
        twi_transfers_complete = true;  
    }
    
    
    /**
     * @brief MPU initialization.
     * Just the usual way. Nothing special here
     */
    void mpu_init()
    {
        uint32_t err_code;
        
        // MPU setup
        err_code = app_mpu_init();
        APP_ERROR_CHECK(err_code); // Check for errors in return value
        app_mpu_config_t p_mpu_config = MPU_DEFAULT_CONFIG();
        p_mpu_config.smplrt_div = 19;
        p_mpu_config.accel_config.afs_sel = AFS_2G;
        p_mpu_config.gyro_config.fs_sel = GFS_250DPS;
        err_code = app_mpu_config(&p_mpu_config);
        APP_ERROR_CHECK(err_code); // Check for errors in return value
    
        	// Enable magnetometer
    	app_mpu_magn_config_t magnetometer_config;
    	magnetometer_config.mode = CONTINUOUS_MEASUREMENT_100Hz_MODE;
        err_code = app_mpu_magnetometer_init(&magnetometer_config);
        APP_ERROR_CHECK(err_code); // Check for errors in return value
        
        app_mpu_int_pin_cfg_t p_int_pin_cfg = MPU_DEFAULT_INT_PIN_CONFIG();
        p_int_pin_cfg.int_rd_clear = 1; // Read operation will clear the MPU interrupt
        err_code = app_mpu_int_cfg_pin(&p_int_pin_cfg);
        APP_ERROR_CHECK(err_code); // Check for errors in return value
        
        app_mpu_int_enable_t p_int_enable = MPU_DEFAULT_INT_ENABLE_CONFIG();
        p_int_enable.data_rdy_en = 1; // Enable interrupt on completed sample
        err_code = app_mpu_int_enable(&p_int_enable);
        APP_ERROR_CHECK(err_code); // Check for errors in return value
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        LEDS_CONFIGURE(LEDS_MASK);
        LEDS_OFF(LEDS_MASK);
        
        // Initialize.
        log_init();
    	NRF_LOG_INFO("\033[2J\033[;H"); // Clear screen
        
        mpu_init();
        
        // Start execution.
        NRF_LOG_INFO("MPU EasyDMA using GPIOTE and registers example.");
        
        
        // Initiate counter to count number of TWI transfers 
        twi_transfer_counter_init();
        // Reconfigure TWI to use PPI and easyDMA
        twi_with_easy_dma_setup();
        
        // Starting the transfers
        start_transfers();
        
        uint32_t sample_nr = 0; // Variable holding number of samples read from MPU
        accel_values_t acc_values; // Variable to temporarily hold MPU accelerometer data
        gyro_values_t gyro_values;
        magn_values_t magn_values;
        temp_value_t  temp_values;
    
        const uint8_t MAG_DATA_SIZE = 10;
        uint8_t magn_data[MAG_DATA_SIZE];
        memset(magn_data, 0, MAG_DATA_SIZE);
    
        while (true)
        {
            if(NRF_LOG_PROCESS() == false)
            {
                nrf_gpio_pin_set(LED_4); // Turn LED OFF when CPU is sleeping
                // Wait for new available data 
                while(twi_transfers_complete == false)
                {
                    // Make sure any pending events are cleared
                    __SEV();
                    __WFE();
                    // Enter System ON sleep mode
                    __WFE();           
                }
                nrf_gpio_pin_clear(LED_4); // Turn LED ON when CPU is working
                // Print header with total number of samples received
                NRF_LOG_RAW_INFO("\033[3;1HSample %d:\r\n", TWIM_RX_BUF_LENGTH * sample_nr++);
                
                // THIS FOR LOOP ASSUMES THAT TWIM_RX_BUF_WIDTH IS 6 BYTES AND THAT ONLY ACCELEROMETER DATA IS SAMPLED
                // IF A WIDER BUFFER IS USED TO SAMPLE TEMPERATURE Ad5g deeerND GYROSCOPE AS WELL YOU SHOULD CHANGE THIS LOOP
                // TO PRINT EVERYTHING
                uint8_t *data;
    
                // Itterate through entire RX buffer 
                for(uint8_t j = 0; j<TWIM_RX_BUF_LENGTH; j++)
                {
                    // Temporarily store each sensor data set found in buffer in accelerometer structure variable
                    data = (uint8_t*)&magn_values;
                    // Itterate through and store all data in each sensor set
                    for(uint8_t i = 0; i<TWIM_RX_BUF_WIDTH; i++)
                    {
                        *data = p_rx_buffer[j].buffer[5-i];
                        data++;
    
                    }
    
                    // Print sensor data set
                    //NRF_LOG_RAW_INFO("Temp %06d\r\n", (int16_t)temp_values);
                    //NRF_LOG_RAW_INFO("X %06d\r\nY %06d\r\nZ %06d\r\n\r\n", (int16_t)acc_values.x, (int16_t)acc_values.y, (int16_t)acc_values.z);
                    //NRF_LOG_RAW_INFO("X %06d\r\nY %06d\r\nZ %06d\r\n\r\n", (int16_t)gyro_values.x, (int16_t)gyro_values.y, (int16_t)gyro_values.z);
                    NRF_LOG_RAW_INFO("X %06d\r\nY %06d\r\nZ %06d\r\n\r\n", (int16_t)magn_values.x, (int16_t)magn_values.y, (int16_t)magn_values.z);
                    
                    // Small delay so not to overload the UART 
                    nrf_delay_ms(200); 
                }
                // Reset data ready flag
                twi_transfers_complete = false;
            }
        }
    }
    /** @} */
    

    Thanks.

    BR,

    Kyle.

Related