1

我正在尝试在 BBC:Microbit 上用 Rust 编写一些程序。这个关于 rust 的微控制器的书还没有完成,所以我遗漏了一些观点。

实际上,我对 I2C 总线有一些问题。有 Rust crate microbit https://github.com/therealprof/microbit允许使用外设,它有一些漂亮的例子。但是,我不确定它们是否都在工作。

当我尝试运行名为i2c_direct_printmagserial我猜应该打印一些磁力计读数的示例时,我只收到以下消息:

Welcome to the magnetometer reader!

这就是代码的样子

#![no_std]

use panic_halt as _;

use microbit::hal::nrf51::*;
use microbit::hal::nrf51::{interrupt, UART0};
use microbit::NVIC;

use cortex_m::interrupt::Mutex;

use core::cell::RefCell;
use core::fmt::Write;
use cortex_m_rt::entry;

static RTC: Mutex<RefCell<Option<RTC0>>> = Mutex::new(RefCell::new(None));
static UART: Mutex<RefCell<Option<UART0>>> = Mutex::new(RefCell::new(None));
static TWI: Mutex<RefCell<Option<TWI1>>> = Mutex::new(RefCell::new(None));

#[entry]
fn main() -> ! {
    if let Some(p) = microbit::Peripherals::take() {
        p.CLOCK.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });

        while p.CLOCK.events_lfclkstarted.read().bits() == 0 {}

        /* And then set it back to 0 again, just because ?!? */
        p.CLOCK.events_lfclkstarted.write(|w| unsafe { w.bits(0) });

        p.GPIO.pin_cnf[24].write(|w| w.pull().pullup().dir().output());
        p.GPIO.pin_cnf[25].write(|w| w.pull().disabled().dir().input());

        p.UART0.pseltxd.write(|w| unsafe { w.bits(24) });
        p.UART0.pselrxd.write(|w| unsafe { w.bits(25) });

        p.UART0.baudrate.write(|w| w.baudrate().baud115200());
        p.UART0.enable.write(|w| w.enable().enabled());

        let _ = write!(
            UART0Buffer(&p.UART0),
            "\n\rWelcome to the magnetometer reader!\n\r"
        );

        p.RTC0.prescaler.write(|w| unsafe { w.bits(4095) });
        p.RTC0.evtenset.write(|w| w.tick().set_bit());
        p.RTC0.intenset.write(|w| w.tick().set_bit());
        p.RTC0.tasks_start.write(|w| unsafe { w.bits(1) });

        /* Prepare PIN0 and PIN30 for I2C SDA and SCL */
        p.GPIO.pin_cnf[0].write(|w| w.pull().disabled().dir().input().drive().s0d1());
        p.GPIO.pin_cnf[30].write(|w| w.pull().disabled().dir().input().drive().s0d1());

        {
            let twi = &p.TWI1;

            /* Set pins 0 and 30 for I2C SDA and SCL */
            twi.pselscl.write(|w| unsafe { w.bits(0) });
            twi.pselsda.write(|w| unsafe { w.bits(30) });

            /* Enable I2C */
            twi.enable.write(|w| w.enable().enabled());

            /* Configure magnetometer for automatic updates */
            twi.address.write(|w| unsafe { w.address().bits(0x0E) });
            twi.tasks_starttx.write(|w| unsafe { w.bits(1) });

            twi.txd.write(|w| unsafe { w.bits(0x10) });
            while twi.events_txdsent.read().bits() == 0 {}
            twi.events_txdsent.write(|w| unsafe { w.bits(0) });

            twi.txd.write(|w| unsafe { w.bits(0x1) });
            while twi.events_txdsent.read().bits() == 0 {}
            twi.events_txdsent.write(|w| unsafe { w.bits(0) });
            twi.tasks_stop.write(|w| unsafe { w.bits(1) });

            twi.address.write(|w| unsafe { w.address().bits(0x0E) });
            twi.tasks_starttx.write(|w| unsafe { w.bits(1) });

            twi.txd.write(|w| unsafe { w.bits(0x11) });
            while twi.events_txdsent.read().bits() == 0 {}
            twi.events_txdsent.write(|w| unsafe { w.bits(127) });

            twi.txd.write(|w| unsafe { w.bits(0x1) });
            while twi.events_txdsent.read().bits() == 0 {}
            twi.events_txdsent.write(|w| unsafe { w.bits(0) });
            twi.tasks_stop.write(|w| unsafe { w.bits(1) });
        }

        cortex_m::interrupt::free(move |cs| {
            *RTC.borrow(cs).borrow_mut() = Some(p.RTC0);
            *UART.borrow(cs).borrow_mut() = Some(p.UART0);
            *TWI.borrow(cs).borrow_mut() = Some(p.TWI1);
        });

        unsafe {
            NVIC::unmask(microbit::Interrupt::RTC0);
        }
        microbit::NVIC::unpend(microbit::Interrupt::RTC0);
    }

    loop {
        continue;
    }
}

