diff --git a/examples/bare4.rs b/examples/bare4.rs index 1cf587d5a5affc069208ce87e6ba25775f4f8380..08d633ec001e1f60aa68e48a1acab31a1307f031 100644 --- a/examples/bare4.rs +++ b/examples/bare4.rs @@ -7,22 +7,25 @@ extern crate cortex_m; extern crate cortex_m_rt; -#[macro_use] -extern crate cortex_m_debug; - -const RCC_AHPB1ENR: u32 = 0x4002_3810; -const GPIOA_MODER: u32 = 0x4002_0000; -//const GPIOA_ODR: u32 = 0x4002_0014; -const GPIOA_BSRR: u32 = 0x4002_0018; +// Peripheral addresses as constants +const PERIPH_BASE: u32 = 0x40000000; +const AHB1PERIPH_BASE: u32 = PERIPH_BASE + 0x00020000; +const RCC_BASE: u32 = AHB1PERIPH_BASE + 0x3800; +const RCC_AHB1ENR: u32 = RCC_BASE + 0x30; +const GBPIA_BASE: u32 = AHB1PERIPH_BASE + 0x0000; +const GPIOA_MODER: u32 = GBPIA_BASE + 0x00; +const GPIOA_BSRR: u32 = GBPIA_BASE + 0x18; // see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf) // rcc, chapter 6 // gpio, chapter 8 +#[inline(always)] fn read_u32(addr: u32) -> u32 { unsafe { core::ptr::read_volatile(addr as *const _) } } +#[inline(always)] fn write_u32(addr: u32, val: u32) { unsafe { core::ptr::write_volatile(addr as *mut _, val); @@ -36,14 +39,12 @@ fn wait(i: u32) { } fn main() { - // // power on GPIOA, RM0368 6.3.11 - // p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + // power on GPIOA, RM0368 6.3.11 - let r = read_u32(RCC_AHPB1ENR); // read - write_u32(RCC_AHPB1ENR, r | 1 << (0)); // set enable + let r = read_u32(RCC_AHB1ENR); // read + write_u32(RCC_AHB1ENR, r | 1); // set enable - // // configure PA5 as output, RM0368 8.4.1 - // p.GPIOA.moder.modify(|_, w| w.moder5().bits(1)); + // configure PA5 as output, RM0368 8.4.1 let r = read_u32(GPIOA_MODER) & !(0b11 << (5 * 2)); // read and mask write_u32(GPIOA_MODER, r | 0b01 << (5 * 2)); // set output mode @@ -53,11 +54,11 @@ fn main() { loop { // set PA5 high, RM0368 8.4.7 - write_u32(GPIOA_BSRR, r | 1 << 5); // set output mode + write_u32(GPIOA_BSRR, 1 << 5); // set bit, output hight (turn on led) wait(10_000); // set PA5 low, RM0368 8.4.7 - write_u32(GPIOA_BSRR, r | 1 << (5 + 16)); // set output mode + write_u32(GPIOA_BSRR, 1 << (5 + 16)); // clear bit, output low (turn off led) wait(10_000); } } diff --git a/examples/bare5.rs b/examples/bare5.rs new file mode 100644 index 0000000000000000000000000000000000000000..29f6744f9b76d034d9691d96bc0c71912d8083fd --- /dev/null +++ b/examples/bare5.rs @@ -0,0 +1,166 @@ +//! bare4.rs +//! Simple bare metal application +//! +#![feature(used)] +#![feature(custom_attribute)] +#![no_std] + +extern crate cortex_m; +extern crate cortex_m_rt; + +// #[macro_use] +// extern crate cortex_m_debug; + +mod stm32f40x { + use core::{cell, ptr}; + + // C like API... + const PERIPH_BASE: u32 = 0x40000000; + const AHB1PERIPH_BASE: u32 = PERIPH_BASE + 0x00020000; + const RCC_BASE: u32 = AHB1PERIPH_BASE + 0x3800; + const GPIOA_BASE: u32 = AHB1PERIPH_BASE; + + pub struct VolatileCell<T> { + value: cell::UnsafeCell<T>, + } + + impl<T> VolatileCell<T> { + #[inline(always)] + pub fn read(&self) -> T + where + T: Copy, + { + unsafe { ptr::read_volatile(self.value.get()) } + } + + #[inline(always)] + pub fn write(&self, value: T) + where + T: Copy, + { + unsafe { ptr::write_volatile(self.value.get(), value) } + } + } + + #[repr(C)] + #[allow(non_snake_case)] + #[rustfmt_skip] + pub struct RCC { + pub CR: VolatileCell<u32>, // < RCC clock control register, Address offset: 0x00 */ + pub PLLCFGR: VolatileCell<u32>, // < RCC PLL configuration register, Address offset: 0x04 */ + pub CFGR: VolatileCell<u32>, // < RCC clock configuration register, Address offset: 0x08 */ + pub CIR: VolatileCell<u32>, // < RCC clock interrupt register, Address offset: 0x0C */ + pub AHB1RSTR: VolatileCell<u32>, // < RCC AHB1 peripheral reset register, Address offset: 0x10 */ + pub AHB2RSTR: VolatileCell<u32>, // < RCC AHB2 peripheral reset register, Address offset: 0x14 */ + pub AHB3RSTR: VolatileCell<u32>, // < RCC AHB3 peripheral reset register, Address offset: 0x18 */ + pub RESERVED0: VolatileCell<u32>, // < Reserved, 0x1C */ + pub APB1RSTR: VolatileCell<u32>, // < RCC APB1 peripheral reset register, Address offset: 0x20 */ + pub APB2RSTR: VolatileCell<u32>, // < RCC APB2 peripheral reset register, Address offset: 0x24 */ + pub RESERVED1: [VolatileCell<u32>; 2], // < Reserved, 0x28-0x2C */ + pub AHB1ENR: VolatileCell<u32>, // < RCC AHB1 peripheral clock register, Address offset: 0x30 */ + pub AHB2ENR: VolatileCell<u32>, // < RCC AHB2 peripheral clock register, Address offset: 0x34 */ + pub AHB3ENR: VolatileCell<u32>, // < RCC AHB3 peripheral clock register, Address offset: 0x38 */ + pub RESERVED2: VolatileCell<u32>, // < Reserved, 0x3C */ + pub APB1ENR: VolatileCell<u32>, // < RCC APB1 peripheral clock enable register, Address offset: 0x40 */ + pub APB2ENR: VolatileCell<u32>, // < RCC APB2 peripheral clock enable register, Address offset: 0x44 */ + pub RESERVED3: [VolatileCell<u32>; 2], // < Reserved, 0x48-0x4C */ + pub AHB1LPENR: VolatileCell<u32>, // < RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */ + pub AHB2LPENR: VolatileCell<u32>, // < RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */ + pub AHB3LPENR: VolatileCell<u32>, // < RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */ + pub RESERVED4: VolatileCell<u32>, // < Reserved, 0x5C */ + pub APB1LPENR: VolatileCell<u32>, // < RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */ + pub APB2LPENR: VolatileCell<u32>, // < RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */ + pub RESERVED5: [VolatileCell<u32>; 2], // < Reserved, 0x68-0x6C */ + pub BDCR: VolatileCell<u32>, // < RCC Backup domain control register, Address offset: 0x70 */ + pub CSR: VolatileCell<u32>, // < RCC clock control & status register, Address offset: 0x74 */ + pub RESERVED6: [VolatileCell<u32>; 2], // < Reserved, 0x78-0x7C */ + pub SSCGR: VolatileCell<u32>, // < RCC spread spectrum clock generation register, Address offset: 0x80 */ + pub PLLI2SCFGR: VolatileCell<u32>, // < RCC PLLI2S configuration register, Address offset: 0x84 */ + } + + impl RCC { + pub fn get() -> *mut RCC { + RCC_BASE as *mut RCC + } + } + + #[repr(C)] + #[allow(non_snake_case)] + #[rustfmt_skip] + pub struct GPIOA { + pub OTYPER: VolatileCell<u32>, // < GPIO port output type register, Address offset: 0x04 */ + pub OSPEEDR: VolatileCell<u32>, // < GPIO port output speed register, Address offset: 0x08 */ + pub PUPDR: VolatileCell<u32>, // < GPIO port pull-up/pull-down register, Address offset: 0x0C */ + pub MODER: VolatileCell<u32>, // < GPIO port mode register, Address offset: 0x00 */ + pub IDR: VolatileCell<u32>, // < GPIO port input data register, Address offset: 0x10 */ + pub ODR: VolatileCell<u32>, // < GPIO port output data register, Address offset: 0x14 */ + pub BSRRL: VolatileCell<u16>, // < GPIO port bit set/reset low register, Address offset: 0x18 */ + pub BSRRH: VolatileCell<u16>, // < GPIO port bit set/reset high register, Address offset: 0x1A */ + pub LCKR: VolatileCell<u32>, // < GPIO port configuration lock register, Address offset: 0x1C */ + pub AFR: [VolatileCell<u32>], // < GPIO alternate function registers, Address offset: 0x20-0x24 */ + } + + // impl GPIOA { + // pub fn get() -> *mut GPIOA { + // GPIOA_BASE as *mut GPIOA + // } + // } + + impl GPIOA { + pub fn get() -> *mut GPIOA { + GPIOA_BASE as *mut GPIOA + } + } +} +use stm32f40x::*; + +// see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf) +// rcc, chapter 6 +// gpio, chapter 8 + +fn wait(i: u32) { + for _ in 0..i { + cortex_m::asm::nop(); // no operation (cannot be optimized out) + } +} + +fn main() { + // // power on GPIOA, RM0368 6.3.11 + // p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + + let rcc = RCC::get(); // get the reference to the Rcc in memory + unsafe { + let r = (*rcc).AHB1ENR.read(); // read + (*rcc).AHB1ENR.write(r | 1 << (0)); // set enable + } + + // configure PA5 as output, RM0368 8.4.1 + // let gpioa = GPIOA::get(); + // unsafe { + // let r = (*gpioa).MODER.read() & !(0b11 << (5 * 2)); // read and mask + // (*gpioa).MODER.write(r | 0b01 << (5 * 2)); // set output mode + + // // and alter the data output through the BSRR register + // // this is more efficient as the read register (in modify) + // // is not needed. + + // loop { + // // set PA5 high, RM0368 8.4.7 + // (*gpioa).BSRRH.write(1 << 5); // set bit, output hight (turn on led) + // wait(10_000); + + // // set PA5 low, RM0368 8.4.7 + // (*gpioa).BSRRH.write(1 << 5); // clear bit, output low (turn off led) + // wait(10_000); + // } + // } +} + +// As we are not using interrupts, we just register a dummy catch all handler +#[link_section = ".vector_table.interrupts"] +#[used] +static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; + +extern "C" fn default_handler() { + cortex_m::asm::bkpt(); +}