2024-07-21 02:43 PM
Hi all! I am trying to communicate with the Nucleo-L4P5ZG via the LPUART1 peripheral over ST-LINK, however it doesn't seem to be transmitting or receiving anything. Following is my system clock initialization code (non-relevant parts cut out):
#pragma once
#include <stm32l4xx.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define SYS_FREQUENCY 16000000
uint32_t SystemCoreClock; // Required by CMSIS
static inline void clock_init(void) {
SCB->CPACR |= 15 << 20; // Enable FPU
RCC->CR |= RCC_CR_HSION; // Set HSI on
while (!(RCC->CR & RCC_CR_HSIRDY)) {}
RCC->CFGR &= ~(RCC_CFGR_SW);
RCC->CFGR |= RCC_CFGR_SW_HSI; // Set HSI as clock source
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {};
rng_init(); // Initialise random number generator
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // Enable SYSCFG
SystemCoreClock = SYS_FREQUENCY; // Required by CMSIS
}
void LPUART_Init(void) {
// Enable LPUART clock
RCC->APB1ENR2 |= RCC_APB1ENR2_LPUART1EN;
spin(30); // Blocking wait
// Set sysclock as LPUART clock source
RCC->CCIPR |= 0x1 << 10;
// Enable GPIO clock
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOGEN;
spin(5); // Blocking wait
// Configure GPIO pins
GPIOG->MODER &= ~((0x3 << (8 * 2)) | (0x3 << (7 * 2)));
GPIOG->MODER |= (0x2 << (8 * 2) | (0x2 << (7 * 2)));
GPIOG->OTYPER &= ~((0x1 << 😎 | (0x1 << 7));
// Set GPIOG pins 7 and 8 speed
GPIOG->OSPEEDR &= ~((0x3 << (8*2)) | (0x3 << (7*2)));
GPIOG->OSPEEDR |= ((0x2 << (8*2)) | (0x2 << (7*2)));
// Set GPIOG pins 7 and 8 to alternate function 8
GPIOG->AFR[0] &= ~((0xF << (7*4)));
GPIOG->AFR[0] |= ((0b1000 << (7*4)));
GPIOG->AFR[1] &= ~((0xF << ((8-8) * 4)));
GPIOG->AFR[1] |= ((0b1000 << ((8-8) *4)));
// Set baud rate
LPUART1->BRR = ((SystemCoreClock) / 9600);
// Enable tx
LPUART1->CR1 |= 0x1 << 3;
// Enable rx
LPUART1->CR1 |= 0x1 << 2;
// Enable LPUART
LPUART1->CR1 |= 0x1;
while ((LPUART1->ISR & USART_ISR_TEACK) == 0);
}
The first function above gets called by the CMSIS startup template, "cmsis_l4/Source/Templates/gcc/startup_stm32l4p5xx.s", which then calls my main():
int main(void) {
// These are defined elsewhere and work fine
gpio_output(LED_PIN);
gpio_input(BTN_PIN);
LPUART_Init();
for (;;) {
gpio_write(LED_PIN, true); // Defined elsewhere, this is reached and works
while(!(LPUART1->ISR & USART_ISR_RXNE_RXFNE)) {};
rxb = LPUART1->RDR;
gpio_write(LED_PIN, false); // Defined elsewhere, this is never reached
while(!(LPUART1->ISR & USART_ISR_TXE_TXFNF)) {};
LPUART1->TDR = rxb;
}
return 0;
}
The first `gpio_write` on line 9 above is reached and activates the on-board LED. I then run `screen -fn /dev/ttyACM0 9600` on the machine connected to the board (which is able to program the board, ruling out the USB) and press some keys. The LED never goes off, which means line 12 is never reached, and, obviously, the byte is never echoed back to the terminal on the machine. Have I done anything obviously wrong? I can connect GDB via openOCD and I see that the registers are set appropriately, so it seems to either be an issue of me not setting the right parameters on initialization or the machine isn't communicating with the board correctly (however it is during programming?). Thanks very much in advance for any assistance!
2024-07-21 03:44 PM - edited 2024-07-21 03:46 PM
BRR seems wrong. See formula in the RM. You're setting it as if there are no fractional bits. Should be 256x what you have.
UE should be set before TE and RE.
Consider setting it up with HAL/CubeMX to see what the proper initialization settings and register values are.