cancel
Showing results for 
Search instead for 
Did you mean: 

Setting up UART 1 on B-L475E-IOT01a using bare metal (Newbie)

B.Redmoon
Associate II

I can see an output in my serial monitor if i am using CubeMX and CubeIDE but with baremetal in Keil, I dont understand why i am not seeing any . I have a B-l475E-IOT01a board with me, and from the schematic I can see both UART1_TX and UART1_RX connected to ST-Link via PB6 and PB7.

//
//Objective: Use USART1 to transmit data to serial monitor software (Putty).
//
//
//USART1 uses APB2 bus
//USART1 is an alternate function of PA9 & PB6
//USART1_TX is alternate function AF7 of PA9 & PB6
//USART1_RX is an alternate function of PA10 & PB7.
//
//PA2, PA3, PD5, PD6, PA9, PB6, PA10 & PB7 all use the AHB2 bus.
 
//ST-Link UART1_TX & UART1_RX connected to PB6 and PB7
               
#include "stm32l4xx.h"  
#include "stm32l475xx.h"                  // Device header
 
 
void usart1_init(void);
void usart1_write(int ch);
void delayMS(int delay);
 
int main(void){
	usart1_init();
	
	while(1){
		usart1_write('S');
	  usart1_write('T');
		usart1_write('M');
		usart1_write('3');
		usart1_write('2');
		delayMS(100);
	}
}
 
void usart1_init(void){
	
RCC->APB2ENR |= (1<<14);  	//Bit 14 in RCC_APB2ENR is used to enable USART1 clock
//RCC->AHB2ENR |= (1<<0);    	//Bit 0 in RCC_AHB2ENR is used to enable GPIOA clock
RCC->AHB2ENR |= (1<<1); 		//Bit 1 in RCC_AHB2ENR is used to enable GPIOB clock 
	
//GPIOA->MODER &=~ (0xC0000);		//PA9: Set Port A Pin 9 to "Analog Mode(Reset State)"
//GPIOB->MODER &=~ (0x3000);		//PB6: Set Port B Pin 6 to "Analog Mode(Reset State)" 
	
//GPIOA->MODER |= (1<<19);		      //Set PA9 to alternate Function mode 
GPIOB->MODER |= (1<<13);	             //Set PB6 to alternate Function mode
		
GPIOA->AFR[1] = (0x70);	  	            /Set PA9 alternate function to USART1_TX 
GPIOB->AFR[0] = (0x7000000);	            //Set PB6 alternate function to USART1_TX 
 
GPIOA->AFR[1] = (0x70);	  		//Set PA10 alternate function to USART1_RX
GPIOB->AFR[0] = (0x70000000);	  	//Set PB7 alternate function to USART1_RX 
	
		
//USART1->BRR = (0x0045);		//15 bits | 0000 0000 0100 0101 ~ 0x0045 |SysClk/ 
                                                                //Baudrate = 8MHz/115200	
//USART1->BRR = (0x0683);
USART1->BRR = 0x8b;
	
USART1->CR1 |= (1<<3);     		// Enable TE (Transmitter)
USART1->CR1 |= (1<<2);     		//Enable RE (Receiver)
	
USART1->CR1 |= (1<<0);     		// Enable USART
}
 
void usart1_write(int ch){
	//wait while TX buffer is empty
	while(!(USART1->ISR & 0x80)){} 		
		USART1->TDR = (ch & 0xFF);   	
}
void delayMS(int delay){
	int i;
	for(;delay>0;delay--){
		for(i=0;i<3195;i++);
	}
}

8 REPLIES 8
TDK
Guru

This statement:

> GPIOB->AFR[0] = (0x7000000);

gets overwritten by:

> GPIOB->AFR[0] = (0x70000000);

Your delayMS function may or may not do anything, depending on compiler settings.

Could be other issues.

Also no way these comments are both correct, since the statement is identical. The first one won't even compile since it's missing a slash.

> GPIOA->AFR[1] = (0x70); /Set PA9 alternate function to USART1_TX

> GPIOA->AFR[1] = (0x70); //Set PA10 alternate function to USART1_RX

Edit: changed my response which was initially incorrect.

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

For a bare metal delay function look at:

https://community.st.com/s/question/0D53W00000BJ7KdSAL/is-haldelay1-quaranteed-to-be-close-to-1ms

Need to enable the DWT counter:

void	bspTsInit_ (void)
{
	/* DWT cycle counter enable. The M7 requires DWT unlocking.*/
 
	CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk ;
 
	#if defined __CM7_REV
		DWT->LAR = 0xC5ACCE55U ;
	#endif
 
	DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk ;
 
	// DWT->CYCNT frequency is SystemCoreClock Hz
	// Compute divider to convert delta values to microseconds
	bspTsMhzDiv = SystemCoreClock / 1000000u ;
}

B.Redmoon
Associate II

Thanks TDK. Yes, my values at GPIO-> AFR gets over written and so I have deleted the part related to RX as I dont need it yet at this point. I am just trying to output a character to serial monitor. Now I have cleaned up the code and I am able to see some characters displayed but it is no where near the expected characters. For BRR calculation I have used the formula usartdiv = ***/(16*baudrate) where *** is 8MHz (XTAL freq). I have read read somewhere that I should use the APB2 bus clock instead which in my case is 80MHz. I have tried using this but I dont see any output at the serial monitor. I am using the BL475E-IOT01a board.

