#![deny(unsafe_code)] #![no_std] #![no_main] // mod i2c_reg_slave; // mod i2c_slave; mod dmx; // extern crate panic_halt; extern crate panic_semihosting; #[rtic::app(device = stm32f1xx_hal::pac, dispatchers = [SPI1, SPI2, SPI3])] mod app { use crate::dmx::DMX; use stm32f1xx_hal::{ gpio::{self, ExtiPin}, pac, prelude::*, timer, }; use systick_monotonic::Systick; const DMX_LEN: usize = 512; // A monotonic timer to enable scheduling in RTIC #[monotonic(binds = SysTick, default = true)] type MyMono = Systick<100>; // 100 Hz / 10 ms granularity #[shared] struct Shared { dmx: DMX<DMX_LEN>, delay_us: timer::DelayUs<pac::TIM2>, int_led: gpio::gpiob::PB0<gpio::Output<gpio::OpenDrain>>, } #[local] struct Local { led: gpio::gpioc::PC13<gpio::Output<gpio::PushPull>>, int_pin: gpio::gpiob::PB10<gpio::Input<gpio::PullUp>>, } #[allow(unsafe_code)] #[init(local = [buffer: [u8; DMX_LEN * 2] = [0b0101_0101; DMX_LEN * 2]])] fn init(mut cx: init::Context) -> (Shared, Local, init::Monotonics) { // Take ownership over the raw flash and rcc devices and convert them into the corresponding // HAL structs let mut flash = cx.device.FLASH.constrain(); let rcc = cx.device.RCC.constrain(); // Freeze the configuration of all the clocks in the system and store the frozen frequencies in // `clocks` let clocks = rcc .cfgr // hf external quartz frequency .use_hse(8.MHz()) // system clock frequency .sysclk(72.MHz()) .freeze(&mut flash.acr); // Initialize the monotonic let mono = Systick::new(cx.core.SYST, clocks.sysclk().to_Hz()); // Acquire the peripherals let mut gpioa = cx.device.GPIOA.split(); let mut gpiob = cx.device.GPIOB.split(); let mut gpioc = cx.device.GPIOC.split(); let mut afio = cx.device.AFIO.constrain(); let dma1 = cx.device.DMA1.split(); // setup EXTI10 for Pin B10 let mut int_pin = gpiob.pb10.into_pull_up_input(&mut gpiob.crh); int_pin.make_interrupt_source(&mut afio); int_pin.enable_interrupt(&mut cx.device.EXTI); int_pin.trigger_on_edge(&mut cx.device.EXTI, gpio::Edge::Falling); unsafe { cx.core.NVIC.set_priority(pac::Interrupt::EXTI15_10, 1) }; // EXTI10 priority sender::spawn().unwrap(); ( Shared { dmx: DMX::new( cx.local.buffer, dma1.4, gpioa.pa8, gpioa.pa9, gpioa.pa10, &mut gpioa.crh, &mut afio.mapr, &clocks, ), // Configure timer delay_us: cx.device.TIM2.delay_us(&clocks), int_led: gpiob .pb0 .into_open_drain_output_with_state(&mut gpiob.crl, gpio::PinState::Low), }, Local { // Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function // in order to configure the port. For pins 0-7, crl should be passed instead. led: gpioc .pc13 .into_push_pull_output_with_state(&mut gpioc.crh, gpio::PinState::High), int_pin, }, init::Monotonics(mono), ) } #[idle] fn idle(_: idle::Context) -> ! { loop { rtic::export::wfi(); } } #[task(local = [led], shared = [delay_us, dmx])] fn sender(mut cx: sender::Context) { cx.shared.dmx.lock(DMX::start_tx); cx.local.led.toggle(); cx.shared.delay_us.lock(|d| d.delay(1.secs())); sender::spawn().unwrap(); } #[task(binds = DMA1_CHANNEL4, shared = [dmx, int_led])] fn waiter(cx: waiter::Context) { (cx.shared.dmx, cx.shared.int_led).lock(|dmx, int_led| { assert!(dmx.tx_is_idle()); int_led.toggle(); }); } #[task(binds = EXTI15_10, local = [int_pin], shared = [delay_us, int_led])] fn toggler(cx: toggler::Context) { (cx.shared.delay_us, cx.shared.int_led).lock(|delay_us, int_led| { int_led.toggle(); delay_us.delay(100.millis()); }); // clear EXTI10 pending status cx.local.int_pin.clear_interrupt_pending_bit() } }