cancel
Showing results for 
Search instead for 
Did you mean: 

Register confusion on stm32f401RE

CMcC.1
Associate II

I am having a but of an issue with setting the registers to portA directly using its address.

I am doing this for demonstration/learning purposes. I am using the STM32F401RE board.

When I read the datasheet it says that GPIO PORT starts on register ->0x40020000 - 0x400203FF

And writing to the MODER of GPIOA has no offset... So that means that if I write 0x01 to 0x40020000 it will set PortA pin 0 to General purpose OUTPUT right?

It also says that the PORTA ODR has an offset of 0x14 which means -> 0x40020014 right?

So when I want to write to switch that PortA pin0 to HIGH I will write 0x01 to 0x40020014 right?

Thanks

Cart

7 REPLIES 7
Uwe Bonnes
Principal II

First you need to enable clock to that GPIO port in the RCC register space. To understand, read the GPIO chapter in the reference manual of that chip. For (re) setting bit, learn also about BSR, BRS and BSSR.

> And writing to the MODER of GPIOA has no offset... So that means that if I write 0x01 to 0x40020000 it will set PortA pin 0 to General purpose OUTPUT right?

After you set the GPIOA clock in RCC as Uwe said, yes, but it will also set other bits of GPIOA_MODER to 0.

Now depending on how exactly will you perform that write, it may be a byte, halfword or word write.

In the latter case, if it's a word write - i.e. writing 0x0000'0001 into GPIOA_MODER - you will overwrite the default settings for PA13 and PA14, which are SWDIO and SWCLK, to inputs, and consequently you will lose the ability to debug.

JW

I dont set anything in the Clock since I read that and it said that the default for the clock input is 0x00 which is High speed Internal Oscillator right?

So then I set address -> 0x40023800 + 0x30 which is the RCC_AHB1ENR register with 0x1; This enables the clock to portA.

After that I set register 0x40020000 = (0x0C000000 + 0x01); which just makes the PORTA0 to General Purpose output.

So then I set register 0x40020014  = 0x01; which just sets the port ON.

But I still dont get a high on that port?

The + is generally just an offset.

I dont set anything in the Clock since I read that and it said that the default for the clock input is 0x00 which is High speed Internal Oscillator right?

So then I set address -> 0x40023800 + 0x30 which is the RCC_AHB1ENR register with 0x1; This enables the clock to portA.

After that I set register 0x40020000 = (0x0C000000 + 0x01); which just makes the PORTA0 to General Purpose output.

So then I set register 0x40020014 = 0x01; which just sets the port ON.

But I still dont get a high on that port?

The + is generally just an offset.

@Uwe Bonnes​ 

@Community member​ 

Sorry I am new and I am not sure how this forum works yet. I use it very rarely.

How do you do all this?

JW

@Community member​ So this is in Rust.

Its quite a weird way to implement when you first see it.

#![no_std]
#![no_main]
use cortex_m::{asm,peripheral::syst, peripheral::Peripherals};
use cortex_m_rt::entry;
use stm32f4::stm32f401;
use volatile_register::{RW,RO};
use panic_halt as _;
use stm32f4xx_hal::{prelude::*, stm32};
 
#[repr(C)]
struct ABlock {
    pub moder: RW<u32>,
    pub otyper: RW<u32>,
    pub ospeedr: RW<u32>,
    pub pupdr: RW<u32>,
    pub idr: RW<u32>,
    pub odr: RW<u32>,
    pub lckr: RW<u32>,
    pub arf1: RW<u32>,
    pub arf2: RW<u32>,
}
 
struct RCCBLock{
    pub ahb1 : RW<u32>
}
 
struct ABlockODR {
    pub odr: RW<u32>,
}
 
pub struct GPIO {
    set: &'static mut ABlock,
    gpio_odr: &'static mut ABlockODR,
}
 
pub struct RCC {
    rcc: &'static mut RCCBLock,
}
 
impl RCC {
    pub fn new() -> RCC {
        RCC {
            rcc: unsafe {&mut *(0x40023830u32 as *mut RCCBLock) }
        }
    }
 
    pub fn set_ahb1_register(&mut self, reload_value: u32){
        unsafe { self.rcc.ahb1.write(reload_value) }        
    }
}
 
impl GPIO {
    pub fn new() -> GPIO {
        GPIO {
            set: unsafe {&mut *(0x40200000u32 as *mut ABlock) },
            gpio_odr: unsafe {&mut *(0x40200014u32 as *mut ABlockODR) }
        }
    }
 
    pub fn get_register(&self) -> u32 {
        self.set.moder.read()
    }
 
    pub fn set_register(&mut self, reload_value: u32){
        unsafe { self.set.moder.write(reload_value) }        
    }
 
    pub fn set_moder_register(&mut self, reload_value: u32){
        unsafe { self.set.moder.write(reload_value) }        
    }
 
    pub fn set_odr_register(&mut self, reload_value: u32){
        unsafe { self.gpio_odr.odr.write(reload_value) }        
    }
}
 
#entry
fn main() -> ! {
 
    let mut RCC = RCC::new();
    RCC.set_ahb1_register(1);
 
    let mut PA = GPIO::new();
    let mut PAModSet: u32 = ((0x0C000000u32) + 1u32);
    PA.set_moder_register(PAModSet);
    PA.set_odr_register((0x01u32));
 
    loop {
        // your code goes here
    }
}

Humm what is it with Rust lately?

Okay and how do you know it does what you say it does? Did you see disasm? DId you single-step?

JW