The delayMS function was copied from the tutorial I was using so it should somehow work. I just use his code as reference as he was using a different stm32 chip. Another thing, in keil target options, what shoudl i use as value of core clock? is it 80MHz?

//
//Objective: Use USART1 to transmit data to serial monitor software (Putty).
//
//USART1 uses APB2 bus
//USART1 is an alternate function of PA9 & PB6
//USART1_TX is alternate function AF7 of PA9 & PB6
//USART1_RX is an alternate function of PA10 & PB7.
//
//PA2, PA3, PD5, PD6, PA9, PB6, PA10 & PB7 all use the AHB2 bus.
 
//ST-Link UART1_TX & UART1_RX connected to PB6 and PB7
               
#include "stm32l4xx.h"  
#include "stm32l475xx.h"                  // Device header
 
 
void usart1_init(void);
void usart1_write(int ch);
void delayMS(int delay);
 
int main(void){
	usart1_init();
	
	while(1){
		usart1_write('S');
		usart1_write('T');
		delayMS(100);
	}
}
 
void usart1_init(void){
	
RCC->APB2ENR |= (1AHB2ENR |= (1MODER &=~ (0x3000);		   //PB6: Set Port B Pin 6 to "Analog Mode(Reset State)" 
	
GPIOB->MODER |= (1AFR[0] = (0x7000000);	  		//Set PB6 alternate function to USART1_TX 
	
USART1->BRR = (0x683);       			//(2x 8Mhz) div 9600 = 1667 = 0x683 **
		 	
USART1->CR1 |= (1CR1 |= (1CR1 |= (1ISR & 0x80)){} 	
		USART1->TDR = (ch & 0xFF);
}
 
void delayMS(int delay){
	int i;
	for(;delay>0;delay--){
		for(i=0;i

 


_legacyfs_online_stmicro_images_0693W0000059P3c.png
_legacyfs_online_stmicro_images_0693W0000059P3X.png

Thanks @Nikita91​ . I will take a look into it.

TDK
Guru

> RCC->APB2ENR |= (1AHB2ENR |= (1MODER &=~ (0x3000); //PB6: Set Port B Pin 6 to "Analog Mode(Reset State)"

> GPIOB->MODER |= (1AFR[0] = (0x7000000); //Set PB6 alternate function to USART1_TX

> ...

> USART1->CR1 |= (1CR1 |= (1CR1 |= (1ISR & 0x80)){}

Something is wrong with your formatting. None of these statements will compile. Hard to see the issue when you're showing code that doesn't compile.

If you feel a post has answered your question, please click "Accept as Solution".
B.Redmoon
Associate II
//
//Objective: Use USART1 to transmit data to serial monitor software (Putty).
//
//USART1 uses APB2 bus
//USART1 is an alternate function of PA9 & PB6
//USART1_TX is alternate function AF7 of PA9 & PB6
//USART1_RX is an alternate function of PA10 & PB7.
//
//PA2, PA3, PD5, PD6, PA9, PB6, PA10 & PB7 all use the AHB2 bus.
 
//ST-Link UART1_TX & UART1_RX connected to PB6 and PB7
               
#include "stm32l4xx.h"  
#include "stm32l475xx.h"                  // Device header
 
 
void usart1_init(void);
void usart1_write(int ch);
void delayMS(int delay);
 
int main(void){
	usart1_init();
	
	while(1){
		usart1_write('S');
		usart1_write('T');
		delayMS(100);
	}
}
 
void usart1_init(void){
	
RCC->APB2ENR |= (1<<14);  		//Bit 14 in RCC_APB2ENR is used to enable USART1 clock
RCC->AHB2ENR |= (1<<1); 			//Bit 1 in RCC_AHB2ENR is used to enable GPIOB clock
	
GPIOB->MODER &=~ (0x3000);		  //PB6: Set Port B Pin 6 to "Analog Mode(Reset State)" 
	
GPIOB->MODER |= (1<<13);		 //Set PB6 to alternate Function mode
		
GPIOB->AFR[0] = (0x7000000);	  	//Set PB6 alternate function to USART1_TX 
	
USART1->BRR = (0x683);       		//(2x 8Mhz) div 9600 = 1667 = 0x683 **
		 	
USART1->CR1 |= (1<<3);     		//Enable TE (Transmitter)
USART1->CR1 |= (1<<2);     		//Enable RE (Receiver)
	
USART1->CR1 |= (1<<0);     		//Enable USART
}
 
void usart1_write(int ch){
	//wait while TX buffer is empty
	while(!(USART1->ISR & 0x80)){} 	
		USART1->TDR = (ch & 0xFF);
}
 
void delayMS(int delay){
	int i;
	for(;delay>0;delay--){
		for(i=0;i<3195;i++);
	}
}	

Tried copying it again as the code snippet messed everything up

B.Redmoon
Associate II

I have used the formula usartdiv = FClock/(16*Baudrate) for a value of 0x341 at 80MHz, 9600 baud for BRR. Serial monitor output will then just be a bunch of ff ff ffs ....

B.Redmoon
Associate II

I finally got to make it work. In L475 chip, default core clock is 4Mz. usartdiv = Fclock/9600 for a value of 0x1A0.

USART1->BRR = (0x1A0);