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');
	}

}

 

1 REPLY 1

Enable UART and GPIO clock in RCC *before* you write into its registers. 

Also, you are writing several times into the same register, overwriting is perhaps content. 

Observing content of registers (carefully, e.g. reading UART DR clears the RXNE flag) is helpful in understanding what happens in the hardware. 

JW