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

TWI function not working when Called from a Pin Interrupt Handler

Hi,

The program I'm testing is mainly based on the example code Martin provided in devzone.nordicsemi.com/.../

First test was that to read sensor data (MPU6050) by programming the nRF to request the data. This was successful.

Second test was to program MPU6050 to generate interrupts and then read the data. Monitoring a couple of pins and TWI pins showed that

  • MPU6050 was programmed correctly and the INT pulses could be seen
  • Code will go to the pin interrupt handler and the read acceleration function is called
  • TX part of the read operation (sending the slave address and the register address) is done, but RX part doesn't go through (no activity on SDA and SCL lines, and I think it eventually timeout)

In all these cases, read_accel() function was called from inside the int_pin_handler. When I tried calling the read function from main() the issue was solved and data can be read correctly.

Any thoughts on why is it acting like this? My SDK is 9, chip revision 3 and level 3 optimization is used.

main-2016-02-19.c mpu9150.c

  • Hi

    I believe you might be the victim of incorrect interrupt nesting. First of all, remember that it is good programming practice to keep the interrupt routines as short as possible. Preferably only a few lines of code. The way to achieve this is to set a flag in the IRQ and evaluate the flag in the main while loop, as you have already done in your code. And as you say this solves the problem.

    The problem with calling mpu9150_read_accel() inside int_pin_handler() is that mpu9150_read_accel() takes a long time to complete. It includes two while() loops, which is very poor practice to have in an IRQ, and it triggers two TWI interrupts. So, i.e., you are nesting interrupts inside interrupts.

    If you insist on nesting the interrupts this way you should be able to do so by setting the correct interrupt priorities. The TWI IRQ should have a higher priority than the GPIOTE IRQ. E.g. I was able to solve it by setting the GPIOTE priority to low and the TWI priority to high:

    in nrf_drv_config.h search for this line

    #define GPIOTE_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOW
    

    and make sure to use APP_IRQ_PRIORITY_LOW.

    In main.c search for this line

    .interrupt_priority = APP_IRQ_PRIORITY_HIGH
    

    and make sure to use APP_IRQ_PRIORITY_HIGH.

    I thought this would be the default configuration though. Do you have it configured differently?

    As a sidenote: The MPU drivers in the example code can certainly be improved. E.g. it should be possible make the transfers rely more on the interrupts and reduce the number of while() loops.

  • You are right, my GPIOTE priority was High and after changing it problem was solved. Regarding the MPU drivers, the while() loop that has been used in different functions is for making sure that the TWI transfer has finished and it can proceed to next transmission. So, can you give an example how we can avoid this? When in the sequence of my program I have to finish reading registers and proceed after that, then even if I use the TWI interrupt handler to continue to next transmission (which I haven't thought if it even works), after the nrf_twi_tx command for example, I can not execute any commands other than a wait.

  • What you should do is to simply start the first transfer. Then instead of waiting in a while() loop you exit the function and put the next call to nrf_drv_twi_tx() (or _rx) inside the twi event handler. I.e. start a TX, return to application code, do your things while waiting for an NRF_DRV_TWI_EVT_DONE event, then finally start next TX or RX from within the event. This is how the SDK team have solved it in e.g. the twi_sensor example in SDK 11. So you can have a look at the twi_handler() function in there for inspiration. I plan to implement this in the MPU driver as well some day. Just have to find the time to do it.

Related