Register Access problem

Hi Team,
I’m new to embedded Rust and currently working with the STM32F410RBT6 board. I’ve written a basic program in Rust on this board and successfully got the output. Now, I need to prove out the UART driver. I tried accessing the registers using their addresses, but I couldn’t get it to work.It throws unsafe errors. Please provide a solution, as this will be very helpful to me. I’ve attached my code repo for referenceGit_Repo.

By default, the stable-deref-trait crate has the std feature enabled. If you have a direct dependency on it, add default-features = false to disable usage of std:

[dependencies]
stable-deref-trait = { version = "1.2", default-features = false }

If stable-deref-trait is not a direct dependency of your crate, please post the output of cargo tree --invert stable-deref-trait to see what pulls it in.

This is the only error I could see in your screenshot, so if there’s more problems you would need to provide more information.

Hi @cod10129,
Thanks for your quick response. I tried adding stable-deref-trait = { version = "1.2", default-features = false } as a dependency, but I am still facing the same problem.
I’ve attached the output of cargo tree --invert stable-deref-trait in this comment, along with the error details. My repo has also been updated and shared for reference this.

My error status:
error[E0463]: can't find crate for std
|
= note: the thumbv7em-none-eabihf target may not support the standard library
= note: std is required by stable_deref_trait because it does not declare #![no_std]

