STM32F411RE Unable to make UART work.
Hello guys.
I've been trying to learn how to program STM32 MCU's using registers.
This time, I've attempted to configure a basic UART programm in which I would like to send whatever I receive via UART back to the source. Basically an echo program.
I'm interfacing a STM32F411RE on a nucleo board with a USB RS232 module towards putty. Nonetheless, no matter what I type on my PC, the MCU does not appear to be sending that data back to the computer
I've tried setting the system clock to 100 MHz by configuring the following parameters for clocking:
*Internal 16MHz oscilator used as clocking source
*PLL M factor = /8
*PLL N factor= x100
*PLL P factor= /2
*PLL Q factor= /4
*AHB Prescaler: 1
*APB1 Prescaler: /2
*APB2 Prescaler: /1
*Calculations are made in order to set baud rate to 9600
I'm including my code here below. I've tried debugging it using Keil's debugging feature. I've noticed that the GPIOA and GPIOB clocks do not seem to be enabled after the MCU runs the following two lines: (In other words, both registers stay at 0 eventhough I'm setting them to 1)
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
I don't know if the fact I'm modifying clocking has something to do with this or if this is just a stetic issue with the debugger
If you do find something off with my code, please let me know
Thank you very much in advance.
#include "stm32f4xx.h"
/*
STM32F411 UART
PINS FOR UART
Port A_15 ->>>> UART1_TX
Port B_7 ->>>> UART1_RX
*/
int main(){
// TODO Configure main clock(?) to run at 100 MHz
//Shut PLL Off
RCC->CR &= ~RCC_CR_PLLON;
//Set PLL Source as HSI
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLSRC;
//Set PLL M value to 8 in dec
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_5; //0
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_4; //0
RCC->PLLCFGR |= RCC_PLLCFGR_PLLM_3; //1
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_2; //0
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_1; //0
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_0; //0
//Set PLL P Value to 0 in DEC. Datasheet states 0 equals 2
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP_0;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP_0;
//SET PLL Q Value to 4 in DEC
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ_3;
RCC->PLLCFGR |= RCC_PLLCFGR_PLLQ_2;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ_1;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ_0;
//Set PLL N value to 100 in dec
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_8; //0
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_7; //0
RCC->PLLCFGR |= RCC_PLLCFGR_PLLN_6; //1
RCC->PLLCFGR |= RCC_PLLCFGR_PLLN_5; //1
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_4; //0
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_3; //0
RCC->PLLCFGR |= RCC_PLLCFGR_PLLN_2; //1
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_1; //0
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_0; //0
//Set APB2 Values TO 2
RCC->CFGR |= RCC_CFGR_PPRE2_2; //1
RCC->CFGR &= ~RCC_CFGR_PPRE2_1; //0
RCC->CFGR &= ~RCC_CFGR_PPRE2_0; //0
//Set APB1 Values TO 1 or No Div
RCC->CFGR &= ~RCC_CFGR_PPRE1_2; //0
//RCC->CFGR |= RCC_CFGR_PPRE1_1; //Datasheet marks this as X when div is set to 1
//RCC->CFGR |= RCC_CFGR_PPRE1_0; //Datasheet marks this as X when div is set to 1
//Set AHB Values to 1 or No Div
RCC->CFGR &= ~RCC_CFGR_HPRE_3; //0
//RCC->CFGR |= RCC_CFGR_HPRE_2; //Datasheet marks this as X when div is set to 1
//RCC->CFGR |= RCC_CFGR_HPRE_1; //Datasheet marks this as X when div is set to 1
//RCC->CFGR |= RCC_CFGR_HPRE_0; //Datasheet marks this as X when div is set to 1
//Set PLL as System Clock. "10" Sets PLL as System Clock
RCC->CFGR |= RCC_CFGR_SW_1;
RCC->CFGR &= ~RCC_CFGR_SW_0;
//Enable HSI
RCC->CR |= RCC_CR_HSION;
while(!(RCC->CR & RCC_CR_HSIRDY));
//Re-enable PLL
RCC->CR |= RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY));
//Enable clock for ports
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
//Enable clock for USART
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
//Define what alternate function will be used
/*
AF7 = UART
0111: AF7
Port A_15 ->>>> UART1_TX
Port B_7 ->>>> UART1_RX
For each GPIO pins 0 through 7 are set in AFR[0] which is called GPIOx_AFRL
For GPIO pins 8 through 15 set the corresponding 4 bits for the desired pin in AFR[1] which is called GPIOx_AFRH on the next page in the RM.
*/
GPIOA->AFR[1] &= ~GPIO_AFRH_AFRH7_3;
GPIOA->AFR[1] |= GPIO_AFRH_AFRH7_2;
GPIOA->AFR[1] |= GPIO_AFRH_AFRH7_1;
GPIOA->AFR[1] |= GPIO_AFRH_AFRH7_0;
GPIOB->AFR[0] &= ~GPIO_AFRL_AFRL7_3;
GPIOB->AFR[0] |= GPIO_AFRL_AFRL7_2;
GPIOB->AFR[0] |= GPIO_AFRL_AFRL7_1;
GPIOB->AFR[0] |= GPIO_AFRL_AFRL7_0;
//Define pins as alternate function pins
GPIOA->MODER |= GPIO_MODER_MODE15_1;
GPIOA->MODER &= ~GPIO_MODER_MODE15_0;
GPIOB->MODER |= GPIO_MODER_MODE7_1;
GPIOB->MODER &= ~GPIO_MODER_MODE7_0;
// TODO Define Baud Rate
//Considering a system clock of 100 MHz
USART1->BRR = 0x28B1;
//Enable RX, TX and UART itself
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
//Check if anything has been received using the SR RXNE flag
while(1)
{
if(USART1->SR & USART_SR_RXNE)
{
//Take what we got
char payload = USART1->DR;
//Send it back
USART1->DR = payload;
//Wait until data is sent
while(!(USART1->SR & USART_SR_TC));
}
}
}