Skip to main content
Explorer II
July 21, 2024
Question

Nucleo-L4P5ZG LPUART not receiving nor transmitting

  • July 21, 2024
  • 3 replies
  • 1011 views

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 << 8) | (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!

    This topic has been closed for replies.

    3 replies

    Super User
    July 21, 2024

    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.

    TDK_0-1721601870921.png

     

    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.

    Graduate II
    July 22, 2024

    For GPIOG you must enable VDDIO via PWR

    tomcat611Author
    Explorer II
    August 3, 2024

    Thank you both @Tesla DeLorean and @TDK, following both of your advice let me to getting some kind of input! My updated LPUART initialization code:

     

    void LPUART_Init(void) {
     RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
     spin(30);
     PWR->CR2 |= 0x1 << 9;
     spin(30);
     // Enable LPUART clock
     RCC->APB1ENR2 |= RCC_APB1ENR2_LPUART1EN;
     spin(30);
     RCC->CCIPR |= 0x1 << 10;
     // Initialize GPIO pin
     gpio_init(PIN('G', 7), GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_UP, 0b1000);
     gpio_init(PIN('G', 8), GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_UP, 0b1000);
     // Enable GPIO clock
     RCC->AHB2ENR |= RCC_AHB2ENR_GPIOGEN;
     spin(30);
     // Configure LPUART controller
     LPUART1->CR1 &= ~USART_CR1_UE; // Disable LPUART
     // Set the baud rate
     //uint16_t uartdiv = SystemCoreClock / 9600;
     //LPUART1->BRR = uartdiv;
     LPUART1->BRR = ((256 * SystemCoreClock) / 9600);
     // Leave all interrupts disabled
    
     // Enable LPUART
     LPUART1->CR1 |= 0x1;
     spin(20);
    
     // Enable tx
     LPUART1->CR1 |= 0x1 << 3;
    
     // Enable rx
     LPUART1->CR1 |= 0x1 << 2;
    
     while ((LPUART1->ISR & USART_ISR_TEACK) == 0);
    }

    And the updated code that sends a character (note that I've changed this to send a constant char on button press):

    if(gpio_read(BTN_PIN) != 0) {
     gpio_write(LED_PIN, true);
     LPUART1->TDR = 'h';
     while(!(LPUART1->ISR & USART_ISR_TXE_TXFNF)) {};
    } else {
     gpio_write(LED_PIN, false);
    }

    Upon starting screen on my computer the same way as before, I get a stream of ">" characters whenever I press the button on the board. I tried changing the char sent by the board to 'r', which changed the character appearing in the terminal to a stream of "�" preceeded by a single "0". I thought this was due to a mismatch between the frames that the tty was expecting and what the board was sending, so I fiddled with stty options by "stty -F /dev/ttyACM0 -cstopb -parenb -clocal cs8". This sets the tty to expect the same as the default LPUART registers - 1 stop bit, 8 data bits, no parity bits. This didn't change anything, however :) I'm left thinking that my baud rate must still not be set correctly, but I cannot see what would be wrong (after correcting the error that @TDK pointed out).