understanding arm cortex 4 proccessor register logic of interrupt double enable

Thread Starter

yef smith

Joined Aug 2, 2020
751
Hello , in the example code bellow we have NVIC_ClearPendingIRQ(USART0_TX_IRQn);
which from page 220 in the manual enables USART_TX interrupt.
But later on in teh code we have

Code:
    // Enable transmit buffer level interrupt

    USART_IntEnable(USART0, USART_IEN_TXBL);
Which means enable the enable the TXBL flag.
So it seems we are anabling the same thing twice,
What is the difference between the two enables,why do we need to enable twice?
1603472145260.png
https://www.silabs.com/content/user...earmcortexm4manualih-jZ8g/Cortex M4 Guide.pdf


Code:
#include "em_device.h"
#include "em_chip.h"
#include "em_emu.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_usart.h"

#include "bsp.h"

// Size of the buffer for received data
#define BUFLEN  80

// Receive data buffer
uint8_t buffer[BUFLEN];

// Current position ins buffer
uint32_t inpos = 0;
uint32_t outpos = 0;

// True while receiving data (waiting for CR or BUFLEN characters)
bool receive = true;

/**************************************************************************//**
 * @brief
 *    GPIO initialization
 *****************************************************************************/
void initGpio(void)
{
  CMU_ClockEnable(cmuClock_GPIO, true);

  // Configure VCOM transmit pin to board controller as an output
  GPIO_PinModeSet(BSP_BCC_TXPORT, BSP_BCC_TXPIN, gpioModePushPull, 1);

  // Configure VCOM reeive pin from board controller as an input
  GPIO_PinModeSet(BSP_BCC_RXPORT, BSP_BCC_RXPIN, gpioModeInput, 0);

  // Enable VCOM connection to board controller
  GPIO_PinModeSet(BSP_BCC_ENABLE_PORT, BSP_BCC_ENABLE_PIN, gpioModePushPull, 1);
}

/**************************************************************************//**
 * @brief
 *    USART0 initialization (VCOM on xG1/xG12/xG13 boards)
 *****************************************************************************/
void initUsart0(void)
{
  CMU_ClockEnable(cmuClock_USART0, true);

  // Default asynchronous initializer (115.2 Kbps, 8N1, no flow control)
  USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;

  // Configure and enable USART0
  USART_InitAsync(USART0, &init);

  // Enable NVIC USART sources
  NVIC_ClearPendingIRQ(USART0_RX_IRQn);
  NVIC_EnableIRQ(USART0_RX_IRQn);
  NVIC_ClearPendingIRQ(USART0_TX_IRQn);
  NVIC_EnableIRQ(USART0_TX_IRQn);


  USART0->ROUTEPEN |= USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
}


void USART0_RX_IRQHandler(void)
{
  // Get the character just received
  buffer[inpos] = USART0->RXDATA;

  // Exit loop on new line or buffer full
  if ((buffer[inpos] != '\r') && (inpos < BUFLEN))
    inpos++;
  else
    receive = false;   // Stop receiving on CR

  // Clear the requesting interrupt before exiting the handler
  USART_IntClear(USART0, USART_IF_RXDATAV);
}

/**************************************************************************//**
 * @brief
 *    The USART0 transmit interrupt outputs characters.
 *****************************************************************************/
void USART0_TX_IRQHandler(void)
{
  // Send a previously received character
  if (outpos < inpos)
    USART0->TXDATA = buffer[outpos++];
  else
  /*
   * Need to disable the transmit buffer level interrupt in this IRQ
   * handler when done or it will immediately trigger again upon exit
   * even though there is no data left to send.
   */
  {
    receive = true;   // Go back into receive when all is sent
    USART_IntDisable(USART0, USART_IEN_TXBL);
  }
  // Clear the requesting interrupt before exiting the handler
  USART_IntClear(USART0, USART_IF_TXBL);
}

/**************************************************************************//**
 * @brief
 *    Main function
 *****************************************************************************/
int main(void)
{
  uint32_t i;

  // Chip errata
  CHIP_Init();

  // Initialize GPIO and USART0
  initGpio();
  initUsart0();

  while (1)
  {
    // Zero out buffer
    for (i = 0; i < BUFLEN; i++)
      buffer[i] = 0;

    // Enable receive data valid interrupt
    USART_IntEnable(USART0, USART_IEN_RXDATAV);

    // Wait in EM1 while receiving to reduce current draw
    while (receive)
      EMU_EnterEM1();

    // Disable receive data valid interrupt
    USART_IntDisable(USART0, USART_IEN_RXDATAV);

    // Enable transmit buffer level interrupt
    USART_IntEnable(USART0, USART_IEN_TXBL);

    // Wait in EM1 while transmitting to reduce current draw
    while (!receive)
      EMU_EnterEM1();

    // Reset buffer indices
    inpos = outpos = 0;
  }
}
 
Last edited:

mckenney

Joined Nov 10, 2018
125
It's typical for a peripheral to have many interrupt sources which are grouped together to trigger a single request to the NVIC. In that case, it's meaningful to be able to enable some and not others within the peripheral, and then configure the (union) NVIC request separately. It's not a requirement to do this, but it does avoid having a zillion vector entries.

In this case it appears they configured designed their USART peripheral to pass each interrupt source directly to the NVIC, which is fine too. You could equally ask if it's the NVIC_EnableIRQ that's redundant, but the NVIC is part of the Cortex-M4, so (as far as I know) they can't get rid of it.

[Edit: small wording change]
 

len_galasso

Joined Jul 13, 2020
1
This is an example of good practices, which will prevent spurious interrupts later. The former snippet clears any latched interrupt in the NVIC from the source (in this case USART transmitter fifo empty) which may have been active from power up, or since the last initialization sequence. The latter code enables the interrupt at its source. A final step (not shown) would be to enable the interrupt in the NVIC.

Failure to do this extra step may cause an immediate interrupt (the one latched, above) to be taken as soon as the interrupt is enabled in the NVIC. It may seem superfluous but it is not.
 
Top