Sfoglia il codice sorgente

display: Restructure the program (with multiple software tasks).

Mathias Gottschlag 5 anni fa
parent
commit
0d48079851

+ 106
- 0
display/firmware/src/display.rs Vedi File

@@ -0,0 +1,106 @@
1
+use embedded_hal::blocking::delay::DelayUs;
2
+use embedded_hal::digital::v2::OutputPin;
3
+use epd_waveshare::{epd4in2::*, prelude::*};
4
+use mkl25z4_hal::time::CopyableMonoTimer;
5
+
6
+use super::information::Information;
7
+use super::pins::{
8
+    DisplayBmeSpi, DisplayBusy, DisplayCs, DisplayDc, DisplayPins, DisplayPwr, DisplayRst,
9
+};
10
+
11
+pub struct DisplayState {
12
+    // TODO
13
+}
14
+
15
+pub struct Display {
16
+    pwr: DisplayPwr,
17
+    epd: EPD4in2<DisplayBmeSpi, DisplayCs, DisplayBusy, DisplayDc, DisplayRst>,
18
+}
19
+
20
+impl Display {
21
+    pub fn init(
22
+        mut pins: DisplayPins,
23
+        spi: &mut DisplayBmeSpi,
24
+        mut time: CopyableMonoTimer,
25
+    ) -> Display {
26
+        // Enable power.
27
+        pins.display_pwr.set_low().ok();
28
+        // Wait a bit for power to stabilize.
29
+        time.delay_us(100u8);
30
+
31
+        let epd = EPD4in2::new(
32
+            spi,
33
+            pins.display_cs,
34
+            pins.display_busy,
35
+            pins.display_dc,
36
+            pins.display_rst,
37
+            &mut time,
38
+        )
39
+        .unwrap(); // TODO: Error handling?
40
+
41
+        // Disable power again.
42
+        pins.display_pwr.set_low().ok();
43
+
44
+        Display {
45
+            pwr: pins.display_pwr,
46
+            epd,
47
+        }
48
+    }
49
+
50
+    pub fn update(
51
+        &mut self,
52
+        _display_state: &DisplayState,
53
+        _info: &Information,
54
+        spi: &mut DisplayBmeSpi,
55
+        mut time: CopyableMonoTimer,
56
+    ) {
57
+        // Enable power.
58
+        self.pwr.set_low().ok();
59
+        // Wait a bit for power to stabilize.
60
+        time.delay_us(100u8);
61
+
62
+        // TODO: Error handling.
63
+        self.epd.wake_up(spi, &mut time).ok();
64
+
65
+        // TODO: Draw the display contents.
66
+        self.epd.set_background_color(Color::Black);
67
+        let checkerboard = Checkerboard::new(400, 300, true);
68
+        self.epd.update_frame_stream(spi, checkerboard).unwrap();
69
+        self.epd.display_frame(spi).unwrap();
70
+
71
+        // Disable power again.
72
+        self.pwr.set_high().ok();
73
+    }
74
+}
75
+
76
+struct Checkerboard {
77
+    width: usize,
78
+    height: usize,
79
+    index: usize,
80
+    buffer: [u8; 1],
81
+}
82
+
83
+impl Checkerboard {
84
+    fn new(width: usize, height: usize, start_black: bool) -> Self {
85
+        Self {
86
+            width: width / 8,
87
+            height,
88
+            index: 0,
89
+            buffer: [if start_black { 0x55 } else { 0xaa }],
90
+        }
91
+    }
92
+}
93
+
94
+impl DisplayStream for Checkerboard {
95
+    fn next<'a>(&'a mut self) -> Option<&'a [u8]> {
96
+        if self.index != self.width * self.height {
97
+            self.index += 1;
98
+            if (self.index - 1) % self.width == 0 {
99
+                self.buffer[0] = !self.buffer[0];
100
+            }
101
+            Some(&self.buffer)
102
+        } else {
103
+            None
104
+        }
105
+    }
106
+}

+ 7
- 0
display/firmware/src/information.rs Vedi File

@@ -0,0 +1,7 @@
1
+//! Sensor information or information fetched from the internet.
2
+
3
+pub struct Information {
4
+    pub time: u32,
5
+    pub valid: bool,
6
+    // TODO
7
+}

+ 86
- 89
display/firmware/src/main.rs Vedi File

@@ -1,54 +1,37 @@
1 1
 #![no_main]
2 2
 #![no_std]
