#![no_std] #![no_main] #![allow(unused_imports, dead_code, unused_variables, unused_mut)] use core::panic::PanicInfo; use embassy_executor::Spawner; use embassy_rp::gpio::{Input, Level, Output, Pin, Pull}; // USB driver use embassy_rp::usb::{Driver, InterruptHandler as USBInterruptHandler}; use embassy_rp::{bind_interrupts, peripherals::USB}; use log::info; use embassy_time::Timer; // I2C use embassy_rp::i2c::{Config as I2cConfig, I2c, InterruptHandler as I2CInterruptHandler}; use embassy_rp::peripherals::I2C0; use embedded_hal_async::i2c::{Error, I2c as _}; use core::cell::RefCell; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_rp::spi; use embassy_rp::spi::{Async, Blocking, Spi}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use core::fmt::Write; use embassy_time::Delay; use embedded_graphics::mono_font::iso_8859_16::FONT_10X20; use embedded_graphics::mono_font::MonoTextStyle; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::text::renderer::CharacterStyle; use embedded_graphics::text::Text; use heapless::String; use lab07_all::SPIDeviceInterface; use st7789::{Orientation, ST7789}; bind_interrupts!(struct Irqs { // Use for the serial over USB driver USBCTRL_IRQ => USBInterruptHandler<USB>; I2C0_IRQ => I2CInterruptHandler<I2C0>; }); const DISPLAY_FREQ: u32 = 64_000_000; #[embassy_executor::task] async fn logger_task(driver: Driver<'static, USB>) { embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver); } // The formula for calculating the actual temperature value (in Celsius) from the raw value fn calculate_temperature(temperature_raw: u32) -> i32 { let var1: i32 = ((temperature_raw as i32 >> 3) - (27504 << 1)) * (26435 >> 11); let var2: i32 = ((temperature_raw as i32 >> 4) - 27504) * (((temperature_raw as i32 >> 4) - 27504) >> 12) * (-1000 >> 14); ((var1 + var2) * 5 + 128) >> 8 } #[embassy_executor::main] async fn main(spawner: Spawner) { let peripherals = embassy_rp::init(Default::default()); // Start the serial port over USB driver let driver = Driver::new(peripherals.USB, Irqs); spawner.spawn(logger_task(driver)).unwrap(); let mut display_config = spi::Config::default(); display_config.frequency = DISPLAY_FREQ; display_config.phase = spi::Phase::CaptureOnSecondTransition; display_config.polarity = spi::Polarity::IdleHigh; // Display SPI pins let miso = peripherals.PIN_4; let mosi = peripherals.PIN_19; let clk = peripherals.PIN_18; // Display SPI let mut spi_display: Spi<'_, _, Blocking> = Spi::new_blocking(peripherals.SPI0, clk, mosi, miso, display_config.clone()); // SPI bus for display let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi_display)); let mut display_cs = Output::new(peripherals.PIN_17, Level::High); // Display SPI device initialization let display_spi = SpiDeviceWithConfig::new(&spi;_bus, display_cs, display_config); // Other display pins let rst = peripherals.PIN_0; let dc = peripherals.PIN_16; let dc = Output::new(dc, Level::Low); let rst = Output::new(rst, Level::Low); let di = SPIDeviceInterface::new(display_spi, dc); // Init ST7789 LCD let mut display = ST7789::new(di, rst, 240, 240); display.init(&mut; Delay).unwrap(); display.set_orientation(Orientation::Portrait).unwrap(); display.clear(Rgb565::BLACK).unwrap(); // Define style let mut style = MonoTextStyle::new(&FONT;_10X20, Rgb565::GREEN); style.set_background_color(Some(Rgb565::BLACK)); // EXERCISE 2 -------------------- // TODO 1: Declare SDA and SCL pins let sda = peripherals.PIN_26; let scl = peripherals.PIN_27; // TODO 2: Define async I2C let mut i2c = I2c::new_async(peripherals.I2C0, scl, sda, Irqs, I2cConfig::default()); // TODO 3: Define I2C address of the BMP280 (from lab or from datasheet) const BMP280_ADDR: u16 = 0x76; // TODO 4: Define ID register address (from last lab or from datasheet) const REG_ADDR_ID: u8 = 0xD0; // EXERCISE 3 -------------------- // TODO 9: Define CTRL_MEAS register address const REG_ADDR_CTRL_MEAS: u8 = 0x00; // TODO 12: Define PRESS register address const REG_ADDR_PRESS_MSB: u8 = 0x00; // TODO 17: Define TEMP register address const REG_ADDR_TEMP_MSB: u8 = 0x00; // TODO 5: Define TX buffer that will be sent to the sensor // This should be initialized with one element: the address of the register we want to read let tx_buf = [0xFA]; // TODO 6: Define RX buffer that will store the value received from the sensor // This can be initially set to a buffer with one empty value (0) // This will store the value of the register we read from the sensor let mut rx_buf = [0x00u8]; let mut id: u8 = 0; match i2c.write_read_async(BMP280_ADDR, tx_buffer.iter().copied(), &mut; rx_buffer).await { Ok(_) => { id = rx_buffer[0]; info!("ID of BMP280: {}", id); } Err(e) => { info!("Error reading ID: {:?}", e); } } loop { Timer::after_millis(1000).await; info!("ID of BMP280: {id}"); // TODO 10: Define TX buffer for configuring the sensor (for writing to the `ctrl_meas` register) // The contents of the buffer are similar to what we used in the last lab with SPI // TODO 11: Write this buffer to the sensor (`write`) // TODO 13: Define TX and RX buffers for reading pressure registers // Hint: The RX buffer should have 3 elements, since we want to // read press_msb, press_lsb and press_xlsb // TODO 14: Read the three pressure register values from the sensor (just like you did with the `id`) // TODO 15: Compute the raw pressure value from the three register values let pressure_raw: u32 = 0; // modify // TODO 16: Print the raw pressure value info!("Raw pressure reading: {pressure_raw}"); // TODO 18: Define TX and RX buffers for reading temperature registers // TODO 19: Read the three temperature register values from the sensor // TODO 20: Compute the raw temperature value from the three register values let temperature_raw: u32 = 0; // modify // TODO 21: Get the actual temperature value (in Celsius), using the provided `calculate_temperature` // function let temperature: i32 = 0; // modify // TODO 22: Print the actual temperature value info!("Temperature reading (Celsius): {temperature}"); // END EXERCISE 3 ------------------------- // EXERCISE 4 // TODO 23: Print the raw pressure and the actual temperature to the screen // Hint: The temperature value returned by the `calculate_temperature` function is 100 * temperature // Print the correct value to the screen, as a rational number (example: 24.50 degrees) } } #[panic_handler] fn panic(_info: &PanicInfo;) -> ! { loop {} }