Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • c3pb/heizung
1 result
Show changes
Commits on Source (3)
nix-shell -p rustup udev.dev pkg-config openssl.dev
cargo install probe-rs-cli
cargo install probe-rs-cli # renamed to probe-rs-tools, it seems
cargo install probe-rs-debugger
# https://github.com/raspberrypi/picoprobe
# https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf
......@@ -18,3 +18,5 @@ python download_firmware_via_modbus.py
~/.cargo/bin/probe-rs-cli gdb --chip rp2040
gdb ./target/thumbv6m-none-eabi/debug/heizung
target remote localhost:1337
cargo-flash --release --chip RP2040
......@@ -15,14 +15,16 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::mutex::Mutex;
use embassy_time::{Duration, Timer, Instant};
use embassy_rp::gpio::{Input, Level, Output, Pull};
use embassy_rp::i2c;
use embassy_rp::{i2c, Peripheral};
use embassy_rp::interrupt;
//use embedded_hal_async::i2c::I2c;
use embassy_embedded_hal::SetConfig;
use embassy_rp::uart::{self, Parity};
use embassy_rp::pio::Pio;
use embassy_rp::pwm::{self, Pwm};
use {defmt_rtt as _, panic_probe as _};
use heapless::String;
use smart_leds::RGB8;
use heizung::i2c_scan::{self, ScanResultForBus};
use heizung::modbus_server::{ModbusServer, ModbusRegisters, ModbusErrorCode, ModbusAdressMatch, U16Pusher};
......@@ -30,6 +32,7 @@ use heizung::program_info::{ProgramInfoBuilder, PinFunction, ConstString};
use heizung::rs485::RS485;
use heizung::uf2updater::UF2UpdateHandler;
use heizung::watchdog::WatchdogFixed;
use heizung::ws2812::Ws2812;
macro_rules! singleton {
($val:expr) => {{
......@@ -66,7 +69,7 @@ async fn i2c_task(mut i2c_peri: embassy_rp::peripherals::I2C0,
}
#[embassy_executor::task]
async fn beeper_task(pwm_channel: embassy_rp::peripherals::PWM_CH3, beeper_pin: embassy_rp::peripherals::PIN_6) {
async fn beeper_task(pwm_channel: embassy_rp::peripherals::PWM_CH3, beeper_pin: embassy_rp::peripherals::PIN_6, short: bool) {
let mut c: pwm::Config = Default::default();
c.top = 0x8000;
c.compare_a = 8;
......@@ -84,6 +87,9 @@ async fn beeper_task(pwm_channel: embassy_rp::peripherals::PWM_CH3, beeper_pin:
if c.divider < 1 {
c.divider = fixed::FixedU16::from_num(20);
}
if short && c.divider < 17 {
break;
}
toggle = true;
pwm.set_config(&c);
}
......@@ -323,6 +329,55 @@ async fn reset_soon(delay: Duration) {
cortex_m::peripheral::SCB::sys_reset();
}
/// Input a value 0 to 255 to get a color value
/// The colours are a transition r - g - b - back to r.
fn wheel(mut wheel_pos: u8) -> RGB8 {
//return (0, 255, 0).into();
wheel_pos = 255 - wheel_pos;
if wheel_pos < 85 {
return (255 - wheel_pos * 3, 0, wheel_pos * 3).into();
}
if wheel_pos < 170 {
wheel_pos -= 85;
return (0, wheel_pos * 3, 255 - wheel_pos * 3).into();
}
wheel_pos -= 170;
(wheel_pos * 3, 255 - wheel_pos * 3, 0).into()
}
#[embassy_executor::task]
async fn ws2812_task(pio: PIO1, pin: PIN_2, dma: DMA_CH3) {
if false {
let mut ws2812_display = Output::new(unsafe { pin.clone_unchecked() }, Level::Low);
for _ in 1..10 {
ws2812_display.toggle();
Timer::after(Duration::from_secs(1)).await;
}
drop(ws2812_display);
}
let Pio { common, sm0, .. } = Pio::new(pio);
const NUM_LEDS: usize = 60;
let mut data = [RGB8::default(); NUM_LEDS];
let mut ws2812: Ws2812<'_, _, _, 0, NUM_LEDS> = Ws2812::new(common, sm0, pin, dma);
// Loop forever making RGB values and pushing them out to the WS2812.
loop {
for j in 0..(256 * 5) {
//debug!("New Colors:");
for i in 0..NUM_LEDS {
data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8);
//debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b);
}
ws2812.write(&data).await;
Timer::after(Duration::from_micros(5)).await;
}
}
}
const FLASH_SIZE: usize = 2 * 1024 * 1024;
......@@ -617,7 +672,7 @@ async fn main2(spawner: Spawner) {
let mut _drive2 = Output::new(p.PIN_0, Level::Low);
let mut _drive1 = Output::new(p.PIN_1, Level::Low);
//let LED_W = p.PIN_2;
let _ws2812_display = p.PIN_2;
let ws2812_display = p.PIN_2;
//let LED_Y = p.PIN_3;
let en_measure_current = Output::new(p.PIN_3, Level::Low);
let mut led_b = Output::new(p.PIN_4, Level::Low);
......@@ -679,12 +734,14 @@ async fn main2(spawner: Spawner) {
);
unwrap!(spawner.spawn(uart_task(rs485)));
if false {
unwrap!(spawner.spawn(beeper_task(p.PWM_CH3, led_r)));
if true {
unwrap!(spawner.spawn(beeper_task(p.PWM_CH3, led_r, true)));
}
unwrap!(spawner.spawn(dogfeeder(p.WATCHDOG)));
unwrap!(spawner.spawn(ws2812_task(p.PIO1, ws2812_display, p.DMA_CH3)));
loop {
led_b.set_high();
Timer::after(Duration::from_secs(1)).await;
......
......@@ -11,6 +11,10 @@ use embassy_time::{Duration, Timer};
use fixed_macro::fixed;
use smart_leds::RGB8;
use {defmt_rtt as _, panic_probe as _};
use embassy_rp::peripherals;
use heizung::watchdog::WatchdogFixed;
pub struct Ws2812<'d, P: Instance, const S: usize> {
sm: StateMachine<'d, P, S>,
}
......@@ -69,6 +73,7 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> {
};
sm.set_config(&cfg);
sm.set_pin_dirs(embassy_rp::pio::Direction::Out, &[&out_pin]);
sm.set_enable(true);
Self { sm }
......@@ -97,21 +102,28 @@ fn wheel(mut wheel_pos: u8) -> RGB8 {
(wheel_pos * 3, 255 - wheel_pos * 3, 0).into()
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
#[embassy_executor::task]
async fn dogfeeder(watchdog: peripherals::WATCHDOG) {
WatchdogFixed::new(watchdog).start_and_feed_continuously().await;
}
//#[embassy_executor::main]
async fn main2(spawner: Spawner) {
info!("Start");
let p = embassy_rp::init(Default::default());
unwrap!(spawner.spawn(dogfeeder(p.WATCHDOG)));
let Pio { common, sm0, .. } = Pio::new(p.PIO0);
// This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
// feather boards for the 2040 both have one built in.
const NUM_LEDS: usize = 1;
const NUM_LEDS: usize = 60;
let mut data = [RGB8::default(); NUM_LEDS];
// For the thing plus, use pin 8
// For the feather, use pin 16
let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8);
let mut ws2812 = Ws2812::new(common, sm0, p.PIN_2);
// Loop forever making RGB values and pushing them out to the WS2812.
loop {
......@@ -127,3 +139,29 @@ async fn main(_spawner: Spawner) {
}
}
}
#[::embassy_executor::task()]
async fn __embassy_main(spawner: Spawner) {
main2(spawner).await;
}
unsafe fn __make_static<T>(t: &mut T) -> &'static mut T {
::core::mem::transmute(t)
}
#[cortex_m_rt::entry]
fn main() -> ! {
init_early();
let mut executor = ::embassy_executor::Executor::new();
let executor = unsafe { __make_static(&mut executor) };
executor.run(|spawner| {
spawner.must_spawn(__embassy_main(spawner));
})
}
fn init_early() {
use embassy_rp::pac;
// release spinlock 31 because we sometimes block on this in the init code
unsafe { pac::SIO.spinlock(31).write_value(1); }
}
\ No newline at end of file
......@@ -8,4 +8,5 @@ pub mod clear_bootloader_state;
pub mod uf2;
pub mod uf2updater;
pub mod watchdog;
pub mod ws2812;
pub mod program_info;
use core::cmp::min;
use embassy_hal_common::PeripheralRef;
use embassy_embedded_hal::SetConfig;
use embassy_rp::gpio::Level;
use embassy_rp::pio::{Common, Config, FifoJoin, Instance, PioPin, ShiftConfig, ShiftDirection, StateMachine};
use embassy_rp::dma::{Channel};
use embassy_rp::relocate::RelocatedProgram;
use fixed_macro::fixed;
use smart_leds::RGB8;
pub struct Ws2812<'d, P: Instance, D: Channel, const S: usize, const LEDS: usize> {
sm: StateMachine<'d, P, S>,
dma: PeripheralRef<'d, D>,
leds: [u32; LEDS],
}
impl<'d, P: Instance, D: Channel, const S: usize, const LEDS: usize> Ws2812<'d, P, D, S, LEDS> {
pub fn new(mut pio: Common<'d, P>, mut sm: StateMachine<'d, P, S>, pin: impl PioPin, dma: D) -> Self {
// Setup sm0
// prepare the PIO program
let side_set = pio::SideSet::new(false, 1, false);
let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set);
const T1: u8 = 2; // start bit
const T2: u8 = 5; // data bit
const T3: u8 = 3; // stop bit
const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32;
let mut wrap_target = a.label();
let mut wrap_source = a.label();
let mut do_zero = a.label();
a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0);
a.bind(&mut wrap_target);
// Do stop bit
a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0);
// Do start bit
a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1);
// Do data bit = 1
a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1);
a.bind(&mut do_zero);
// Do data bit = 0
a.nop_with_delay_and_side_set(T2 - 1, 0);
a.bind(&mut wrap_source);
let prg = a.assemble_with_wrap(wrap_source, wrap_target);
let mut cfg = Config::default();
// Pin config
let out_pin = pio.make_pio_pin(pin);
let relocated = RelocatedProgram::new(&prg);
cfg.use_program(&pio.load_program(&relocated), &[&out_pin]);
// Clock config, measured in kHz to avoid overflows
// TODO CLOCK_FREQ should come from embassy_rp
let clock_freq = fixed!(125_000: U24F8);
let ws2812_freq = fixed!(800: U24F8);
let bit_freq = ws2812_freq * CYCLES_PER_BIT;
cfg.clock_divider = clock_freq / bit_freq;
// FIFO config
cfg.fifo_join = FifoJoin::TxOnly;
cfg.shift_out = ShiftConfig {
auto_fill: true,
threshold: 24,
direction: ShiftDirection::Left,
};
sm.set_config(&cfg);
sm.set_pin_dirs(embassy_rp::pio::Direction::Out, &[&out_pin]);
sm.set_pins(Level::Low, &[&out_pin]);
sm.set_enable(true);
let dma = dma.into_ref();
let leds = [0u32; LEDS];
Self { sm, dma, leds }
}
pub async fn write(&mut self, colors: &[RGB8]) {
if false {
for color in colors {
let word = (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8);
self.sm.tx().wait_push(word).await;
}
} else {
for (i, color) in colors.iter().enumerate() {
if i < LEDS {
self.leds[i] = (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8);
}
}
self.sm.tx().dma_push(self.dma.reborrow(),
&self.leds[0..min(LEDS, colors.len())]).await;
}
}
}
......@@ -18,3 +18,5 @@ lib_deps =
sparkfun/SparkFun TMP102 Breakout@^1.1.2
adafruit/Adafruit MPR121@^1.1.1
adafruit/Adafruit NeoPixel@^1.11.0
#upload_protocol = picoprobe
......@@ -169,6 +169,7 @@
rust = with flakePkgs; pkgs.mkShell rec {
passthru.packages = with pkgs; [
rustup udev.dev pkg-config openssl.dev picotool
(pkgs.probe-rs-tools or pkgs.probe-rs)
];
passthru.pythonPackages = p: with p; [ pymodbus3 pyserial modbus-tk ];
passthru.python = python3.withPackages passthru.pythonPackages;
......