3 3
 
4
+mod display;
5
+mod information;
4 6
 mod pins;
7
+
8
+// TODO: Enable warnings again.
9
+#[allow(unused)]
5 10
 mod assets {
6 11
     include!(concat!(env!("OUT_DIR"), "/assets.rs"));
7 12
 }
8 13
 
9
-use cortex_m_semihosting::{debug, hprintln};
10 14
 use embedded_epd as epd;
11
-use embedded_epd::{gui, Display};
12
-use embedded_hal::blocking::delay::DelayMs;
13
-use embedded_hal::digital::v2::OutputPin;
14
-use embedded_hal::timer::CountDown;
15
-use epd_waveshare::{epd4in2::*, prelude::*};
16
-use mkl25z4_hal as hal;
17 15
 use mkl25z4_hal::clocks::ClockConfiguration;
18
-use mkl25z4_hal::time::NonCopyableMonoTimer;
19
-use mkl25z4_hal::time::U32Ext;
20
-use mkl25z4_hal::timer::Timer;
21
-use nb::block;
16
+use mkl25z4_hal::time::{CopyableMonoTimer, NonCopyableMonoTimer, U32Ext};
22 17
 use panic_semihosting as _;
23 18
 
24
-struct EPDTimer<Timer> {
25
-    timer: Timer,
26
-}
27
-
28
-impl<Timer> CountDown for EPDTimer<Timer>
29
-where
30
-    Timer: CountDown<Time = hal::time::Hertz>,
31
-{
32
-    type Time = epd::Hertz;
33
-
34
-    fn start<T>(&mut self, timeout: T)
35
-    where
36
-        T: Into<epd::Hertz>,
37
-    {
38
-        self.timer.start(hal::time::Hertz(timeout.into().0))
39
-    }
40
-
41
-    fn wait(&mut self) -> nb::Result<(), void::Void> {
42
-        self.timer.wait()
43
-    }
44
-}
19
+use display::{Display, DisplayState};
20
+use information::Information;
21
+use pins::DisplayBmeSpi;
45 22
 
46 23
 #[rtfm::app(device = mkl25z4_hal::mkl25z4, peripherals = true)]
