Which bit of which register gets set when a TWI interrupt is fired and where is it being reset?

Which bit of which register gets set upon the triggering of an interrupt? Is there something equivalent to EXTI_PR (pending register) from STM32 which gets set upon triggering and reset before IRQ handler is exited? To be precise, this is in the context of TWI. Is it the EVENT_TXDSENT register each time a master has clocked out a byte? If so, where is it being reset?

in my program, I'm using twi_handler to service TWI requests but where is the specific bit being cleared? can't seem to find in the relevant functions in nrfx_twi.c

Parents
  • Hi,

    The concept of pending interrupts is related to the Cortex core and NVIC are generic. That includes enabling and disabling interrupts with a specific ID. All interrupts from the same peripheral has the same ID (and thus same interrupt handler). I interpret the question here to be more related to how interrupts are generated and cleared in the peripherals, though and specifically the TWI.

    I want to first highlight the Tasks, events, shortcuts, and interrupts figure under peripheral interface. As you see here, events are always enabled, but only trigger interrupt when interrupt has been enabled for that specific interrupt. So for instance, in order to get an interrupt for EVENT_TXDSENT, you first need to enable interrupts for TWI in the NVIC, and then also need to enable interrupt for TXDSENT in INTENSET. Once that is in place, you will get an interrupt for any TXDSENT event.

    In order to clear this event, you need to write 0 to EVENTS_TXDSENT.

    Looking at the driver (nrfx_twi.c in SDK 17.1.0) you can see that the event is cleared when appropriate using nrf_twi_event_clear(). For instance, on line 365:

            nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);

  • thanks for the response.

    so in twi_transfer(), the interrupts of the respective flags that got triggered are cleared and at the end, the callback handler is invoked which is a part of the user application.

    Also, what's the way to acquire mutual exclusion within the context of ISRs? to disable any other interrupt that may potentially access the same resources as used within the current ISR?

    The twi_sensor application invokes nrf_drv_twi_enable to enable the TWI instance and not interrupts? which call sets INTENSET register with the respective flags?

  • Hi,

    morpho said:
    Also, what's the way to acquire mutual exclusion within the context of ISRs? to disable any other interrupt that may potentially access the same resources as used within the current ISR?

    I am not sure why this would be needed in the drivers, as they are typically independent, and normally only use a single interrupt ID. But if you have your own code where you have two interrupts or two threads or similar that share data, this can be important. Generally, you have two fundamental methods. One is to use critical sections, where all interrupts are disabled whenever you need to do something that cannot be interrupted (like updating a mutex). Alternatively, you can use the Load-Exclusive and Store-Exclusive (LDREX/STREX) instructions in the cortex core, which is less intrusive. These are used in the nrfx_atomic library. This in turn is used by nRF Mutx, which implements a mutex that you can use.

    morpho said:
    The twi_sensor application invokes nrf_drv_twi_enable to enable the TWI instance and not interrupts? which call sets INTENSET register with the respective flags?

    Interrupts are enabled by the driver implementation. If you use the TWI peripheral (no DMA), you find that in modules\nrfx\drivers\src\nrfx_twi.c. If yo use TWIM (with DMA), you see it in modules\nrfx\drivers\src\nrfx_twim.c. Then search for "int_enable" in these files to see where it is. (This is implementation details that you normally do not need to consider when you are just using the driver.)

  • Yes, I was referring more to the case where an interrupt modifying a FIFO and the next moment it gets preempted by an interrupt of higher priority that accesses the same FIFO. Mutex can't really be used in the context of interrupts and in FreeRTOS, there's a way to disable all the interrupts via  taskenter_critical_from_isr but what's the way to do so in ARM? __disable_irq? does it disable ALL the interrupts? If so, in this case, the higher priority interrupt would not trigger/not preempt?

Reply
  • Yes, I was referring more to the case where an interrupt modifying a FIFO and the next moment it gets preempted by an interrupt of higher priority that accesses the same FIFO. Mutex can't really be used in the context of interrupts and in FreeRTOS, there's a way to disable all the interrupts via  taskenter_critical_from_isr but what's the way to do so in ARM? __disable_irq? does it disable ALL the interrupts? If so, in this case, the higher priority interrupt would not trigger/not preempt?

Children
  • Hi,

    __disable_irq() disables all interrupts, yes. Note that you should not use this if you are using  a SoftDevice, though (I don't know if you do). If you are using the nRF5 SDK then you could look at the app_util_critical_region_enter() et in components\libraries\util\app_util_platform.c, which is the implementatino used for CRITICAL_REGION_ENTER()/EXIT(). This use __disable_irq() when a SoftDevice is not used, and sd_nvic_critical_region_enter() if a SoftDevice is used. In the latter case sd_nvic_critical_region_enter() only disables application interrupts. SoftDevice interrupts may still happen.

Related