zainka
zainka

Reputation: 371

STM32F407 USART1 : Clearing USART_FLAG_TC requires pgm to be halted before actually clearing the bit

When initializing USART1 on STM32F407 I have run into a problem when enabling TC interrupt. The TC flag in SR is set ('1') as soon as the USART RCC is enabled and clearing the flag before enabling TC interrupt has become a headache for me because it throws a TC interrupt as soon as UART_IT_TC is enabld. i.e. this is a startup problem.

By writing 0 to the flag in status register (SR) when initializing the USART and before enabling interrupts should clear the flags. But it does not when I run the program straight trough, but (!!!) if having a breakpoint and stepping trough the code where SR is cleared works fine, TC flag is set to 0.

Therefor i always get a TC interrupt even before transmitting anything if I run the code without a breakpoint. And then another one after transmitting a character, naturally. But when I was using a breakpoint where TC flag is cleared gives only one TC IRQ and thats when actually transmitting something.

Inside the IRQ handler I also clear the flags by writing 0 to SR register and this works without any breakpoint. Both transmitting and receiving data works well after this.

So, timing issue was in my mind, but adding even an second delay did not change behavior and then it should not work clearing the SR register later either. Or? Does USARTs require settling time for RCC before initializing the USART?

void Console_init(long baud)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  USART_InitTypeDef USART_InitStruct;
  NVIC_InitTypeDef NVIC_InitStruct;

  /* Init clock domains */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  /* Set alternate functions */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

  /* Init GPIO pins */
  GPIO_StructInit(&GPIO_InitStruct);
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz;
  GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* Configure UART setup */
  USART_StructInit(&USART_InitStruct);
  USART_InitStruct.USART_BaudRate = baud;
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
  USART_InitStruct.USART_Parity = USART_Parity_No;
  USART_InitStruct.USART_StopBits = USART_StopBits_1;
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;
  USART_Init(USART1, &USART_InitStruct);

  /* Enable global interrupts for USART */
  NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  NVIC_Init(&NVIC_InitStruct);

  /* Clear old interrupt flags and enable required IRQs*/
  USART1->SR = 0;

  /* Enable USART */
  USART_Cmd(USART1, ENABLE);    
}


void console_transmit(void)
{  
  USART_ITConfig(USART1, USART_IT_TC, ENABLE);
  USART1->DR = 0x55;
}

void USART1_IRQHandler(void)
{
  if (USART1->SR & USART_FLAG_TC)
  {
    USART_ITConfig(USART1, USART_IT_TC, DISABLE);
  }

  USART1->SR = 0;
}

In this code I will get two interrupts on TC, one as soon I enables TC and one after character is transmitted. This code is what I am using now while trying to understand the issue.

Note: I have also tried to clear the SR inside console_transmit before enabling TC but to no help. It almost like it requires to be cleared inside the interrupt handler.

Upvotes: 0

Views: 1562

Answers (1)

user58697
user58697

Reputation: 7923

I think this is a conceptual misunderstanding.

A transmit interrupt does not tell you that something has been transmitted. It tells you that there is space in the buffer, and it is OK to push data to the UART. Of course at the startup the UART buffer is empty, and you are getting an interrupt as soon as you enable it. It is not a matter of timing. It is an expected behavior.

Such design makes the transmit flow very straightforward:

  • the mainline code prepares the buffer, and enables the interrupt
  • the ISR moves data to UART until either UART is full or there is no more data to send, and
  • once there is no more data to send, the ISR disables the interrupt

Upvotes: 1

Related Questions