ひきつづき、HALを使わず、素でレジスタを叩いてUART用のsend/receiveルーチンを作成
以下のソースはシステムクロック4HMzで、38400bpsで通信する。抽象化していないので、STM32L47xxxシリーズ専用。
変数型もu32でなくてもいいところがあるけど、、無駄が多くてもまずは動かすのが目標
UARTが使えるようになったので、次はI2Cでセンサと接続する。
// // stm32 device driver // pub const GPIOA_BASE: u32 = 0x4800_0000; //APB2PERIPH_BASE + 0x0800; pub const MODER_OFFSET: u32 = 0x0; // GPIOA pub const BSRR_OFFSET: u32 = 0x18; pub const AFRL_OFFSET: u32 = 0x20; pub const RCC_BASE: u32 = 0x4002_1000; pub const AHB2ENR_OFFSET : u32 = 0x4C; // RCC_AHB2ENR pub const APB1ENR1_OFFSET: u32 = 0x58; pub const GPIO_PIN_2 : u32 = 2; pub const GPIO_PIN_3 : u32 = 3; pub const GPIO_PIN_5 : u32 = 5; pub const RCC_CCIPR : u32 = 0x88; pub const USART2_SEL : u32 = 1; pub const USART2_BASE : u32 = 0x4000_4400; pub const USART2EN : u32 = 17; pub const BRR_OFFSET : u32 = 0x0c; pub const ISR_OFFSET : u32 = 0x1c; pub const CR1_OFFSET : u32 = 0; pub const RDR_OFFSET: u32 = 0x24; pub const TDR_OFFSET: u32 = 0x28; pub const UE_BIT : u8 = 0; pub const RE_BIT : u8 = 2; pub const TE_BIT : u8 = 3; pub const TC_BIT : u8 = 6; pub const TXE_BIT : u8 = 7; pub const RXNE_BIT : u8 = 5; pub fn serial_putc(ch : u8){ // send data let mut addr = (USART2_BASE + TDR_OFFSET) as *mut u32; // 0x28 let ch32 : u32 = ch as u32; unsafe { core::ptr::write_volatile(addr, ch32); //let _ = my_wait(0x1); } // wait until TC(Transmission complete) is set let mut val : u32 = 0; addr = (USART2_BASE + ISR_OFFSET) as *mut u32; // 0x1c while (val & (1 << TC_BIT)) == 0 { unsafe { val = core::ptr::read_volatile(addr); } } } pub fn serial_getc()-> u8 { // wait until RXNE is set let mut val : u32 = 0; let mut addr = (USART2_BASE + ISR_OFFSET) as *mut u32; // 0x1c while (val & (1 << RXNE_BIT)) == 0 { unsafe { val = core::ptr::read_volatile(addr); } } // recv data addr = (USART2_BASE + RDR_OFFSET) as *mut u32; // 0x28 let val : u32; unsafe { val = core::ptr::read_volatile(addr); } let ch = val as u8; ch } pub fn setup_serial(){ // set GPIO PA2, PA3 to alternate mode let mut addr = (GPIOA_BASE + MODER_OFFSET) as *mut u32; let mut set_mode = 0x2 << (GPIO_PIN_2 * 2); // 0x2 ... Alternate MODE set_mode |= 0x2 << (GPIO_PIN_3 * 2); // 0x2 ... Alternate MODE unsafe { let current = core::ptr::read_volatile(addr) ; let mut val = current & 0xFF_FF_FF_0F; val |= set_mode; core::ptr::write_volatile(addr, val) ; } // set GPIO PA2, PA3 to AF7 addr = (GPIOA_BASE + AFRL_OFFSET) as *mut u32; set_mode = 0x7 << (GPIO_PIN_2 * 4); // 0x7 ... UART set_mode |= 0x7 << (GPIO_PIN_3 * 4); // 0x7 ... UART unsafe { let current = core::ptr::read_volatile(addr) ; let mut val = current & 0xFF_FF_00_FF; val |= set_mode; core::ptr::write_volatile(addr, val) ; } // enable addr = (RCC_BASE + APB1ENR1_OFFSET) as *mut u32; // 0x58 set_mode = 0x1 << USART2EN; // USART2EN 17 unsafe { let current = core::ptr::read_volatile(addr) ; let mut val = current & 0xFF_FC_FF_FF; val |= set_mode; core::ptr::write_volatile(addr, val); } // set clock (USART2SEL) addr = (RCC_BASE + RCC_CCIPR) as *mut u32; // 0x88 set_mode = 0x1 << (USART2_SEL * 2 ); //01 .... SYSCLK unsafe { let current = core::ptr::read_volatile(addr) ; let mut val = current & 0xFF_FF_FF_F3; val |= set_mode; core::ptr::write_volatile(addr, val) ; } // set baud rate let div = 104; // 38400 (4MHz/38400 = 104.166666) addr = (USART2_BASE + BRR_OFFSET) as *mut u32; // unsafe { core::ptr::write_volatile(addr, div) ; } // enable UE/TE/RE set_mode = 0x1 << UE_BIT; // UE_BIT = 0 set_mode |= 0x1 << TE_BIT; // TE_BIT = 3 set_mode |= 0x1 << RE_BIT; // RE_BIT = 2 addr = (USART2_BASE + CR1_OFFSET) as *mut u32; // unsafe { let current = core::ptr::read_volatile(addr) ; let mut val = current & 0xff_ff_ff_f2; val |= set_mode; core::ptr::write_volatile(addr, val) ; } // send data just test addr = (USART2_BASE + TDR_OFFSET) as *mut u32; // 0x28 for _i in 0..20 { unsafe { let val = 0x33; core::ptr::write_volatile(addr, val) ; } let _ = my_wait(0x10); } }
参考にした動画。。。アドレスとかビット配列が違うが分かりやすい。感謝
#3. How to Configure UART using REGISTERS || STM32F4 - YouTube
I2C版は以下
#4. STM32F4 I2C Using Registers || Master mode || NO HAL || - YouTube