error[E0405]: cannot find trait Clone in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:129:50
|
129 | pub unsafe trait CloneStableDeref: StableDeref + Clone {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::clone::Clone;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:157:17
|
157 | unsafe impl<T: ?Sized> StableDeref for Box {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:170:17
|
170 | unsafe impl<T: ?Sized> StableDeref for Rc {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:172:17
|
172 | unsafe impl<T: ?Sized> CloneStableDeref for Rc {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:174:17
|
174 | unsafe impl<T: ?Sized> StableDeref for Arc {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:176:17
|
176 | unsafe impl<T: ?Sized> CloneStableDeref for Arc {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:178:21
|
178 | unsafe impl<'a, T: ?Sized> StableDeref for Ref<'a, T> {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:179:21
|
179 | unsafe impl<'a, T: ?Sized> StableDeref for RefMut<'a, T> {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:181:21
|
181 | unsafe impl<'a, T: ?Sized> StableDeref for MutexGuard<'a, T> {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:183:21
|
183 | unsafe impl<'a, T: ?Sized> StableDeref for RwLockReadGuard<'a, T> {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:185:21
|
185 | unsafe impl<'a, T: ?Sized> StableDeref for RwLockWriteGuard<'a, T> {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:187:21
|
187 | unsafe impl<'a, T: ?Sized> StableDeref for &'a T {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:188:21
|
188 | unsafe impl<'a, T: ?Sized> CloneStableDeref for &'a T {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

error[E0405]: cannot find trait Sized in this scope
--> C:\Users\MuthuArasan.cargo\registry\src\index.crates.io-6f17d22bba15001f\stable_deref_trait-1.2.0\src\lib.rs:189:21
|
189 | unsafe impl<'a, T: ?Sized> StableDeref for &'a mut T {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
25 + use core::marker::Sized;
|

Some errors have detailed explanations: E0405, E0463.
For more information about an error, try rustc --explain E0405.
error: could not compile stable_deref_trait (lib) due to 15 previous errors
warning: build failed, waiting for other jobs to finish...

After checking some dependencies, I found that this is because probe-rs does not support #![no_std]. It needs std functionality in the gimli and object crates. Your inverted tree shows how gimli pulls in stable_deref_trait. I’m not an expert in embedded, but I don’t think probe-rs is meant to be used as a library running on the chip it’s probing. You’ll need to rethink your design.

It’s definitely true that probe-rs needs std available. What I’m not sure about is what device probe-rs is intended to be run on (maybe a “host” machine connected to the embedded device via debug probe? Again, I’m not an embedded developer).

1 Like

Hi @cod10129
I want to write a UART driver in Rust by accessing the registers directly, similar to how it is done in C, without using embedded-hal. Is this possible? If yes, please provide some guidance and references.

If you want to manually access specific registers, you'll need inline assembly with asm!.
Memory-mapped registers are different, and can be accessed by just converting their memory addresses into a pointer. The source code of stm32f4xx-hal would be a useful reference, although it's a lot of code.

For an example, assume there's a memory-mapped 4 byte register at address 0x4000 that you want to write 0xDEADBEEF into. That can be done like so:

fn main() {
    const ADDR: usize = 0x4000;
    let ptr = ADDR as *mut u32;
    // SAFETY: pretend there's an MMIO device at this address
    unsafe {
        ptr.write_volatile(0xDEADBEEF);
    }
}

You can build abstractions around this similar to stm32f4-staging::Reg for more ergonomic use.

1 Like

The HAL crate already has a UART driver. May as well use it, since it works with higher level crates like embassy. It will get you up an running much sooner.

FWIW, I use embassy-rp with a Raspberry Pi Pico, and it is a billion times better than trying to reinvent everything from scratch.

1 Like

Hi @cod10129 @parasyte ,
I am currently using this method to run the code and hitting the write function, but the data is not showing up in the terminal. What could be the problem? Could you please guide me.


I have upadate my code here PFA.

#![no_std]
#![no_main]

use cortex_m::asm;
use cortex_m_rt::entry;
use core::ptr;
use stm32f4xx_hal::{pac, prelude::*};

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    cortex_m::asm::bkpt(); // Trigger breakpoint for debugging
    loop {}
}

// Base addresses for UART peripherals
const UART1_BASE: u32 = 0x40011000; // USART1 base address
const UART2_BASE: u32 = 0x40004400; // USART2 base address

// Register offsets
const UART_SR: u32 = 0x00;
const UART_DR: u32 = 0x04;
const UART_BRR: u32 = 0x08;
const UART_CR1: u32 = 0x0C;
const UART_CR2: u32 = 0x10;
const UART_CR3: u32 = 0x14;

#[derive(Copy, Clone)]
enum Uart {
    Uart1,
    Uart2,
}

fn get_uart_base(uart: Uart) -> u32 {
    match uart {
        Uart::Uart1 => UART1_BASE,
        Uart::Uart2 => UART2_BASE,
    }
}

fn enable_peripherals(uart: Uart) {
    let rcc = unsafe { &*pac::RCC::ptr() };
    let gpioa = unsafe { &*pac::GPIOA::ptr() };
    let gpiob = unsafe { &*pac::GPIOB::ptr() };

    match uart {
        Uart::Uart1 => {
            rcc.apb2enr.modify(|_, w| w.usart1en().set_bit());
            rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
            gpioa.afrh.modify(|_, w| w.afrh9().bits(7).afrh10().bits(7));
        }
        Uart::Uart2 => {
            rcc.apb1enr.modify(|_, w| w.usart2en().set_bit());
            rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
            gpioa.afrl.modify(|_, w| w.afrl2().bits(7).afrl3().bits(7));
        }
    }
}

fn uart_init(uart: Uart, baud_rate: u32, clock_freq: u32) {
    let base = get_uart_base(uart);

    unsafe {
        //let brr = clock_freq / baud_rate;
        let brr = 1667;
        ptr::write_volatile((base + UART_BRR) as *mut u32, brr);
        let cr1 = (1 << 13) | (1 << 3) | (1 << 2);
        ptr::write_volatile((base + UART_CR1) as *mut u32, cr1);
        ptr::write_volatile((base + UART_CR2) as *mut u32, 0x00);
        ptr::write_volatile((base + UART_CR3) as *mut u32, 0x00);
    }
}

fn uart_write(uart: Uart, data: u8) {
    let base = get_uart_base(uart);

    unsafe {
        while (ptr::read_volatile((base + UART_SR) as *const u32) & (1 << 7)) == 0 {}
        ptr::write_volatile((base + UART_DR) as *mut u32, data as u32);
    }
}

fn uart_read(uart: Uart) -> u8 {
    let base = get_uart_base(uart);

    unsafe {
        while (ptr::read_volatile((base + UART_SR) as *const u32) & (1 << 5)) == 0 {}
        ptr::read_volatile((base + UART_DR) as *const u32) as u8
    }
}

#[entry]
fn main() -> ! {
    let selected_uart = Uart::Uart2;
    enable_peripherals(selected_uart);
    uart_init(selected_uart, 9600, 16_000_000);
    for _ in 1..=10{
    uart_write(selected_uart, b'H');
    }
    let _received = uart_read(selected_uart);

    loop {
        asm::nop();
    }
}
1 Like