Реализация I2C на Rust stm32f3discovery
Итак, я пытаюсь создать несколько функций, которые помогают взаимодействовать с интерфейсом i2c на stm32f3discovery. У меня проблемы со следующим кодом. Все это компилируется и запускается, но когда я запускаю цикл while, проверяющий, установлен ли регистр txis (проверяет, пуст ли txdr), он просто зависает в этой строке, и регистр, по-видимому, никогда не устанавливается. Если я возьму эту строку, она зависнет в цикле while, проверяя, очищен ли регистр tc (передача завершена).
my_api.rs
pub fn new(rcc: &stm32f3::stm32f303::RCC, gpiob: &stm32f3::stm32f303::GPIOB, i2c: &stm32f3::stm32f303::I2C1) -> Self {
rcc.apb1enr.write(|w| w.i2c1en().set_bit()); //enable i2c1 clock
rcc.ahbenr.write(|w| w.iopaen().set_bit()); //enable gpioa clock
gpiob.moder.write(|w| w.moder8().bits(0b10).moder9().bits(0b10)); //alternate function mode
gpiob.pupdr.write(|w| unsafe{w.pupdr8().bits(0b01).pupdr9().bits(0b01)}); //pull up resister
gpiob.otyper.write(|w| w.ot8().set_bit().ot9().set_bit()); //open drain output
gpiob.ospeedr.write(|w| w.ospeedr8().bits(0b11).ospeedr9().bits(0b11)); //high speed
gpiob.afrh.write(|w| w.afrh8().bits(0b0100).afrh9().bits(0b0100)); //alternate function 4
i2c.cr1.write(|w| w.pe().clear_bit());
i2c.timingr.write(|w| {
w.presc().bits(1); // all settings from page 849 on port mapping
w.scll().bits(0x13); // standard mode at 8MHz cpu and 100kHz i2c
w.sclh().bits(0xF);
w.sdadel().bits(0x2);
w.scldel().bits(0x4)
});
i2c.cr1.write(|w| {
w.nostretch().clear_bit();
w.txie().set_bit(); //enable interrupt registers
w.rxie().set_bit()
});
i2c.cr1.write(|w| w.pe().set_bit()); //enable preipheral
i2c_func{}
}
pub fn read(&self, i2c: &stm32f3::stm32f303::I2C1, device_address: u16, register_address: u8, request_length: u8, rx_data: &mut [u8]) {
i2c.cr2.write(|w| {
w.sadd().bits(device_address); //set device address
w.nbytes().bits(1); //amount of bytes to send
w.rd_wrn().clear_bit(); //set as a write operation
w.autoend().clear_bit()
});
i2c.cr2.write(|w| w.start().set_bit()); //send start signal
//hangs on this line
while i2c.isr.read().txis().bit_is_clear() {} //wait for txis to register to be set
i2c.txdr.write(|w| w.txdata().bits(register_address)); // Send the address of the register that we want to read: IRA_REG_M
while i2c.isr.read().tc().bit_is_clear() {} // Wait until transfer complete
i2c.cr2.modify(|_, w| {
w.nbytes().bits(request_length); //set
w.rd_wrn().set_bit();
w.autoend().set_bit()
});
i2c.cr2.write(|w| w.start().set_bit());
for count in 0..request_length{
// Wait until we have received the contents of the register
while i2c.isr.read().rxne().bit_is_clear() {}
// Broadcast STOP (automatic because of `AUTOEND = 1`)
rx_data[count as usize] = i2c.rxdr.read().rxdata().bits()
}
}
main.rs
#![no_std]
#![no_main]
// pick a panicking behavior
extern crate panic_halt; // you can put a breakpoint on `rust_begin_unwind` to catch panics
// extern crate panic_abort; // requires nightly
// extern crate panic_itm; // logs messages over ITM; requires ITM support
// extern crate panic_semihosting; // logs messages to the host stderr; requires a debugger
use cortex_m_rt::entry;
use cortex_m_semihosting::{debug, hprintln};
use stm32f3::stm32f303;
mod my_api;
#[entry]
fn main() -> ! {
//hprintln!("Starting Setup").unwrap();
let periph = stm32f303::Peripherals::take().unwrap();
let gpioe = periph.GPIOE;
let rcc = periph.RCC;
let tim6 = periph.TIM6;
let gpiob = periph.GPIOB;
let i2c1 = periph.I2C1;
let i2c = my_api::i2c_mod::i2c_func::new(&rcc, &gpiob, &i2c1);
let mut rx_data: [u8; 10] = [0,0,0,0,0,0,0,0,0,0];
i2c.read(&i2c1, 0b001_1110, 0x0A, 1, &mut rx_data);
hprintln!("{}", rx_data[0]).unwrap();
loop {}
}