How to work with “No Invalid Address”? Safe Access

Reading Time: 3 minutes

In the previous blog, we tried to write directly to the BSRR Register address and that was not Safe Access because of which we fall into Hardware Fault exception. You can read that blog from here.

Now in this blog, we are going to work in a very different way. We are not going to use the BSRR register instead of that we are going to use the Register Block to access the registers of the GPIO block.

As we are working with the Embedded Systems they make our task fast and reliable. Also, they are much smaller in size compared to traditional computers, which makes them compact and portable, and useful for mass production. Management of Embedded Systems is pretty easy, as elements used in their creation are cheap & long-lasting. Embedded Systems are also cost-effective.

Directly working with hexadecimal addresses is error-prone and this we have already seen in the last blog itself and how we face the Hardware Exception. Now we are going to work in a “safe” manner. Let’s see how we do that.

We will be working with the register now keeping 3 rules in mind.

  1. No messing around with the actual addresses
  2. Should respect read/write permissions
  3. Should prevent modification of the reserved parts of a register.

Register Block

Register Block safe access

Register Block is a group of registers associated with a peripheral and these groups of registers is located in a contiguous region of memory.

Why we are talking about the Register Block here?

Register Blocks are the type of struct in which each of its fields represents a Register. These Registers are a combination of the following methods: read, write, or modify according to its read/write permissions. The no. of registers we can access using Register Block is.

We can access all these registers with the help of the Register Block struct.


Code

Time to code a safe program that will help us to access the “bsrr” register using its Register Block.

#![no_main]
#![no_std]

use cortex_m::asm::delay;
use cortex_m_rt::entry;
use panic_itm as _;
use stm32f3_discovery::leds::Leds;
use stm32f3_discovery::stm32f3xx_hal::{pac::GPIOE, prelude::*, stm32};

#[entry]
fn main() -> ! {
    let gpioe = unsafe { &*GPIOE::ptr() };
    let device_peripherals = stm32::Peripherals::take().unwrap();
    let mut reset_and_clock_control = device_peripherals.RCC.constrain();

    // initialize user leds
    let mut gpio_pe = device_peripherals
        .GPIOE
        .split(&mut reset_and_clock_control.ahb);
    let _leds = Leds::new(
        gpio_pe.pe8,
        gpio_pe.pe9,
        gpio_pe.pe10,
        gpio_pe.pe11,
        gpio_pe.pe12,
        gpio_pe.pe13,
        gpio_pe.pe14,
        gpio_pe.pe15,
        &mut gpio_pe.moder,
        &mut gpio_pe.otyper,
    );

    loop {
        // Turn "on" the North LED
        gpioe.bsrr.write(|write| write.bs9().set_bit());
        delay(3_0000_00);
        // Turn "on" the North LED
        gpioe.bsrr.write(|write| write.bs11().set_bit());
        delay(3_0000_00);
        // Turn "off" the North LED
        gpioe.bsrr.write(|write| write.br9().set_bit());
        delay(3_0000_00);
        // Turn "off" the North LED
        gpioe.bsrr.write(|write| write.br11().set_bit());
        delay(3_0000_00);
    }
}

Note: You can see the code and the dependencies used here from this Repository.

Here you can notice that we have used the “stm32f3_discovery::stm32f3xx_hal::pac::GPIOE” which is providing us the RegisterBlock. We have to access this Register Block using unsafe block as we have to de-reference the Raw Pointer.

  • First thing you notice: There are no magic addresses involved. Instead, we use a more human-friendly way, for example, gpioe.bsrr, to refer to the BSRR register in the GPIOE register block.
  • Then we have this writing method that takes a closure. If the identity closure (|w|w) is used, this method will set the register to its default (reset) value, the value it had right after the microcontroller was powered on / reset.
  • That value is 0x0 for BSRR register. Since we want to write a non-zero value to the register, we use builder methods like bs9 and br9 to some of the bits of the default value.

Now apply these commands one by one

  • load
  • break main
  • continue
  • step
  • next
  • print gpioe

You will see the output like this.

This print the address of the Register Block and the address of the “bsrr” register will be in a contiguous memory that is 0x48001018.


Blink LEDs using Register Block–

Now let’s try to blink the LEDs using this safe manner. Run commandcontinue” now.

Output…

So this is how you can access the LEDs using Register Block in a safe manner.

I hope you like this way of working with the registers. Thanks for reading…!


If you want to read more content like this?  Subscribe to Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe to Rust Times Newsletter: https://bit.ly/2Vdlld7.

Written by 

Nitin is a Software Consultant, with experience of more than 7 months. He works on Rust Programming Language and Embedded Development using Rust. He is also fond of Java Programming & Artificial Intelligence. Apart from that, his hobbies are Watching Netflix, Reading, Singing & Writing.

1 thought on “How to work with “No Invalid Address”? Safe Access5 min read

Comments are closed.