47 24
 const APP: () = {
48
-    struct Resources {}
25
+    struct Resources {
26
+        info: Information,
27
+        display_state: DisplayState,
28
+        display: Display,
29
+        display_bme_spi: Option<DisplayBmeSpi>,
30
+        time: CopyableMonoTimer,
31
+    }
49 32
 
50
-    #[init]
51
-    fn init(ctx: init::Context) {
33
+    #[init(spawn = [fetch_update])]
34
+    fn init(ctx: init::Context) -> init::LateResources {
52 35
         let mut sim = ctx.device.SIM;
53 36
         mkl25z4_hal::watchdog::disable(&mut sim);
54 37
         let clocks = ClockConfiguration::new()
@@ -69,29 +52,70 @@ const APP: () = {
69 52
             ctx.device.SPI1,
70 53
         );
71 54
 
72
-        // Enable power.
73
-        pins.display_pwr.set_low().ok();
74
-        pins.display_rst.set_high().unwrap();
75
-        pins.display_dc.set_high().unwrap();
76
-        pins.display_cs.set_high().unwrap();
77
-
78
-        let mut timer = NonCopyableMonoTimer::new(ctx.device.PIT, clocks, &mut sim);
79
-
80
-        let mut epd = EPD4in2::new(
81
-            &mut pins.display_bme_spi,
82
-            pins.display_cs,
83
-            pins.display_busy,
84
-            pins.display_dc,
85
-            pins.display_rst,
86
-            &mut timer,
87
-        )
88
-        .unwrap();
89
-
90
-        epd.set_background_color(Color::Black);
91
-        let checkerboard = Checkerboard::new(400, 300, true);
92
-        epd.update_frame_stream(&mut pins.display_bme_spi, checkerboard)
93
-            .unwrap();
94
-        epd.display_frame(&mut pins.display_bme_spi).unwrap();
55
+        let time =
56
+            CopyableMonoTimer::new(NonCopyableMonoTimer::new(ctx.device.PIT, clocks, &mut sim));
57
+
58
+        let display = Display::init(pins.display, &mut pins.display_bme_spi, time);
59
+
60
+        // Fetch the first update.
61
+        ctx.spawn.fetch_update().ok();
62
+
63
+        init::LateResources {
64
+            info: Information {
65
+                time: 0,
66
+                valid: false,
67
+            },
68
+            display_state: DisplayState{
69
+                // TODO
70
+            },
71
+            display,
72
+            display_bme_spi: Some(pins.display_bme_spi),
73
+            time,
74
+        }
75
+    }
76
+
77
+    #[task(binds = LPTMR0, priority = 3, spawn = [fetch_update])]
78
+    fn lptmr0_interrupt(ctx: lptmr0_interrupt::Context) {
79
+        // Restart the timer.
80
+        // TODO
81
+
82
+        // Trigger an update of the displayed values.
83
+        ctx.spawn.fetch_update().ok();
84
+    }
85
+
86
+    #[task(binds = LLWU, priority = 3)]
87
+    fn llwu_interrupt(_: llwu_interrupt::Context) {
88
+        // TODO
89
+    }
90
+
91
+    #[task(priority = 1, spawn = [update_display], resources = [info])]
92
+    fn fetch_update(ctx: fetch_update::Context) {
93
+        // Fetch local updates.
94
+        // TODO
95
+
96
+        // Send local measurements to the base station. This needs to be done before fetching data
97
+        // from the base station as the base station might return the data to us.
98
+        // TODO
99
+
100
+        // Fetch updates via radio.
101
+        // TODO
102
+
103
+        // If the update failed, simply increment the time and place a hint that
104
+        // the information might be invalid.
105
+        // TODO
106
+
107
+        // Update the display to show the new values.
108
+        ctx.spawn.update_display().ok();
109
+    }
110
+
111
+    #[task(priority = 2, resources = [info, display_state, display, display_bme_spi, &time])]
112
+    fn update_display(ctx: update_display::Context) {
113
+        ctx.resources.display.update(
114
+            &ctx.resources.display_state,
115
+            &ctx.resources.info,
116
+            ctx.resources.display_bme_spi.as_mut().unwrap(),
117
+            ctx.resources.time.clone(),
118
+        );
95 119
     }
96 120
 
97 121
     #[idle]
@@ -105,36 +129,9 @@ const APP: () = {
105 129
             cortex_m::asm::wfi();
106 130
         }
107 131
     }
108
-};
109
-
110
-struct Checkerboard {
111
-    width: usize,
112
-    height: usize,
113
-    index: usize,
114
-    buffer: [u8; 1],
115
-}
116
-
117
-impl Checkerboard {
118
-    fn new(width: usize, height: usize, start_black: bool) -> Self {
119
-        Self {
120
-            width: width / 8,
121
-            height,
122
-            index: 0,
123
-            buffer: [if start_black { 0x55 } else { 0xaa }],
124
-        }
125
-    }
126
-}
127 132
 
128
-impl DisplayStream for Checkerboard {
129
-    fn next<'a>(&'a mut self) -> Option<&'a [u8]> {
130
-        if self.index != self.width * self.height {
131
-            self.index += 1;
132
-            if (self.index - 1) % self.width == 0 {
133
-                self.buffer[0] = !self.buffer[0];
134
-            }
135
-            Some(&self.buffer)
136
-        } else {
137
-            None
138
-        }
133
+    extern "C" {
134
+        fn I2C0();
135
+        fn I2C1();
139 136
     }
140
-}
137
+};

+ 38
- 23
display/firmware/src/pins.rs Vedi File

@@ -5,6 +5,32 @@ use mkl25z4_hal::gpio::{self, gpioa, gpiob, gpioc, gpiod, gpioe, GpioExt};
5 5
 use mkl25z4_hal::spi::{self, Phase, Polarity, Spi};
6 6
 use mkl25z4_hal::time::U32Ext;
7 7
 
