ひきつづき、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