Skip to content

Instantly share code, notes, and snippets.

@MathiasKoch
Created March 13, 2020 09:30
Show Gist options
  • Save MathiasKoch/586623739166a40238652dfef80eb20b to your computer and use it in GitHub Desktop.
Save MathiasKoch/586623739166a40238652dfef80eb20b to your computer and use it in GitHub Desktop.
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,
}
}
}
#![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