From dc38bc1d675ff42ce148afc4c2bef26aa454ed37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sat, 29 Jul 2023 12:59:12 +0200 Subject: [PATCH] feat(tests): add rtc counter test --- tests/counter/.cargo/config | 8 ++ tests/counter/Cargo.toml | 13 +++ tests/counter/config.gdb | 41 ++++++++ tests/counter/memory.x | 6 ++ tests/counter/src/main.rs | 181 ++++++++++++++++++++++++++++++++++++ 5 files changed, 249 insertions(+) create mode 100644 tests/counter/.cargo/config create mode 100644 tests/counter/Cargo.toml create mode 100644 tests/counter/config.gdb create mode 100644 tests/counter/memory.x create mode 100644 tests/counter/src/main.rs diff --git a/tests/counter/.cargo/config b/tests/counter/.cargo/config new file mode 100644 index 0000000..2550387 --- /dev/null +++ b/tests/counter/.cargo/config @@ -0,0 +1,8 @@ +[target.thumbv7m-none-eabi] +runner = 'probe-run --chip STM32F103C8' +rustflags = [ + "-C", "link-arg=-Tlink.x", +] + +[build] +target = "thumbv7m-none-eabi" diff --git a/tests/counter/Cargo.toml b/tests/counter/Cargo.toml new file mode 100644 index 0000000..4118d8a --- /dev/null +++ b/tests/counter/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "counter" +version = "0.1.0" +edition = "2021" + +[dependencies] +cortex-m = "0.7.7" +cortex-m-rt = "0.7.3" +embedded-hal = "0.2.7" +nb = "1.1.0" +panic-halt = "0.2.0" +stm32f1xx-hal = { version = "0.10.0", features = ["rt", "stm32f103", "medium"] } +you-can = "0.0.14" diff --git a/tests/counter/config.gdb b/tests/counter/config.gdb new file mode 100644 index 0000000..051f3c5 --- /dev/null +++ b/tests/counter/config.gdb @@ -0,0 +1,41 @@ +# GDB script for loading and running programs in STM32 Blue Pill. +# This file used to be .gdbinit, which could not be autoloaded due to autoloading security in GDB. + +# Send GDB commands to OpenOCD, which listens on port 3333. Extend the timeout. +target ext :3333 + +# Disable all messages. +set verbose off +set complaints 0 +set confirm off +set exec-done-display off +show exec-done-display +set trace-commands off +set debug displaced off +set debug expression 0 +set debug frame 0 +set debug infrun 0 +set debug observer 0 +set debug overload 0 +set pagination off +set print address off +set print symbol-filename off +set print symbol off +set print pretty off +set print object off +set debug parser off +set debug remote 0 + +# Print demangled symbols by default. +set print asm-demangle on + +# Enable ARM semihosting to show debug console output in OpenOCD console. +monitor arm semihosting enable + +monitor reset init +monitor sleep 50 +monitor halt +monitor sleep 50 + +load +continue diff --git a/tests/counter/memory.x b/tests/counter/memory.x new file mode 100644 index 0000000..71f245d --- /dev/null +++ b/tests/counter/memory.x @@ -0,0 +1,6 @@ +/* Linker script for the STM32F103C8T6 */ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 64K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} diff --git a/tests/counter/src/main.rs b/tests/counter/src/main.rs new file mode 100644 index 0000000..13893d1 --- /dev/null +++ b/tests/counter/src/main.rs @@ -0,0 +1,181 @@ +#![no_std] +#![no_main] + +use core::convert::Infallible; +use embedded_hal::digital::v2::{OutputPin, InputPin}; +use panic_halt as _; + +use nb::block; + +use cortex_m_rt::entry; +use stm32f1xx_hal::{pac, prelude::*, timer::{Timer, Tim1NoRemap, Tim2NoRemap, Tim3NoRemap}, rtc::Rtc}; + +struct Segments<'a> { + a: &'a mut dyn OutputPin, + b: &'a mut dyn OutputPin, + c: &'a mut dyn OutputPin, + d: &'a mut dyn OutputPin, + e: &'a mut dyn OutputPin, + f: &'a mut dyn OutputPin, + g: &'a mut dyn OutputPin +} + +fn set_segments(segments: &mut Segments, enabled_segments: (bool, bool, bool, bool, bool, bool, bool)) { + segments.a.set_state((!enabled_segments.0).into()).unwrap(); + segments.b.set_state((!enabled_segments.1).into()).unwrap(); + segments.c.set_state((!enabled_segments.2).into()).unwrap(); + segments.d.set_state((!enabled_segments.3).into()).unwrap(); + segments.e.set_state((!enabled_segments.4).into()).unwrap(); + segments.f.set_state((!enabled_segments.5).into()).unwrap(); + segments.g.set_state((!enabled_segments.6).into()).unwrap(); +} + +fn show_digit(segments: &mut Segments, digit: u8) { + match digit { + 0 => set_segments(segments, (true, true, true, true, true, true, false)), + 1 => set_segments(segments, (false, true, true, false, false, false, false)), + 2 => set_segments(segments, (true, true, false, true, true, false, true)), + 3 => set_segments(segments, (true, true, true, true, false, false, true)), + 4 => set_segments(segments, (false, true, true, false, false, true, true)), + 5 => set_segments(segments, (true, false, true, true, false, true, true)), + 6 => set_segments(segments, (true, false, true, true, true, true, true)), + 7 => set_segments(segments, (true, true, true, false, false, false, false)), + 8 => set_segments(segments, (true, true, true, true, true, true, true)), + 9 => set_segments(segments, (true, true, true, true, false, true, true)), + _ => set_segments(segments, (true, true, true, false, false, false, true)) + } +} + +fn get_digit(number: u32, digit_index: u8) -> u8 { + let mut number = number; + for _ in 0..digit_index { + number /= 10; + } + (number % 10) as u8 +} + +#[entry] +fn main() -> ! { + // Get access to the core peripherals from the cortex-m crate + let cp = cortex_m::Peripherals::take().unwrap(); + // Get access to the device specific peripherals from the peripheral access crate + let dp = pac::Peripherals::take().unwrap(); + + // Take ownership over the raw flash and rcc devices and convert them into the corresponding + // HAL structs + let mut pwr = dp.PWR; + let mut flash = dp.FLASH.constrain(); + let rcc = dp.RCC.constrain(); + let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut pwr); + + let mut rtc = Rtc::new(dp.RTC, &mut backup_domain); + + // Freeze the configuration of all the clocks in the system and store the frozen frequencies in + // `clocks` + let clocks = rcc + .cfgr + .use_hse(8.MHz()) + .sysclk(24.MHz()) + .pclk1(24.MHz()) + .pclk2(24.MHz()) + .freeze(&mut flash.acr); + + let mut gpiob = dp.GPIOB.split(); + let mut gpioa = dp.GPIOA.split(); + let mut gpioc = dp.GPIOC.split(); + let mut afio = dp.AFIO.constrain(); + + let (_, pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4); + + let mut led1 = gpiob.pb12.into_open_drain_output(&mut gpiob.crh); + let mut led2 = gpiob.pb11.into_open_drain_output(&mut gpiob.crh); + let mut led3 = gpiob.pb1.into_open_drain_output(&mut gpiob.crl); + let mut led4 = gpiob.pb0.into_open_drain_output(&mut gpiob.crl); + + let mut leds: [&mut dyn OutputPin; 4] = [&mut led1, &mut led2, &mut led3, &mut led4]; + + let btn1 = gpiob.pb15.into_pull_down_input(&mut gpiob.crh); + let btn2 = gpiob.pb14.into_pull_down_input(&mut gpiob.crh); + let btn3 = gpiob.pb13.into_pull_down_input(&mut gpiob.crh); + let btn4 = gpioc.pc13.into_floating_input(&mut gpioc.crh); + + let btns: [&dyn InputPin; 4] = [&btn1, &btn2, &btn3, &btn4]; + + let mut a = gpiob.pb10.into_open_drain_output(&mut gpiob.crh); + let mut b = gpiob.pb2.into_open_drain_output(&mut gpiob.crl); + let mut c = gpiob.pb8.into_open_drain_output(&mut gpiob.crh); + let mut d = gpiob.pb6.into_open_drain_output(&mut gpiob.crl); + let mut e = gpiob.pb9.into_open_drain_output(&mut gpiob.crh); + let mut f = pb3.into_open_drain_output(&mut gpiob.crl); + let mut g = pb4.into_open_drain_output(&mut gpiob.crl); + let mut dpp = gpiob.pb7.into_open_drain_output(&mut gpiob.crl); + dpp.set_high(); + + let mut segments = Segments { a: &mut a, b: &mut b, c: &mut c, d: &mut d, e: &mut e, f: &mut f, g: &mut g }; + + let dig1 = gpioa.pa6.into_alternate_open_drain(&mut gpioa.crl); + let dig2 = gpioa.pa3.into_alternate_open_drain(&mut gpioa.crl); + let dig3 = gpioa.pa7.into_alternate_open_drain(&mut gpioa.crl); + let dig4 = gpioa.pa8.into_alternate_open_drain(&mut gpioa.crh); + let dig5 = gpioa.pa9.into_alternate_open_drain(&mut gpioa.crh); + let dig6 = gpioa.pa2.into_alternate_open_drain(&mut gpioa.crl); + let dig7 = gpioa.pa10.into_alternate_open_drain(&mut gpioa.crh); + let dig8 = gpioa.pa1.into_alternate_open_drain(&mut gpioa.crl); + + let tim1 = Timer::new(dp.TIM1, &clocks); + let tim2 = Timer::new(dp.TIM2, &clocks); + let tim3 = Timer::new(dp.TIM3, &clocks); + + let pins1 = (dig4, dig5, dig7); + let pwm1 = tim1 + .pwm_hz::(pins1, &mut afio.mapr, 2.kHz()); + + let pins2 = (dig8, dig6, dig2); + let pwm2 = tim2 + .pwm_hz::(pins2, &mut afio.mapr, 2.kHz()); + + let pins3 = (dig1, dig3); + let pwm3 = tim3 + .pwm_hz::(pins3, &mut afio.mapr, 2.kHz()); + + let (mut dig4, mut dig5, mut dig7) = pwm1.split(); + let (mut dig8, mut dig6, mut dig2) = pwm2.split(); + let (mut dig1, mut dig3) = pwm3.split(); + + for led in leds.iter_mut() { + led.set_high().unwrap(); + } + + let mut digits: [&mut dyn _embedded_hal_PwmPin; 8] = [ &mut dig1, &mut dig2, &mut dig3, &mut dig4, &mut dig5, &mut dig6, &mut dig7, &mut dig8 ]; + for digit in digits.iter_mut() { + // has to be enabled, when disabled, 0 is outputted, meaning digit is turned on... + digit.enable(); + digit.set_duty(0xFFFF); + } + + // Configure the timer to trigger an update with freq of 500 Hz + let mut delay = cp.SYST.delay(&clocks); + let mut timer = Timer::new(dp.TIM4, &clocks).counter_hz(); + timer.start(500.Hz()).unwrap(); + + let mut digit_index = 0usize; + let mut counter = 1; + loop { + for digit in digits.iter_mut() { + digit.set_duty(0xFFFF); + } + + delay.delay_us(480_u16); + + show_digit(&mut segments, get_digit(counter, (digits.len() - digit_index - 1) as u8)); + // digits[digit_index].set_duty(11500); + digits[digit_index].set_duty(5000); + + digit_index = (digit_index + 1) % digits.len(); + if digit_index == 0 { + counter = rtc.current_time(); + } + + block!(timer.wait()).unwrap(); + } +} -- 2.48.1