cancel
Showing results for 
Search instead for 
Did you mean: 

CLOSED - USART receiver not working on F446RE MCU

FGiai.1
Associate II

Hello all,

I'm trying to implement a really simple exercise:

  1. Send a char via USART2 (PA2);
  2. Receive the char via USART1 (PA10);
  3. After the char is received, within an interrupt I increase a variable called "Debug".

The only HW connection done is that between PA2 and PA10.

The send process works correctly, because I can see the char sent via USART2 in the console.

At the contrary, the part related to the receiver doesn't work. I don't see in any case the Debug variable increasing.

Can someone help me to the debug the code (see below)?

Thank you in advance,

Federico.

#include "main.h"
 
/* Initialize GPIO PA2 pin */
void GPIO_Init_PA2(void)
{
	/* Enable IO port A clock */
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
 
	/* Configure the I/O direction mode */
	// 10: Alternate function mode
	GPIOA->MODER &= ~GPIO_MODER_MODE2_0;
	GPIOA->MODER |=  GPIO_MODER_MODE2_1;
 
	/* Configure the I/O alternate function */
	// 0111: AF7 (i.e. USART2_TX for GPIO PA2 pin)
	GPIOA->AFR[0] |=  GPIO_AFRL_AFRL2_0;
	GPIOA->AFR[0] |=  GPIO_AFRL_AFRL2_1;
	GPIOA->AFR[0] |=  GPIO_AFRL_AFRL2_2;
	GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL2_3;
}
 
/* Initialize USART USART2 */
void USART_Init_USART2(void)
{
	/* Enable USART2 clock */
	RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
 
	/* Enable USART2 */
	USART2->CR1 |= USART_CR1_UE;
 
	/* Select the word length */
	// 0: 1 Start bit, 8 Data bits, n Stop bits
	USART2->CR1 &= ~USART_CR1_M;
 
	/* Select number of stop bits */
	// 00: 1 Stop Bit
	USART2->CR2 &= ~USART_CR2_STOP_0;
	USART2->CR2 &= ~USART_CR2_STOP_1;
 
	/* Select the baud rate */
	USART2->BRR = (8 << 4) | 10;
 
	/* Select parity */
	// 0: Even parity
	//USART2->CR1 &= ~USART_CR1_PS;
 
	/* Enable transmitter */
	USART2->CR1 |= USART_CR1_TE;
}
 
/* Initialize GPIO PA10 pin */
void GPIO_Init_PA10(void)
{
	/* Enable IO port A clock */
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
 
	/* Configure the I/O direction mode */
	// 10: Alternate function mode
	GPIOA->MODER &= ~GPIO_MODER_MODE10_0;
	GPIOA->MODER |=  GPIO_MODER_MODE10_1;
 
	/* Configure the I/O alternate function */
	// 0111: AF7 (i.e. USART1_RX for GPIO PA10 pin)
	GPIOA->AFR[1] |=  GPIO_AFRH_AFSEL10_0;
	GPIOA->AFR[1] |=  GPIO_AFRH_AFSEL10_1;
	GPIOA->AFR[1] |=  GPIO_AFRH_AFSEL10_2;
	GPIOA->AFR[1] &= ~GPIO_AFRH_AFSEL10_3;
}
 
/* Initialize USART USART1 */
void USART_Init_USART1(void)
{
	/* Enable USART1 clock */
	RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
 
	/* Enable USART1 */
	USART1->CR1 |= USART_CR1_UE;
 
	/* Select the word length */
	// 0: 1 Start bit, 8 Data bits, n Stop bits
	USART1->CR1 &= ~USART_CR1_M;
 
	/* Select number of stop bits */
	// 00: 1 Stop Bit
	USART1->CR2 &= ~USART_CR2_STOP_0;
	USART1->CR2 &= ~USART_CR2_STOP_1;
 
	/* Select the baud rate */
	USART1->BRR = (8 << 4) | 10;
 
	/* Select parity */
	// 0: Even parity
	//USART1->CR1 &= ~USART_CR1_PS;
 
	/* Enable RXNE interrupt */
	// 1: An USART interrupt is generated whenever ORE=1 or RXNE=1 in the USART_SR register
	USART1->CR1 |= USART_CR1_RXNEIE;
 
	/* Set interrupt priority */
	NVIC_SetPriority(USART1_IRQn, 1);
 
	/* Enable interrupt */
	NVIC_EnableIRQ(USART1_IRQn);
 
	/* Enable receiver */
	USART1->CR1 |= USART_CR1_RE;
}
 
