Embedded-Rust: Turning LEDs on/off using registers

Knoldus Blog Audio
Reading Time: 5 minutes

An embedded system is computer hardware with software embedded in it. Or we can say it is a combination of computer processors, computer memory, and input/output devices and it can be an independent system or a part of a large system.

Hi folks, we are back again with another interesting article where we’ll try to turn on STM32F3Discovery board’s LEDs using registers.
Alright!!! let’s start to update our knowledge pool by adding one more interesting row in it.

In a nutshell, we’ll play with the register’s addresses to turn on the board’s LEDs. And before jumping into this article, I’d request to first have a look at this to grab more information from this article.

Okay, before implementing our logic, we need to figure out few things:

  • firstly we need to find out details of LEDs & their pins,
  • secondly, address of the register block in which we need to work

If you have gone through this article then you may know the answer to the first statement. If not then let’s try to figure it out:

Figuring out the pin details

To know which pin is connected to which LED, we need to look into the F3(STM32F3Discovery) board’s user manual.
If we look into Section 6.4, then we’ll get some information about LEDs, like total we have 10 LEDs but we’ll take only two of them, so as per the documentation:

User LD3: Red LED is a user LED connected to the I/O PE9 of the STM32F303VCT6.
User LD4: Blue LED is a user LED connected to the I/O PE8 of the STM32F303VCT6

Here PE9 means Pin 9 on Port E, as the pins are part of Port E then we’ll have to deal with GPIOE peripheral, okay we got the details of LEDs and their pins now let’s move to our next step where we need to figure out the most important aspect of this article (address of the register) through which we’ll turn on the LEDs.

Figuring out the address of the register

Before actually getting address of the register, let’s figure out from where the register came into the picture! Okay, let me tell you: we have peripherals present in the board and each peripheral has a register block associated with it.
So our goal is to get the starting address of this register block which is also its base address. And these address details are present in the reference manual of the F3 board in Section 3.2.2.

As we can see here, the base address of GPIOE’s register block is 0x4800_1000 and if we talk about boundary address then it is 0x4800_1000 to 0x4800_13FF. Okay, now so using this information can we turn on the LEDs?

The answer is NO. To turn on an LED we need to send a signal to the corresponding pin. The signal means high voltage or low voltage, high will turn on the LED and low will turn it off. But here nothing to worry about these signals, because we have a GPIO’s register present BSRR(Bit Set Reset Register) which will helps us to provide a signal to pins, now we just need to figure out the address of this register and which is present here Section 11.4.7.

We can see the offset of the register is 0x18 which means the address to this register will be 0x48001018 because our base address is 0x48001000. The next box represents the set and reset bits, which means 0-15 bits are used to set and 16-31 bits are used to reset the pins. And we can see 1 is used to set and reset the bits.
The table represents the bit 0 sets the pin 0, which means outputting high voltage on the pin.

Now, we are all set to implement out logic to turn on the LED.

Implementation

#![no_main]
#![no_std]

pub use panic_itm;
use cortex_m_rt::entry;
pub use stm32f3_discovery::stm32f3xx_hal;
use stm32f3xx_hal::prelude::*;
pub use stm32f3xx_hal::stm32;

#[entry]
fn main() -> ! {
    // initializing device peripherals to access led's pins
    let device_peripherals = stm32::Peripherals::take().unwrap();
    let mut rcc = device_peripherals.RCC.constrain();

    // initialize leds
    let mut gpioe = device_peripherals.GPIOE.split(&mut rcc.ahb);

    // configure LD3
    gpioe.pe9.into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
    // configure LD4
    gpioe.pe8.into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);

    loop {
        unsafe {
    
            const GPIOE_BSRR: u32 = 0x48001018;

            // Turn on LD3
            *(GPIOE_BSRR as *mut u32) = 1 << 9;

            // Turn on LD4
            *(GPIOE_BSRR as *mut u32) = 1 << 10;

            // Turn off LD3
            *(GPIOE_BSRR as *mut u32) = 1 << 25;

            // Turn off LD4
            *(GPIOE_BSRR as *mut u32) = 1 << 26;
        }
    }
}

We can get the explanation of the first few lines in this article. So let’s understand the unsafe block.
Firstly we are storing the address of our GPIO‘s BSRR(Bit Set Reset Register) to a const variable because this is the path to our LEDs. Secondly, we are using the statement

*(GPIOE_BSRR as *mut u32) = 1 << 9;

This is used to turn on the LD3 (Red LED), we are using GPIOE_BSRR as *mut u32 this raw pointer is making a mutable copy of our address variable so that we can make changes in it and after that, we are dereferencing using *(asterisk) and wrapping it inside the unsafe block as per the raw pointer deference rules.
1 << 9 this operation means we are providing a high voltage to pin 9 by using left shift. As we already discussed in the previous diagram 1 is used for both set(high voltage) and reset(low voltage).

Similarly we are using turning the same LED off using

*(GPIOE_BSRR as *mut u32) = 1 << 25;

Because 25th position is the reset bit of pin 9. In other words, this operation will turn the LD3(Red LED) off.

This is how we can turn on and off all the LEDs of F3Discovery board. And if you are not aware of running this program on the F3Discovery board I would request you to have a look at these articles:

That’s all about this article, in the next article we’ll try to grab some other components of the STM32F3Discovery board.
Thanks for reading!!!

References:

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


Knoldus-blog-footer-image

Written by 

Pawan Singh Bisht is a Software Consultant at Knoldus Software LLP, having a strong experience of more than two years in the technology field. He has been well versed in the core implementation of Rust and Java. He loves to contribute to the community which he attained from the community.

1 thought on “Embedded-Rust: Turning LEDs on/off using registers6 min read

Leave a Reply