From 4160df667ff63b6068337271060137debf2b764c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 12 Dec 2021 13:46:45 +0100 Subject: [PATCH] Completed BSP core features - Added basic accelerometer example. Board in not populated so it is not complete, but it provides a starting point - Added ADC base library and example building on the new `max116xx-10bit` device driver crate --- .vscode/launch.json | 1 - Cargo.toml | 15 +- README.md | 11 ++ .../{temp-sensor.rs => adt75-temp-sensor.rs} | 0 examples/adxl343-accelerometer.rs | 89 +++++++++ examples/max11619-adc.rs | 186 ++++++++++++++++++ src/lib.rs | 1 + src/max11619.rs | 48 +++++ 8 files changed, 349 insertions(+), 2 deletions(-) rename examples/{temp-sensor.rs => adt75-temp-sensor.rs} (100%) create mode 100644 examples/adxl343-accelerometer.rs create mode 100644 examples/max11619-adc.rs create mode 100644 src/max11619.rs diff --git a/.vscode/launch.json b/.vscode/launch.json index 9ca710e..dbc7f05 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,6 @@ "request": "launch", "name": "Debug Blinky", "servertype": "jlink", - "gdbPath": "/usr/bin/gdb-multiarch", "cwd": "${workspaceRoot}", "device": "VA10820", "svdFile": "../va108xx-rs/va108xx.svd", diff --git a/Cargo.toml b/Cargo.toml index b88ddad..cb8fb99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,12 @@ cortex-m = "0.7.3" cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" +[dependencies.max116xx-10bit] +path = "../max116xx-10bit" + [dependencies.va108xx-hal] -version = "0.2.3" +path = "../va108xx-hal" +# version = "0.4.1" features = ["rt"] [features] @@ -27,7 +31,16 @@ cortex-m-rtic = "0.6.0-rc.4" panic-rtt-target = { version = "0.1", features = ["cortex-m"] } rtt-target = { version = "0.3", features = ["cortex-m"] } panic-halt = "0.2" +nb = "1.0.0" [[example]] name = "blinky-button-rtic" required-features = ["rt"] + +[[example]] +name = "adxl343-accelerometer" +required-features = ["rt"] + +[[example]] +name = "max11619-adc" +required-features = ["rt", "nb"] diff --git a/README.md b/README.md index 01c1c08..a9b1da8 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,17 @@ the [`Cortex-Debug` plugin](https://marketplace.visualstudio.com/items?itemName= Some sample configuration files for VS code were provided as well. You can simply use `Run and Debug` to automatically rebuild and flash your application. +The `tasks.json` and the `launch.json` files are generic and you can use them immediately by +opening the folder in VS code or adding it to a workspace. + +If you would like to use a custom GDB application, you can specify the gdb binary in the following +configuration variables in your `settings.json`: + +- `"cortex-debug.gdbPath"` +- `"cortex-debug.gdbPath.linux"` +- `"cortex-debug.gdbPath.windows"` +- `"cortex-debug.gdbPath.osx"` + ## Flashing the non-volatile memory Coming Soon diff --git a/examples/temp-sensor.rs b/examples/adt75-temp-sensor.rs similarity index 100% rename from examples/temp-sensor.rs rename to examples/adt75-temp-sensor.rs diff --git a/examples/adxl343-accelerometer.rs b/examples/adxl343-accelerometer.rs new file mode 100644 index 0000000..38f2ad9 --- /dev/null +++ b/examples/adxl343-accelerometer.rs @@ -0,0 +1,89 @@ +//! ADXL343 accelerometer example +//! +//! Please note that the default REB1 board is not populated with the ADXL343BCCZ-RL7. +//! To use this example, this chip needs to be soldered onto the board. +#![no_main] +#![no_std] +use cortex_m_rt::entry; +use embedded_hal::spi; +use panic_rtt_target as _; +use rtt_target::{rprintln, rtt_init_print}; +use va108xx_hal::{ + gpio::PinsA, + pac::{self, interrupt}, + prelude::*, + spi::{Spi, SpiConfig, TransferConfig}, + timer::{default_ms_irq_handler, set_up_ms_timer, Delay}, +}; + +const READ_MASK: u8 = 1 << 7; +const _MULTI_BYTE_MASK: u8 = 1 << 6; +const DEVID_REG: u8 = 0x00; + +const POWER_CTL_REG: u8 = 0x2D; +const PWR_MEASUREMENT_MODE_MASK: u8 = 1 << 3; + +#[entry] +fn main() -> ! { + rtt_init_print!(); + rprintln!("-- Vorago Accelerometer Example --"); + let mut dp = pac::Peripherals::take().unwrap(); + let tim0 = set_up_ms_timer( + &mut dp.SYSCONFIG, + &mut dp.IRQSEL, + 50.mhz().into(), + dp.TIM0, + interrupt::OC0, + ); + let mut delay = Delay::new(tim0); + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0); + } + + let pinsa = PinsA::new(&mut dp.SYSCONFIG, None, dp.PORTA); + let spi_cfg = SpiConfig::default(); + let (sck, mosi, miso) = ( + pinsa.pa20.into_funsel_2(), + pinsa.pa19.into_funsel_2(), + pinsa.pa18.into_funsel_2(), + ); + let cs_pin = pinsa.pa16.into_funsel_2(); + + // Need to set the ADC chip select low + let mut adc_cs = pinsa.pa17.into_push_pull_output(); + adc_cs + .set_high() + .expect("Setting ADC chip select high failed"); + + let transfer_cfg = TransferConfig::new(1.mhz(), spi::MODE_3, Some(cs_pin), false, true); + let mut spi = Spi::spib( + dp.SPIB, + (sck, miso, mosi), + 50.mhz(), + spi_cfg, + Some(&mut dp.SYSCONFIG), + Some(&transfer_cfg.downgrade()), + ); + + let mut send_buf: [u8; 3] = [0; 3]; + send_buf[0] = READ_MASK | DEVID_REG; + let reply = spi + .transfer(&mut send_buf[0..2]) + .expect("Reading DEVID register failed"); + rprintln!("DEVID register: {}", reply[1]); + + send_buf[0] = POWER_CTL_REG; + send_buf[1] = PWR_MEASUREMENT_MODE_MASK; + spi.write(&send_buf[0..2]) + .expect("Enabling measurement mode failed"); + + loop { + delay.delay_ms(500); + todo!("Not implemented for now, is not populated on the board.."); + } +} + +#[interrupt] +fn OC0() { + default_ms_irq_handler(); +} diff --git a/examples/max11619-adc.rs b/examples/max11619-adc.rs new file mode 100644 index 0000000..a4d8862 --- /dev/null +++ b/examples/max11619-adc.rs @@ -0,0 +1,186 @@ +//! MAX11619 ADC example applikcation +#![no_main] +#![no_std] + +use core::panic; + +use cortex_m_rt::entry; +use embedded_hal::spi; +use panic_rtt_target as _; +use rtt_target::{rprintln, rtt_init_print}; +use va108xx_hal::{ + gpio::PinsA, + pac::{self, interrupt, SPIB}, + prelude::*, + spi::{Spi, SpiBase, SpiConfig, TransferConfig}, + timer::{default_ms_irq_handler, set_up_ms_timer, Delay}, + utility::*, +}; +use vorago_reb1::max11619::{ + max11619_externally_clocked, max11619_internally_clocked, EocPin, AN2_CHANNEL, + POTENTIOMETER_CHANNEL, +}; + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum ExampleMode { + UsingEoc, + NotUsingEoc, +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum ReadMode { + Single, + Multiple, + MultipleNToHighest, +} + +const EXAMPLE_MODE: ExampleMode = ExampleMode::NotUsingEoc; +const READ_MODE: ReadMode = ReadMode::Multiple; + +#[entry] +fn main() -> ! { + rtt_init_print!(); + rprintln!("-- Vorago ADC Example --"); + + let mut dp = pac::Peripherals::take().unwrap(); + let tim0 = set_up_ms_timer( + &mut dp.SYSCONFIG, + &mut dp.IRQSEL, + 50.mhz().into(), + dp.TIM0, + interrupt::OC0, + ); + let delay = Delay::new(tim0); + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0); + } + + let pinsa = PinsA::new(&mut dp.SYSCONFIG, None, dp.PORTA); + let mut spi_cfg = SpiConfig::default(); + spi_cfg.scrdv = 0x07; + let (sck, mosi, miso) = ( + pinsa.pa20.into_funsel_2(), + pinsa.pa19.into_funsel_2(), + pinsa.pa18.into_funsel_2(), + ); + + port_mux(&mut dp.IOCONFIG, PortSel::PortB, 16, Funsel::Funsel1).ok(); + // port_mux(&mut dp.IOCONFIG, PortSel::PortB, 17, Funsel::Funsel1).ok(); + port_mux(&mut dp.IOCONFIG, PortSel::PortB, 18, Funsel::Funsel1).ok(); + port_mux(&mut dp.IOCONFIG, PortSel::PortB, 19, Funsel::Funsel1).ok(); + // Set the accelerometer chip select low in case the board slot is populated + let mut accel_cs = pinsa.pa16.into_push_pull_output(); + accel_cs + .set_high() + .expect("Setting accelerometer chip select high failed"); + + let transfer_cfg = TransferConfig::new( + 3.mhz(), + spi::MODE_0, + Some(pinsa.pa17.into_funsel_2()), + true, + false, + ); + let spi = Spi::spib( + dp.SPIB, + (sck, miso, mosi), + 50.mhz(), + spi_cfg, + Some(&mut dp.SYSCONFIG), + Some(&transfer_cfg.downgrade()), + ) + .downgrade(); + match EXAMPLE_MODE { + ExampleMode::NotUsingEoc => spi_example_externally_clocked(spi, delay), + ExampleMode::UsingEoc => { + spi_example_internally_clocked(spi, delay, pinsa.pa14.into_floating_input()); + } + } +} + +#[interrupt] +fn OC0() { + default_ms_irq_handler(); +} + +fn spi_example_externally_clocked(spi: SpiBase, mut delay: Delay) -> ! { + let mut adc = max11619_externally_clocked(spi) + .expect("Creating externally clocked MAX11619 device failed"); + let mut cmd_buf: [u8; 32] = [0; 32]; + let mut counter = 0; + loop { + rprintln!("-- Measurement {} --", counter); + + match READ_MODE { + ReadMode::Single => { + rprintln!("Reading single potentiometer channel"); + let pot_val = match adc.read_single_channel(&mut cmd_buf, POTENTIOMETER_CHANNEL) { + Ok(pot_val) => pot_val, + _ => { + panic!("Creating externally clocked MAX11619 ADC failed"); + } + }; + rprintln!("Single channel read:"); + rprintln!("\tPotentiometer value: {}", pot_val); + } + ReadMode::Multiple => { + let mut res_buf: [u16; 4] = [0; 4]; + match adc.read_multiple_channels_0_to_n( + &mut cmd_buf, + &mut res_buf.iter_mut(), + POTENTIOMETER_CHANNEL, + ) { + Ok(_) => { + rprintln!("Multi channel read from 0 to 3:"); + rprintln!("\tAN0 value: {}", res_buf[0]); + rprintln!("\tAN1 value: {}", res_buf[1]); + rprintln!("\tAN2 value: {}", res_buf[2]); + rprintln!("\tAN3 / Potentiometer value: {}", res_buf[3]); + } + _ => { + panic!("Multi-Channel read failed"); + } + } + } + ReadMode::MultipleNToHighest => { + let mut res_buf: [u16; 2] = [0; 2]; + match adc.read_multiple_channels_n_to_highest( + &mut cmd_buf, + &mut res_buf.iter_mut(), + AN2_CHANNEL, + ) { + Ok(_) => { + rprintln!("Multi channel read from 2 to 3:"); + rprintln!("\tAN2 value: {}", res_buf[0]); + rprintln!("\tAN3 / Potentiometer value: {}", res_buf[1]); + } + _ => { + panic!("Multi-Channel read failed"); + } + } + } + } + counter += 1; + delay.delay_ms(500); + } +} + +fn spi_example_internally_clocked(spi: SpiBase, mut delay: Delay, mut eoc_pin: EocPin) -> ! { + let mut adc = max11619_internally_clocked(spi).expect("Creaintg MAX116xx device failed"); + let mut counter = 0; + loop { + rprintln!("-- Measurement {} --", counter); + match adc.request_single_channel(POTENTIOMETER_CHANNEL) { + Ok(_) => (), + _ => panic!("Requesting single channel value failed"), + }; + + let pot_val = match nb::block!(adc.get_single_channel(&mut eoc_pin)) { + Ok(pot_val) => pot_val, + _ => panic!("Reading single channel value failed"), + }; + rprintln!("\tPotentiometer value: {}", pot_val); + counter += 1; + delay.delay_ms(500); + } +} diff --git a/src/lib.rs b/src/lib.rs index 09ad829..e2fd4e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,4 +2,5 @@ pub mod button; pub mod leds; +pub mod max11619; pub mod temp_sensor; diff --git a/src/max11619.rs b/src/max11619.rs new file mode 100644 index 0000000..cc52b55 --- /dev/null +++ b/src/max11619.rs @@ -0,0 +1,48 @@ +use max116xx_10bit::{ + Error, ExternallyClocked, InternallyClockedInternallyTimedSerialInterface, Max11619, + Max116xx10Bit, RefMode, WithoutWakeupDelay, +}; +use embedded_hal::blocking::spi::Transfer; +use embedded_hal::spi::FullDuplex; +use va108xx_hal::gpio::{Floating, Input, Pin, PA14}; + +pub type Max11619ExternallyClocked = + Max116xx10Bit; +pub type Max11619InternallyClocked = Max116xx10Bit< + SPI, + Max11619, + InternallyClockedInternallyTimedSerialInterface, + WithoutWakeupDelay, +>; +pub type EocPin = Pin>; + +pub const AN0_CHANNEL: u8 = 0; +pub const AN1_CHANNEL: u8 = 1; +pub const AN2_CHANNEL: u8 = 2; +pub const POTENTIOMETER_CHANNEL: u8 = 3; + +pub fn max11619_externally_clocked( + spi: SPI, +) -> Result, Error> +where + SPI: Transfer + FullDuplex, +{ + let adc: Max116xx10Bit = + Max116xx10Bit::new(spi, RefMode::ExternalSingleEndedNoWakeupDelay)?; + Ok(adc) +} + +pub fn max11619_internally_clocked( + spi: SPI, +) -> Result, Error> +where + SPI: Transfer + FullDuplex, +{ + let adc: Max116xx10Bit< + SPI, + Max11619, + InternallyClockedInternallyTimedSerialInterface, + WithoutWakeupDelay, + > = Max116xx10Bit::new(spi, RefMode::ExternalSingleEndedNoWakeupDelay)?; + Ok(adc) +}