/* Transmit via USART */
void USART_Transmit(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size)
{
	/* For cycle to transmit byte by byte */
	for(uint16_t Index = 0; Index <= Size - 1; Index = Index + 1)
	{
		/* Wait until the data transmission register is empty */
		// This bit is set by HW when the content of the TDR register has been transmitted into the shift register. An interrupt is generated if the TXIE bit = 1 in the USART_CR1 register. It is cleared by a write to the USART_DR register
		while((USARTx->SR & USART_SR_TXE) == 0);
 
		/* Write data to be transmitted */
		USARTx->DR = *pData; // This clears the TXE bit
 
		/* Wait until transmission is complete */
		// TC bit is set by HW if the transmission of a frame containing data is complete and if TXE is set. An interrupt is generated if TCIE = 1 in the USART_CR1 register.
		while((USARTx->SR & USART_SR_TC) == 0);
 
		/* Pointer increase by 8 bits */
		pData = pData + 1;
	}
}
 
/* Receive via USART */
void USART_Receive(USART_TypeDef *USARTx, uint8_t *pData, uint16_t Size)
{
	/* Wait until the read data receive register is not empty */
	// When a character is received, the RXNE bit is set. It indicates that the content of the shift reister is transferred to the RDR. IN other words, data has been received and can be read (as well as its associated error flags)
	//while((USARTx->SR & USART_SR_RXNE) == 0);
 
	/* Read data received */
	*pData = USARTx->DR; // This clears the RXNE bit to the USART_DR register.
}
 
uint32_t Counter = 0;
void USART1_IRQHandler(void)
{
	Counter = Counter + 1;
}
 
/* Main */
int main(void)
{
	/* Initialize GPIO PA2 pin */
	GPIO_Init_PA2();
 
	/* Initialize USART USART2 module */
	USART_Init_USART2();
 
	/* Initialize GPIO PA10 pin */
	GPIO_Init_PA10();
 
	/* Initialize USART USART1 module */
	USART_Init_USART1();
 
	/* Buffer */
	char DataTx = 'A';
 
	/* Infinite loop */
	while(1)
	{
		/* Transmit via USART2 */
		USART_Transmit(USART2, (uint8_t *)&DataTx, 1);
	}
}

16 REPLIES 16

You chose to do register level code, expect to have to debug it too. Review the register content in the debugger, check it is as expected/desired.

Quick observation, don't you have to enable the uart last? Pretty sure the BRR can't be set when UE asserted. You can set the Transmit and Receive enables early.

Also your code is really inefficient, isn't the point of register level programming that it be small, efficient, and do everything in the LEAST moves possible?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

Do the baud rates match? Note that USART1 and USART2 are in different domains and (usually) have different base clock rates.

You also need the clear the RXNE flag, otherwise the IRQ handler is just going to retrigger. You don't actually call USART_Receive anywhere.

> Quick observation, don't you have to enable the uart last? Pretty sure the BRR can't be set when UE asserted. You can set the Transmit and Receive enables early.

Actually, the opposite. UE is set first, then BRR, then TE/RE.

If you feel a post has answered your question, please click "Accept as Solution".
FGiai.1
Associate II

1) Do the baud rates match? Note that USART1 and USART2 are in different domains and (usually) have different base clock rates.

I repeated the "exercise" also adding the default clock configuration generated by CubeMX and nothing changed.

2) You also need the clear the RXNE flag, otherwise the IRQ handler is just going to retrigger. You don't actually call USART_Receive anywhere.

You are right. I modified the IRQHandler clearing the register. Nothing changed.

And what do you expect to happen? You have nothing relevant to USART in the ISR.

jW

FGiai.1
Associate II

I expect that, during debugging, the value of "Counter" increases by 1 every time a the USART1 receives something (and so every time USART2 transmits something). Insted, the value is fixed to 0.

Qualify Counter as volatile.

JW

TDK
Guru

Gotta be an answer somewhere, but I don't see it. If you're super stuck, go use HAL to do the same thing and compare the register values between what it does and what you do.

Could also set PA10 as a GPIO and verify it's connected to the pin you think it's connected to, and that nothing else is on there.

If you feel a post has answered your question, please click "Accept as Solution".
FGiai.1
Associate II

Also setting the counter as volatile nothing changes.

In this case I see that It increases but only because the code enters in the handler because of ORE =1. I see that a lot of times there is IDLE =1, ORE =1.​

​I already tried to use the HAL, but I got the Sand situation.

TDK
Guru

> because the code enters in the handler because of ORE =1

The Overrun Error bit getting set indicates it is receiving values.

Is this a C++ file? If so, USART1_IRQHandler won't be getting called without C linkage.

> the value is fixed to 0.

Your story isn't making complete sense. If the code is entering the handler, the counter should be increasing in value. But you're also saying the counter stays at 0 which indicates it doesn't enter the handler. I feel like your current code and the code posted in the OP may have diverged significantly.

If you feel a post has answered your question, please click "Accept as Solution".