AnsweredAssumed Answered

USART Interrupt triggered too often

Question asked by ott.simon on May 15, 2014
Latest reply on May 18, 2014 by ott.simon
I'm using USART with circular buffers and interrupts to transmit and receive. 
To transmit, a byte is written to the buffer, the TXE interrupt is enabled and then the byte is sent and theTXE Flag is cleared in the interrupt. At certain speed and send frequency (often I send a certain string every 20ms) it works fine, but sometimes, the interrupt seems to be called immediately again after being left and the whole buffer is sent via USART. 

I found the following answer with SPI in the forum: 
Watch the following well known issue regarding disabling the interrupt inside the ISR: due to the cortex core architecture the interrupt being disabled in the ISR shortly before the ISR returns can cause the ISR to trigger again immediately. There are two solutions:
1 - to place enough code between the instruction that disables the interrupt and the end of the ISR - often that is the case, and people never experience the bug.
2 - to place __DSB() call at the end of the ISR - see core_cmInstr.h from CMSIS.

I placed the __DSB() call at the end of the ISR, but this doesn't seem to change anything. 
Are there other possibilities/solutions or any ideas that can cause this behaviour? The same buffer algorithm works fine for CAN transmission and receive which is much faster so I can't imagine that the buffer causes the problem. 

This is my ISR: 
void USART1_IRQHandler(void)
{
    uint8_t ch;
 
    if (USART_GetITStatus(USART_CCU, USART_IT_RXNE) != RESET)
    {
        ch = (uint8_t) USART_ReceiveData(USART_CCU);
        //put char to the buffer
        USART_BufferWrite((USART_FIFO_TypeDef*) &USART_RxBuffer, ch);
    }
    if (USART_GetITStatus(USART_CCU, USART_IT_TXE) != RESET)
    {
        if (!USART_BufferIsEmpty((USART_FIFO_TypeDef*) &USART_TxBuffer))
        {
            USART_BufferRead((USART_FIFO_TypeDef*) &USART_TxBuffer, &ch);
            USART_SendData(USART_CCU, ch);
        }
        else //if buffer empty
        {
            //disable Transmit Data Register empty interrupt
            USART_ITConfig(USART_CCU, USART_IT_TXE, DISABLE);
        }
    }
}


And if it helps, the USART Setup: 
void USART_Setup(uint32_t USART_BaudRate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_Initstructure;
 
    USART_BufferInit((USART_FIFO_TypeDef*) &USART_RxBuffer);
    USART_BufferInit((USART_FIFO_TypeDef*) &USART_TxBuffer);
 
    USART_InitStructure.USART_BaudRate = USART_BaudRate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl =
            USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
 
    //configure clock for USART
    RCC_APB2PeriphClockCmd(USART_CLOCK, ENABLE);
    //configure AF
    GPIO_PinAFConfig(USART_PORT, USART_TX_SOURCE, GPIO_USART_MAPPING);
    GPIO_PinAFConfig(USART_PORT, USART_RX_SOURCE, GPIO_USART_MAPPING);
 
    //configure ports, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin = USART_RXD | USART_TXD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(USART_PORT, &GPIO_InitStructure);
 
    USART_Init(USART_CCU, &USART_InitStructure);
    USART_Cmd(USART_CCU, ENABLE);
 
    NVIC_Initstructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 0x0;
    NVIC_Initstructure.NVIC_IRQChannelSubPriority = 0x6;
    NVIC_Init(&NVIC_Initstructure);
    USART_ITConfig(USART_CCU, USART_IT_TXE, DISABLE);
    USART_ITConfig(USART_CCU, USART_IT_RXNE, ENABLE);
 
    //Settings for printf and scanf
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);
}

Outcomes