2024-11-27 09:14 AM
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');
}
}
2024-11-27 10:07 AM - edited 2024-11-27 10:08 AM
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