Created
March 13, 2020 09:30
-
-
Save MathiasKoch/586623739166a40238652dfef80eb20b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use hal::{ | |
delay::Delay, | |
dma::{dma1, dma2, Event as DmaEvent}, | |
gpio::{ | |
gpioa::{PA0, PA1, PA15, PA6}, | |
gpiob::{PB1, PB14, PB4, PB6, PB7}, | |
gpioc::{PC13, PC4, PC5}, | |
gpiod::{PD14, PD15, PD3, PD5, PD6, PD8, PD9}, | |
gpioe::{PE0, PE1, PE2, PE4, PE5}, | |
Alternate, Edge, Floating, Input, OpenDrain, Output, PushPull, AF7, AF8, | |
}, | |
pac::{Peripherals, EXTI, TIM15, TIM2, TIM4, TIM6, UART4, USART1, USART2, USART3}, | |
// adc, | |
prelude::*, | |
rcc::{ClockSecuritySystem, Clocks, CrystalBypass, MsiFreq, PllConfig, PllDivider, PllSource}, | |
serial::{Config, Event as SerialEvent, Rx, Serial, Tx}, | |
// flash::{Flash} | |
time::{Bps, MonoTimer}, | |
timer::{Event as TimerEvent, Timer}, | |
}; | |
pub const DMA_HALF_BYTES: usize = 64; | |
type Tx4 = PA0<Alternate<AF8, Input<Floating>>>; | |
type Rx4 = PA1<Alternate<AF8, Input<Floating>>>; | |
type Rts4 = PA15<Alternate<AF8, Input<Floating>>>; | |
type Cts4 = PB7<Alternate<AF8, Input<Floating>>>; | |
type Serial4 = Serial<UART4, (Tx4, Rx4, Rts4, Cts4)>; | |
// type Serial4 = Serial<UART4, (Tx4, Rx4)>; | |
pub type Btn = PC13<Input<Floating>>; | |
pub struct BoardParts { | |
pub dma2_channels: dma2::Channels, | |
pub btn: Btn, | |
pub serial: Serial4, | |
} | |
pub struct FactbirdRevB; | |
impl FactbirdRevB { | |
pub fn new(mut dp: Peripherals) -> BoardParts { | |
// Enable exti clock | |
dp.RCC.apb2enr.write(|w| w.syscfgen().set_bit()); | |
let mut flash = dp.FLASH.constrain(); | |
let mut rcc = dp.RCC.constrain(); | |
let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); | |
let clocks = rcc | |
.cfgr | |
// .hsi48(true) | |
.lse(CrystalBypass::Disable, ClockSecuritySystem::Enable) | |
.hse(8.mhz(), CrystalBypass::Disable, ClockSecuritySystem::Enable) | |
.sysclk_with_pll(80.mhz(), PllConfig::new(1, 20, PllDivider::Div2)) | |
.pll_source(PllSource::HSE) | |
// Temp fix until PLLSAI1 is implemented | |
.msi(MsiFreq::RANGE48M) | |
.hclk(80.mhz()) | |
.pclk1(80.mhz()) | |
.pclk2(80.mhz()) | |
.freeze(&mut flash.acr, &mut pwr); | |
let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); | |
let mut gpiob = dp.GPIOB.split(&mut rcc.ahb2); | |
let mut gpioc = dp.GPIOC.split(&mut rcc.ahb2); | |
let mut gpiod = dp.GPIOD.split(&mut rcc.ahb2); | |
let mut gpioe = dp.GPIOE.split(&mut rcc.ahb2); | |
let dma2_channels = dp.DMA2.split(&mut rcc.ahb1); | |
// User button: | |
let mut btn = gpioc | |
.pc13 | |
.into_floating_input(&mut gpioc.moder, &mut gpioc.pupdr); | |
btn.make_interrupt_source(&mut dp.SYSCFG); | |
btn.enable_interrupt(&mut dp.EXTI); | |
btn.trigger_on_edge(&mut dp.EXTI, Edge::FALLING); | |
let mut serial = { | |
let tx = gpioa.pa0.into_af8(&mut gpioa.moder, &mut gpioa.afrl); | |
let rx = gpioa.pa1.into_af8(&mut gpioa.moder, &mut gpioa.afrl); | |
let rts = gpioa.pa15.into_af8(&mut gpioa.moder, &mut gpioa.afrh); | |
let cts = gpiob.pb7.into_af8(&mut gpiob.moder, &mut gpiob.afrl); | |
Serial::uart4( | |
dp.UART4, | |
(tx, rx, rts, cts), | |
Config::default().baudrate(115_200_u32.bps()), | |
clocks, | |
&mut rcc.apb1r1, | |
) | |
}; | |
serial.listen(SerialEvent::Idle); | |
BoardParts { | |
dma2_channels, | |
serial, | |
btn, | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![no_main] | |
#![no_std] | |
extern crate heapless; | |
#[macro_use] | |
extern crate log; | |
extern crate nb; | |
extern crate stm32l4xx_hal as hal; | |
use cortex_m::peripheral::DWT; | |
use lib::bsp; | |
use lib::logging; | |
use rtfm::{ | |
app, | |
cyccnt::{Duration, Instant, U32Ext}, | |
export::wfi, | |
}; | |
use hal::prelude::*; | |
use hal::dma::{dma2, CircBuffer, Event}; | |
use hal::pac::UART4; | |
use hal::serial::{Rx, Serial, Tx}; | |
#[app(device = hal::pac, peripherals = true, monotonic = rtfm::cyccnt::CYCCNT)] | |
const APP: () = { | |
struct Resources { | |
cb: CircBuffer<&'static mut [[u8; bsp::DMA_HALF_BYTES]; 2], dma2::C5>, | |
rx: Rx<UART4>, | |
tx: Tx<UART4>, | |
btn: bsp::Btn, | |
#[init([[0u8; bsp::DMA_HALF_BYTES]; 2])] | |
dma_buffer: [[u8; bsp::DMA_HALF_BYTES]; 2], | |
#[init(None)] | |
logger: Option<logging::LoggerType>, | |
} | |
#[init(resources = [dma_buffer, logger])] | |
fn init(mut ctx: init::Context) -> init::LateResources { | |
// Enable the DWT monotonic cycle counter for RTFM scheduling | |
ctx.core.DCB.enable_trace(); | |
DWT::unlock(); | |
ctx.core.DWT.enable_cycle_counter(); | |
let bsp::BoardParts { | |
mut dma2_channels, | |
serial, | |
btn, | |
.. | |
} = bsp::FactbirdRevB::new(ctx.device); | |
// Initialize logger | |
let logger = cortex_m_log::log::Logger { | |
inner: logging::create(ctx.core.ITM, serial).unwrap(), | |
level: log::LevelFilter::Trace, | |
}; | |
*ctx.resources.logger = Some(logger); | |
let log: &'static mut _ = ctx.resources.logger.as_mut().unwrap_or_else(|| { | |
panic!("Failed to get the static logger"); | |
}); | |
unsafe { | |
cortex_m_log::log::trick_init(&log).unwrap_or_else(|err| { | |
panic!("Failed to get initialize the logger {:?}", err); | |
}); | |
} | |
let (tx, rx) = serial.split(); | |
dma2_channels.5.listen(hal::dma::Event::HalfTransfer); | |
dma2_channels.5.listen(hal::dma::Event::TransferComplete); | |
let buffer: &'static mut [[u8; bsp::DMA_HALF_BYTES]; 2] = ctx.resources.dma_buffer; | |
init::LateResources { | |
cb: rx.circ_read(dma2_channels.5, buffer), | |
rx, | |
tx, | |
btn, | |
} | |
} | |
#[idle(resources = [sleep_time])] | |
fn idle(mut ctx: idle::Context) -> ! { | |
loop { | |
wfi(); | |
} | |
} | |
/// Handles the intermediate state where the DMA has data in it but | |
/// not enough to trigger a half or full dma complete | |
#[task(binds = UART4, resources = [cb, rx], priority = 3)] | |
fn serial_partial_dma(ctx: serial_partial_dma::Context) { | |
// let mgr = ctx.resources.cell_ingress; | |
// If the idle flag is set then we take what we have and push | |
// it into the ingress manager | |
// >>>>> Called every time something is received, but buf is always empty | |
info!("UART idle! \r"); | |
if ctx.resources.rx.is_idle(true) { | |
ctx.resources | |
.cb | |
.partial_peek(|buf, _half| { | |
let len = buf.len(); | |
info!("UART idle! {:?} {}\r", buf, len); | |
if len > 0 { | |
// mgr.write(buf); | |
} | |
Ok((len, ())) | |
}) | |
.unwrap_or_else(|err| { | |
error!("Failed to partial peek into circular buffer {:?}", err); | |
}); | |
} | |
} | |
/// Handles a full or hal full dma buffer of serial data, | |
/// and writes it into the MessageManager rb | |
#[task(binds = DMA2_CHANNEL5, resources = [cb], priority = 3)] | |
fn serial_full_dma(ctx: serial_full_dma::Context) { | |
// >>>>> NEVER CALLED! | |
info!("UART DMA!\r"); | |
ctx.resources | |
.cb | |
.peek(|buf, _half| { | |
// mgr.write(buf); | |
}) | |
.unwrap_or_else(|err| { | |
error!("Failed to full peek into circular buffer {:?}", err); | |
}); | |
} | |
#[task(binds = EXTI15_10, resources = [btn, tx], priority = 4)] | |
fn button(mut ctx: button::Context) { | |
let tx = ctx.resources.tx; | |
if ctx.resources.btn.check_interrupt() { | |
ctx.resources.btn.clear_interrupt_pending_bit(); | |
log::info!("BNT!\r"); | |
for c in "AT\r\n".as_bytes() { | |
nb::block!(tx.write(*c)).unwrap(); | |
} | |
} | |
} | |
// spare interrupt used for scheduling software tasks | |
extern "C" { | |
fn UART5(); | |
fn LCD(); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment