2020-12-24 05:06 PM
I was trying to configure USART on an STM32L476 Discovery board. I know that register level coding is not great but it really works well for what I need to use the board for. I was able to send messages out using the transmit but I'm not able to get the receiver to work. When I investigated with a scope I could see that the characters I was sending were appearing at the Rx pin of the MCU but the RXNE pin doesn't seem to be setting. Any help would be greatly appreciated. Here is my main.cpp:
#include "mbed.h"
#include "stm32l476xx.h"
#include <string.h>
#define GPIO_MODER_AF 0x2UL //select alternate function for GPIO
#define GPIO_OSPEEDR_VHS 0x3UL //High speed GPIO
#define GPIO_AFR_AF7 0x7UL //alternate function 7
void setMSI(double frequency); //function to set MSI frequency
void setLatency(); //function to set flash read latency
void init_GPIOA();//initialise GPIOA
void printserial(char[]); //print serial message on USART Tx
double F_CPU = 80; //frequency of CPU in MHZ
// main() runs in its own thread in the OS
int main()
{
init_GPIOA();
setMSI(4);
//USART GPIO init
//PA2 and PA3 as alternate functions
GPIOA->MODER = (GPIOA->MODER & (~GPIO_MODER_MODE2_Msk) & (~GPIO_MODER_MODE3_Msk)) | (GPIO_MODER_AF << GPIO_MODER_MODE2_Pos) | (GPIO_MODER_AF << GPIO_MODER_MODE3_Pos);
//very high speed output
GPIOA->OSPEEDR |= (GPIO_OSPEEDR_VHS << GPIO_OSPEEDR_OSPEED2_Pos) | (GPIO_OSPEEDR_VHS << GPIO_OSPEEDR_OSPEED3_Pos);
//configure as pull up
GPIOA->PUPDR = (GPIOA->PUPDR & (~GPIO_PUPDR_PUPD2_Msk) & (~GPIO_PUPDR_PUPD3_Msk)) | GPIO_PUPDR_PUPD2_0 | GPIO_PUPDR_PUPD3_0;
//Alternate function 7 for both pins
GPIOA->AFR[0] = (GPIOA->AFR[0] & (~GPIO_AFRL_AFSEL2_Msk) & (~GPIO_AFRL_AFSEL3_Msk)) | (GPIO_AFR_AF7 << GPIO_AFRL_AFSEL2_Pos) | (GPIO_AFR_AF7 << GPIO_AFRL_AFSEL3_Pos);
//calculate div register value based on baud
unsigned long baud = 9600;
uint32_t usart_div = uint32_t(long(F_CPU * 1000000)/baud);
USART2->BRR = usart_div; //programmme baud rate
RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN; //enble USART2 clock
RCC->CCIPR |= (RCC->CCIPR & ~RCC_CCIPR_USART2SEL_Msk) | RCC_CCIPR_USART2SEL_0; //select system clock as USART clock
USART2->CR1 |= USART_CR1_UE; //enable USART
USART2->CR1 |= USART_CR1_TE; //enable transmitter
USART2->CR1 |= USART_CR1_RE; //enable reciever
char worked[] = "It Worked \n\r"; //message to send out
char didntwork[] = "It Didnt Work \n\r"; //message to send out
while (true) {
//if character recieved in RDR, print 'It worked'
if ((USART2->ISR & USART_ISR_RXNE) == USART_ISR_RXNE){
printserial(worked);
USART2->RQR |= USART_RQR_RXFRQ; // clear RXNE bit
}
}
}
//print message on USART Tx
void printserial(char send[]){
int length = strlen(send);
for (int i=0; i<=length; i++){
USART2->TDR = send[i];
while ((USART2->ISR & USART_ISR_TXE) != USART_ISR_TXE){int p = 0;}
}
}
//initialise GPIOA
void init_GPIOA(){
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN; //enable AHB clock for GPIO A
}
//set MSI as system clock with chosen frequency
void setMSI(double frequency){
if (frequency > F_CPU){
// function to increase frequency
setLatency();
}
//find required frequency range
unsigned long range = RCC_CR_MSIRANGE_6;
if (frequency == 0.1){range = RCC_CR_MSIRANGE_0;}
else if (frequency == 0.2){range = RCC_CR_MSIRANGE_1;}
else if (frequency == 0.4){range = RCC_CR_MSIRANGE_2;}
else if (frequency == 0.8){range = RCC_CR_MSIRANGE_3;}
else if (frequency == 1){range = RCC_CR_MSIRANGE_4;}
else if (frequency == 2){range = RCC_CR_MSIRANGE_5;}
else if (frequency == 4){range = RCC_CR_MSIRANGE_6;}
else if (frequency == 8){range = RCC_CR_MSIRANGE_7;}
else if (frequency == 16){range = RCC_CR_MSIRANGE_8;}
else if (frequency == 24){range = RCC_CR_MSIRANGE_9;}
else if (frequency == 32){range = RCC_CR_MSIRANGE_10;}
else if (frequency == 48){range = RCC_CR_MSIRANGE_11;}
RCC->CR |= RCC_CR_MSIRGSEL; //select MSI range from RCC_CR register
RCC->CR = (RCC->CR & ~RCC_CR_MSIRANGE_Msk) | range; //set MSI range
RCC->CR |= RCC_CR_MSION; //enable MSI
while ((RCC->CR & RCC_CR_MSION_Msk) != RCC_CR_MSION_Msk){int i = 0;} //wait for stability
RCC->CFGR = (RCC->CFGR & (~RCC_CFGR_SW_Msk)) | RCC_CFGR_SW_MSI; //set MSI as system clock source
while((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_MSI){int i = 0;} //check MSI is system clock
if (frequency < F_CPU){
// function to decrease frequency
setLatency();
}
F_CPU = frequency;
}
//set latency for reading flash memory
void setLatency(){
//choose number of wait states based on frequency
unsigned long wait_states = 0;
if (F_CPU <= 16){wait_states = FLASH_ACR_LATENCY_0WS;}
else if (F_CPU <= 32){wait_states = FLASH_ACR_LATENCY_1WS;}
else if (F_CPU <= 48){wait_states = FLASH_ACR_LATENCY_2WS;}
else if (F_CPU <= 64){wait_states = FLASH_ACR_LATENCY_3WS;}
else if (F_CPU <= 80){wait_states = FLASH_ACR_LATENCY_4WS;}
FLASH->ACR = (FLASH->ACR & ~FLASH_ACR_LATENCY_Msk) | wait_states; //set wait states
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != wait_states){int i = 0;} //wait till wait states are programmed
}
2020-12-24 05:52 PM
You have to enable the clocks before writing the registers, enable the USART2 before writing BRR