// Define an interrupt handler, i.e. function to call when exception occurs. Here if our timer
// trips, we'll read data from the accelerometer
#[interrupt]
fn RTC0() {
    /* Enter critical section */
    cortex_m::interrupt::free(|cs| {
        if let (Some(rtc), Some(twi)) = (
            RTC.borrow(cs).borrow().as_ref(),
            TWI.borrow(cs).borrow().as_ref(),
        ) {
            let mut data: [u8; 6] = [0; 6];

            /* Request data */
            twi.address.write(|w| unsafe { w.address().bits(0x0E) });
            twi.tasks_starttx.write(|w| unsafe { w.bits(1) });
            twi.txd.write(|w| unsafe { w.bits(0x1) });
            while twi.events_txdsent.read().bits() == 0 {}
            twi.events_txdsent.write(|w| unsafe { w.bits(0) });

            /* Turn around to read data */
            twi.shorts.write(|w| w.bb_suspend().enabled());
            twi.tasks_startrx.write(|w| unsafe { w.bits(1) });

            /* Get 5 values */
            for d in &mut data {
                while twi.events_rxdready.read().bits() == 0 {}
                *d = twi.rxd.read().bits() as u8;
                twi.events_rxdready.write(|w| unsafe { w.bits(0) });

                twi.tasks_resume.write(|w| unsafe { w.bits(1) });
            }

            /* Get the last value */
            twi.shorts.write(|w| w.bb_stop().enabled());
            twi.tasks_resume.write(|w| unsafe { w.bits(1) });

            while twi.events_rxdready.read().bits() == 0 {}
            data[5] = twi.rxd.read().bits() as u8;
            twi.events_rxdready.write(|w| unsafe { w.bits(0) });

            /* Join and translate 2s complement values */

            let (x, y, z) = (
                (u16::from(data[0]) << 8 | u16::from(data[1])) as i16,
                (u16::from(data[2]) << 8 | u16::from(data[3])) as i16,
                (u16::from(data[4]) << 8 | u16::from(data[5])) as i16,
            );

            /* Print read values on the serial console */
            if let Some(uart) = UART.borrow(cs).borrow().as_ref() {
                let _ = write!(UART0Buffer(uart), "x: {}, y: {}, z: {}\n\r", x, y, z);
            }

            /* Clear timer event */
            rtc.events_tick.write(|w| unsafe { w.bits(0) });
        }
    });

    loop {
        continue;
    }
}

pub struct UART0Buffer<'a>(pub &'a UART0);

impl<'a> core::fmt::Write for UART0Buffer<'a> {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        let uart0 = self.0;
        uart0.tasks_starttx.write(|w| unsafe { w.bits(1) });
        for c in s.as_bytes() {
            /* Write the current character to the output register */
            uart0.txd.write(|w| unsafe { w.bits(u32::from(*c)) });

            /* Wait until the UART is clear to send */
            while uart0.events_txdrdy.read().bits() == 0 {}

            /* And then set it back to 0 again, just because ?!? */
            uart0.events_txdrdy.write(|w| unsafe { w.bits(0) });
        }
        uart0.tasks_stoptx.write(|w| unsafe { w.bits(1) });
        Ok(())
    }
}

我认为这是地址问题,因为我在这里找到了不同的磁力计地址

所以,正如你可能猜到的,改变这条线 twi.address.write(|w| unsafe { w.address().bits(0x0E) });

twi.address.write(|w| unsafe { w.address().bits(0x1E) });

没有帮助,但是,出现了这条消息

x:0, y: 0, z: 0

我真的是硬件编程的新手,所以我可以使用任何帮助

4

0 回答 0