I am trying to make TWI calls from an APP_TIMER event. However the TWI calls are failing. I can see that the twi message is sent on an oscilloscope, but the function never returns (handler function doesnt get called), and it holds the clock low after the last message.
I have tried increasing the TWI priority to highest (0) but no change. I am not running a soft device or any other timers.
Is there something prohibiting use of TWI functions from a timer callback function? Am I doing anything wrong, or is there a better way to go about this?
My main function is as follows, and does not work (twi as shown in image above):
int main(void) { lfclk_config(); utils_setup(); twi_init_all(); twi_read_init(); while (true) { nrf_pwr_mgmt_run(); NRF_LOG_FLUSH(); } }
If I modify it to call the twi_timer_handler function in the main loop, then it does work as expected.
int main(void) { lfclk_config(); utils_setup(); twi_init_all(); while (true) { nrf_pwr_mgmt_run(); NRF_LOG_FLUSH(); nrf_delay_ms(100); twi_timer_handler(NULL); } }
Here is full code listing:
#include <stdio.h> #include "nrf.h" #include "bsp.h" #include "hardfault.h" #include "app_error.h" #include "app_timer.h" #include "nrf_pwr_mgmt.h" #include "nrf_drv_clock.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "nrf_drv_twi.h" #include "nrf_delay.h" APP_TIMER_DEF(twi_timer); static void utils_setup(void) { ret_code_t err_code = NRF_LOG_INIT(NULL); APP_ERROR_CHECK(err_code); err_code = app_timer_init(); APP_ERROR_CHECK(err_code); err_code = nrf_pwr_mgmt_init(); APP_ERROR_CHECK(err_code); NRF_LOG_DEFAULT_BACKENDS_INIT(); } static void lfclk_config(void) { ret_code_t err_code = nrf_drv_clock_init(); APP_ERROR_CHECK(err_code); nrf_drv_clock_lfclk_request(NULL); } typedef struct { const nrf_drv_twi_t twi_inst; volatile bool xfer_status; ///< status for twi_instance uint8_t id_num; ///< twi id } twi_struct; static twi_struct twi_instance= { .twi_inst = NRF_DRV_TWI_INSTANCE(0), .xfer_status = false, .id_num = 0 }; static void twi_event_handler(nrf_drv_twi_evt_t const * p_event, void * p_context) { switch (p_event->type) { case NRF_DRV_TWI_EVT_DONE: twi_instance.xfer_status = true; break; case NRF_DRV_TWI_EVT_ADDRESS_NACK: break; case NRF_DRV_TWI_EVT_DATA_NACK: break; default: break; } } void twi_init (nrf_drv_twi_config_t * p_twi_config) { ret_code_t err_code; err_code = nrf_drv_twi_init(&twi_instance.twi_inst, p_twi_config, twi_event_handler, NULL); APP_ERROR_CHECK(err_code); nrf_drv_twi_enable(&twi_instance.twi_inst); } void twi_init_all() { nrf_drv_twi_config_t twi_config = { .scl = 16, .sda = 12, .frequency = NRF_TWI_FREQ_100K, .interrupt_priority = APP_IRQ_PRIORITY_LOWEST, .clear_bus_init = false }; twi_init(&twi_config); } void twi_write_register(uint8_t address, uint8_t * p_reg, uint8_t reg_size) { //ret_code_t err_code = nrf_drv_twi_tx(&twi_i[id_num].twi_inst, address, reg, reg_size, false); twi_instance.xfer_status = false; ret_code_t err_code = nrf_drv_twi_tx(&twi_instance.twi_inst, address, p_reg, reg_size, false); APP_ERROR_CHECK(err_code); while (twi_instance.xfer_status == false); twi_instance.xfer_status = false; } void twi_read_register(uint8_t address, uint8_t * p_reg, uint8_t * p_data, uint8_t data_size) { twi_write_register(address, p_reg, 1); ret_code_t err_code = nrf_drv_twi_rx(&twi_instance.twi_inst, address, p_data, data_size); APP_ERROR_CHECK(err_code); while (twi_instance.xfer_status == false); twi_instance.xfer_status = false; } void twi_timer_handler(void * p_context) { uint8_t buffer_local[3]; uint8_t reg=0xA2; twi_read_register(0x76,®,&buffer_local[0],3); } void twi_read_init() { ret_code_t err_code; err_code = app_timer_create(&twi_timer, APP_TIMER_MODE_REPEATED, twi_timer_handler); APP_ERROR_CHECK(err_code); err_code = app_timer_start(twi_timer, APP_TIMER_TICKS(10), NULL); APP_ERROR_CHECK(err_code); } int main(void) { lfclk_config(); utils_setup(); twi_init_all(); twi_read_init(); while (true) { nrf_pwr_mgmt_run(); NRF_LOG_FLUSH(); } }
Many thanks!