cancel
Showing results for 
Search instead for 
Did you mean: 

USART stm32h5 rust

HardFaultHero
Visitor

Hi everyone,

I’m bringing up USART2 on an STM32 using bare-metal Rust (#![no_std]), direct register access (no HAL, no CubeMX).

The CODE looks correctly

However, the data itself is wrong.

Instead of transmitting 'A' (0x41), the terminal consistently receives values like:

  • 0xCE

  • 0x05

(always stable, but never 0x41).

#![no_std]
#![no_main]

use core::ptr::{read_volatile, write_volatile};
use core::panic::PanicInfo;
use cortex_m_rt::entry;

#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
loop {}
}

#[inline(always)]
fn r(addr: u32) -> u32 {
unsafe { read_volatile(addr as *const u32) }
}

#[inline(always)]
fn w(addr: u32, val: u32) {
unsafe { write_volatile(addr as *mut u32, val) }
}

/* ================= BASE ================= */
const RCC: u32 = 0x4402_0C00;
const GPIOA: u32 = 0x4202_0000;
const USART2: u32 = 0x4000_4400;

/* ================= RCC ================= */
const RCC_AHB2ENR: u32 = RCC + 0x08C;
const RCC_APB1LENR: u32 = RCC + 0x09C;
const RCC_CCIPR2: u32 = RCC + 0x0DC;

/* ================= GPIO ================= */
const GPIOA_MODER: u32 = GPIOA + 0x00;
const GPIOA_AFRL: u32 = GPIOA + 0x20;

/* ================= USART ================= */
const USART_CR1: u32 = USART2 + 0x00;
const USART_BRR: u32 = USART2 + 0x0C;
const USART_ISR: u32 = USART2 + 0x1C;
const USART_TDR: u32 = USART2 + 0x28;
const USART_PRESC: u32 = USART2 + 0x2C;

/* ================= BITS ================= */
const USART_CR1_UE: u32 = 1 << 0;
const USART_CR1_RE: u32 = 1 << 2;
const USART_CR1_TE: u32 = 1 << 3;

const USART_ISR_TXFNF: u32 = 1 << 7;
const USART_ISR_TEACK: u32 = 1 << 21;
const USART_ISR_REACK: u32 = 1 << 22;

#[entry]
fn main() -> ! {

/* -------- CLOCK ENABLE -------- */

// GPIOA enable
w(RCC_AHB2ENR, r(RCC_AHB2ENR) | (1 << 0));

// USART2 enable
w(RCC_APB1LENR, r(RCC_APB1LENR) | (1 << 17));

// USART2 clock = PCLK1
w(RCC_CCIPR2, r(RCC_CCIPR2) & !(0b111 << 3));

/* -------- GPIO -------- */

// PA2, PA3 → AF
w(GPIOA_MODER,
(r(GPIOA_MODER) & !(0b1111 << 4)) | (0b1010 << 4)
);

// AF7
w(GPIOA_AFRL,
(r(GPIOA_AFRL) & !(0xFF << 8)) | (0x77 << 8)
);

/* -------- USART -------- */

// Disable
w(USART_CR1, 0);
while (r(USART_ISR) & (USART_ISR_TEACK | USART_ISR_REACK)) != 0 {}

// Prescaler /1
w(USART_PRESC, 0);

// 115200 @ 16 MHz
w(USART_BRR, 16_000_000 / 115_200);

// Enable TX RX
w(USART_CR1, USART_CR1_TE | USART_CR1_RE);

// Enable USART
w(USART_CR1, r(USART_CR1) | USART_CR1_UE);

while (r(USART_ISR) & USART_ISR_TEACK) == 0 {}

/* -------- TX LOOP -------- */
loop {
while (r(USART_ISR) & USART_ISR_TXFNF) == 0 {}
w(USART_TDR, b'A' as u32);
}
}

If anyone has run into “stable baud but wrong characters” on STM32 USART, I’d really appreciate pointers on what to double-check.

Thanks!



0 REPLIES 0