8
+pub type DisplayBusy = gpioc::PC4<gpio::Input<gpio::PullUp>>;
9
+pub type DisplayCs = gpioc::PC8<gpio::Output<gpio::PushPull>>;
10
+pub type DisplayDc = gpioc::PC9<gpio::Output<gpio::PushPull>>;
11
+pub type DisplayRst = gpioc::PC10<gpio::Output<gpio::PushPull>>;
12
+pub type DisplayPwr = gpioc::PC11<gpio::Output<gpio::PushPull>>;
13
+
14
+pub struct DisplayPins {
15
+    /// Display busy (active low).
16
+    pub display_busy: gpioc::PC4<gpio::Input<gpio::PullUp>>,
17
+    /// Display chip select (active low).
18
+    pub display_cs: gpioc::PC8<gpio::Output<gpio::PushPull>>,
19
+    /// Display data/command.
20
+    pub display_dc: gpioc::PC9<gpio::Output<gpio::PushPull>>,
21
+    /// Display reset (active low).
22
+    pub display_rst: gpioc::PC10<gpio::Output<gpio::PushPull>>,
23
+    /// Display supply voltage enable (active low).
24
+    pub display_pwr: gpioc::PC11<gpio::Output<gpio::PushPull>>,
25
+}
26
+
27
+pub type DisplayBmeSpi = Spi<
28
+    SPI0,
29
+    gpioc::PC7<gpio::Alternate5>,
30
+    gpioc::PC6<gpio::Alternate5>,
31
+    gpioc::PC5<gpio::Alternate2>,
32
+>;
33
+
8 34
 pub struct Pins {
9 35
     /// 5V supply for the LED (active high).
10 36
     pub enable_5v: gpioa::PA1<gpio::Output<gpio::PushPull>>,
@@ -61,24 +87,10 @@ pub struct Pins {
61 87
     /// BME280 chip select (active low).
62 88
     pub bme_cs: gpioc::PC2<gpio::Output<gpio::PushPull>>,
63 89
 
64
-    /// Display busy (active low).
65
-    pub display_busy: gpioc::PC4<gpio::Input<gpio::PullUp>>,
66
-    /// Display chip select (active low).
67
-    pub display_cs: gpioc::PC8<gpio::Output<gpio::PushPull>>,
68
-    /// Display data/command.
69
-    pub display_dc: gpioc::PC9<gpio::Output<gpio::PushPull>>,
70
-    /// Display reset (active low).
71
-    pub display_rst: gpioc::PC10<gpio::Output<gpio::PushPull>>,
72
-    /// Display supply voltage enable (active low).
73
-    pub display_pwr: gpioc::PC11<gpio::Output<gpio::PushPull>>,
90
+    pub display: DisplayPins,
74 91
 
75 92
     /// SPI for both display and BME280.
76
-    pub display_bme_spi: Spi<
77
-        SPI0,
78
-        gpioc::PC7<gpio::Alternate5>,
79
-        gpioc::PC6<gpio::Alternate5>,
80
-        gpioc::PC5<gpio::Alternate2>,
81
-    >,
93
+    pub display_bme_spi: DisplayBmeSpi,
82 94
 }
83 95
 
84 96
 impl Pins {
@@ -146,11 +158,14 @@ impl Pins {
146 158
             nrf_pwr: gpiob.pb3.into_push_pull_output(&mut gpiob.pddr),
147 159
             nrf_spi: spi1,
148 160
             bme_cs: gpioc.pc2.into_push_pull_output(&mut gpioc.pddr),
149
-            display_busy: gpioc.pc4.into_pull_up_input(&mut gpioc.pddr),
150
-            display_cs: gpioc.pc8.into_push_pull_output(&mut gpioc.pddr),
151
-            display_dc: gpioc.pc9.into_push_pull_output(&mut gpioc.pddr),
152
-            display_rst: gpioc.pc10.into_push_pull_output(&mut gpioc.pddr),
153
-            display_pwr: gpioc.pc11.into_push_pull_output(&mut gpioc.pddr),
161
+
162
+            display: DisplayPins {
163
+                display_busy: gpioc.pc4.into_pull_up_input(&mut gpioc.pddr),
164
+                display_cs: gpioc.pc8.into_push_pull_output(&mut gpioc.pddr),
165
+                display_dc: gpioc.pc9.into_push_pull_output(&mut gpioc.pddr),
166
+                display_rst: gpioc.pc10.into_push_pull_output(&mut gpioc.pddr),
167
+                display_pwr: gpioc.pc11.into_push_pull_output(&mut gpioc.pddr),
168
+            },
154 169
 
155 170
             display_bme_spi: spi0,
156 171
         };
@@ -162,8 +177,8 @@ impl Pins {
162 177
         pins.nrf_cs.set_high().ok();
163 178
         pins.nrf_pwr.set_high().ok();
164 179
         pins.bme_cs.set_high().ok();
165
-        pins.display_cs.set_high().ok();
166
-        pins.display_pwr.set_high().ok();
180
+        pins.display.display_cs.set_high().ok();
181
+        pins.display.display_pwr.set_high().ok();
167 182
 
168 183
         pins
169 184
     }

Loading…
Annulla
Salva