cancel
Showing results for 
Search instead for 
Did you mean: 

Problem setting up UART on STM32F756VGH6

Vilius
Associate III

Hi,

I am learning and exploring the STM32F756VGH6. My goal is to setup a simple UART and send some data to the PC using USB-UART serial converter and  puTTy terminal on PC. I am using register based coding approach as it makes the code more efficient. However, the code provided down bellow (that I have written) is faulty. I strongly suspect the problem lies somewhere in my UART setup function (but I could not figure out where exactly), because if I omit it, main loops gets executed (it does not even jam in the UART_Send function even though the UART has not been initialized) and I see the background leds blinking. If I try to execute the UART setup function, the led turns on and it stays like that indefinitely, needless to say I do not get any signals on my TX/RX lines, those always stay at high level (I have checked it with a logic analyzer). Both TX/RX lines have a 5.1k pullups to +3.3V. I have written some simple codes for my current setup and it worked fine, so hardware issue is very unlikely. Any ideas to get this code moving? Thank you in advance.

 

#include "main.h"

void Core_Clock_Setup (void){

	RCC->CR |= RCC_CR_HSEON;               //Set the clock source to external crystal/resonator (HSE)
	while (!(RCC->CR & RCC_CR_HSEON));	   //Wait until clock gets stable

	RCC->APB1ENR |= RCC_APB1ENR_PWREN;     //Enable power interface clock
	PWR->CR1  &= ~(1U << 14);
	PWR->CR1  &= ~(1U << 15);              //Set internal voltage regulator to is reset value (scale 1)

	FLASH->ACR &= ~FLASH_ACR_ARTEN;        //Disable ART accelerator
	FLASH->ACR &= ~FLASH_ACR_ARTRST;       //Reset ART accelerator
	FLASH->ACR |= FLASH_ACR_PRFTEN;        //Enable prefetch
	FLASH->ACR |= FLASH_ACR_LATENCY_6WS;   //Set 7 CPU clock cycle flash memory access time (in order to get 200 MHz core clock)

	//@ 25 MHz crystal, 200 MHz core clock configuration down below

	RCC->CFGR &= ~(((1 << (7 - 4 + 1)) - 1) << 4);
	RCC->CFGR &= ~(1 << 4);                //Core clock division by 1 (core clock is not devided)
	RCC->CFGR &= ~(1 << 5);
	RCC->CFGR &= ~(1 << 6);
	RCC->CFGR &= ~(1 << 7);

	RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE;//HSE is set to be PLL entry

	RCC->PLLCFGR &= ~(1 << 16);              //PLLP Setting corresponding PLL prescalers (division by 2)
	RCC->PLLCFGR &= ~(1 << 17);

	RCC->PLLCFGR &= ~((1 << 6) - 1);
	RCC->PLLCFGR |= (16 & ((1 << 6) - 1));  //PLLM Setting corresponding PLL prescalers (division by 16)
	//RCC->PLLCFGR |= (16 << 0);

	RCC->PLLCFGR &= ~(((1 << (14 - 6 + 1)) - 1) << 6);
	RCC->PLLCFGR |= (256 << 6);            //PLLN Setting corresponding PLL prescalers ( multiplication by 256)

	RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;      //APB1 Low speed prescaler of 4 (50 MHz, max is 54 Mhz)
	RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;      //APB2 High speed prescaler of 2 (100 MHz, max is 108 Mhz)

	RCC->CR |= RCC_CR_PLLON;               //Enable PLL
	while (!(RCC->CR & RCC_CR_PLLRDY));	   //Wait until PLL gets stable

	RCC->CFGR |= RCC_CFGR_SW_PLL;          //PLL is set to be core clock


	//RCC->CFGR |= RCC_CFGR_SW_HSE;        //HSE is set to be core clock

	while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait until PLL indeed becomes core clock source
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Timer1_Setup(void){ //16 bit advanced timer

	RCC->DCKCFGR1 &= ~ (1 << 24);          //TIMxCLK = 2xPCLKx

	//When TIMPRE bit of the RCC_DCKCFGR1 register is reset, if APBx prescaler is 1, then TIMxCLK = PCLKx, otherwise
	//TIMxCLK = 2x PCLKx.
	// When TIMPRE bit in the RCC_DCKCFGR1 register is set, if APBx prescaler is 1,2 or 4, then TIMxCLK = HCLK, otherwise
	//TIMxCLK = 4x PCLKx.
	//TIM1 CLK is HCLK in this case

	RCC->APB2ENR |= (1 << 0);               //Enable Timer 1 clock
	TIM1->PSC = 99;                         //APB1 is 50 Mhz and 100 MHZ for timer (The number is set: Clock in MHz - 1) 1 full period equals 1 MHZ
	TIM1->ARR = 0xFFFF;                     //Auto reload at 100 ticks -> around 100 micro seconds at 100 MHz timer clock
	TIM1->CR1 |= (1 << 0);                  //Enable Timer 1 counter
	while(!(TIM1->SR & (1<<0)));            //Wait until timer update bit is set
}


void delay_ms (uint16_t ms){
	TIM1->CR1 = (1 << 0);
	for(uint16_t i = 0; i<ms; i++)
	{
		TIM1->CNT = 0;                      //Reset counter
		while (TIM1->CNT < 2000);           //Wait until counter reaches desired value
	}
	TIM1->CR1 &= ~(1 << 0);
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void GPIO_Setup(void){

	//PC14 OUTPUT                                                                  //LEDS

	RCC->AHB1ENR |= (1 << 2);				 //Enable clock for GPIO bank C
	RCC->AHB1ENR |= (1 << 4);                //Enable clock for GPIO bank E

	delay_ms(1);

	GPIOC->MODER |= (0b01 << 28);            //PC14 General purpose output mode
	GPIOC->OTYPER &= ~ (1 << 14);            //PC14 Output push-pull (reset state)
	GPIOC->OSPEEDR |= (0b11 << 28);          //PC14 very high GPIO speed
	GPIOC->PUPDR |= (0b10 << 28);            //PC14 pull down resistors
	//PC15 OUTPUT
	GPIOC->MODER |= (0b01 << 30);            //PC15 General purpose output mode
	GPIOC->OTYPER &= ~ (1 << 15);            //PC15 Output push-pull (reset state)
	GPIOC->OSPEEDR |= (0b11 << 30);          //PC15 very high GPIO speed
	GPIOC->PUPDR |= (0b10 << 30);            //PC15 pull down resistors
	//PE4 OUTPUT
	GPIOE->MODER |= (0b01 << 8);             //PE4 General purpose output mode
	GPIOE->OTYPER &= ~ (1 << 4);             //PE4 Output push-pull (reset state)
	GPIOE->OSPEEDR |= (0b11 << 8);           //PE4 very high GPIO speed
	GPIOE->PUPDR |= (0b10 << 8);             //PE4 pull down resistors
	//PE0 OUTPUT
	GPIOE->MODER |= (0b01 << 0);             //PE0 General purpose output mode
	GPIOE->OTYPER &= ~ (1 << 0);             //PE0 Output push-pull (reset state)
	GPIOE->OSPEEDR |= (0b11 << 0);           //PE0 very high GPIO speed
	GPIOE->PUPDR |= (0b10 << 0);             //PE0 pull down resistors
	//-----------------------------------------------------------------------------------
	//PE5 INPUT                                                                        ALL BUTTONS EXTERNALLY PULLED UP
	GPIOE->MODER |= (0b00 << 10);             //PE5 General purpose input mode
	//PE6 INPUT
	GPIOE->MODER |= (0b00 << 12);             //PE6 General purpose input mode

}

void UART1_Setup(){

	//RCC->APB2ENR = (1 << 4);         		  //USART1 clock enabled
	//TX1 at pin PA9 and RX1 at pin PA10

	GPIOA->MODER = (0b10 << 18);		 	  //Assign alternate function of UART to pin PA9
	GPIOA->MODER = (0b10 << 20);			  //Assign alternate function of UART to pin PA10

	GPIOA->OSPEEDR = (0b11 << 18);		 	  //Highest speed at pin PA9
	GPIOA->OSPEEDR = (0b11 << 20);			  //Highest speed at pin PA10

	GPIOA->PUPDR = (0b00 << 18);		 	  //No pullup, no pulldown resistor on PA9
	GPIOA->PUPDR = (0b00 << 20);              //No pullup, no pulldown resistor on PA10

	GPIOA->AFR[1] = (0b0111 << 4);            //Select alternate function as UART on pin PA9
	GPIOA->AFR[1] = (0b0111 << 8);	   		  //Select alternate function as UART on pin PA10

	RCC->AHB1ENR |= (1 << 0);                 //Enable clock for GPIO bank A

	USART1->CR1 = 0x00;                       //Reset register just in case
	USART1->CR1 = (0b00 << 28);               //M[1:0] = 00: 1 Start bit, 8 data bits, n stop bits
	USART1->CR1 &= ~ (1 << 15);               //Oversampling by 16

	USART1->BRR = 0x6C8;                      //fclk/baud rate 200MHz / 115200

	USART1->CR1 = (1 << 3);                   //Transmitter is enabled
	USART1->CR1 = (1 << 2);                   //Receiver is enabled

	RCC->APB2ENR = (1 << 4);         		  //USART1 clock enabled
	USART1->CR1 = (1 << 0);                   //USART enable
	}

void UART1_Send(uint8_t character){
	USART1->TDR = character;                   //Load data to transmit register
	//while(!(USART1->ISR & (1 << 6)));          //Wait until transmission is executed
}


uint8_t UART1_Receive (void){
	uint8_t character;
	while(!(USART1->ISR & (1 << 5)));          //Wait receive buffer fills up
	character = USART1->RDR;				   //Read the receive register
	return character;

}

int main (void){

	Core_Clock_Setup();
	Timer1_Setup();
	GPIO_Setup();
	UART1_Setup();

	GPIOC->BSRR = 0x4000;
	GPIOC->BSRR = (1 << 30);

	while(1){

		GPIOC->BSRR = (1 << 15);
		delay_ms(750);
		UART1_Send('S');
		GPIOC->BSRR = (1 << 31);
		delay_ms(750);
		UART1_Send('S');
	}

}

 

10 REPLIES 10

@Vilius wrote:

I am learning and exploring the STM32F756VGH6 ... I am using register based coding approach as it makes the code more efficient. 


Apart from the fallacy already noted by @Tesla DeLorean, trying to optimise while learning is probably not a great approach.

As the famous saying goes,

"premature optimisation is a root of all kinds of evil"