Skip to main content

oxstack_cardputer/
board.rs

1use esp_hal::peripherals::*;
2
3/// Every peripheral of the chip, grouped by what the Cardputer ADV wires it
4/// to. Create it with [`crate::init`] or [`Board::new`].
5///
6/// Each group's `init` borrows the group, so take the board as `mut` and
7/// keep it for the life of the program; drivers are created from it and
8/// dropped as apps come and go.
9#[non_exhaustive]
10pub struct Board {
11    /// ST7789V2 LCD (SPI3 + DMA channel 0).
12    pub display: crate::display::DisplayResources<'static>,
13    /// LCD backlight, which also powers the RGB LED.
14    pub backlight: crate::backlight::BacklightResources<'static>,
15    /// Internal I²C bus (keyboard, codec, IMU).
16    pub sys_i2c: crate::i2c::SysI2cResources<'static>,
17    /// Keyboard scanner interrupt line (the scanner itself is on `sys_i2c`).
18    pub keyboard: crate::keyboard::KeyboardResources<'static>,
19    /// ES8311 codec I²S link.
20    pub audio: crate::audio::AudioResources<'static>,
21    /// SPI bus shared by microSD and the EXT header.
22    pub spi_bus: SpiBusResources<'static>,
23    /// EXT header control and UART lines.
24    pub ext: ExtResources<'static>,
25    /// RMT pulse generator with the RGB LED and IR LED it drives.
26    pub rmt: crate::rmt::RmtResources<'static>,
27    /// Battery voltage sense.
28    pub battery: crate::battery::BatteryResources<'static>,
29    /// BMI270 IMU (on `sys_i2c`).
30    pub imu: crate::imu::ImuResources,
31    /// G0 button (active low). Read it with
32    /// `Input::new(board.button.reborrow(), InputConfig::default().with_pull(Pull::Up))`.
33    pub button: GPIO0<'static>,
34    /// Grove port.
35    pub grove: GroveResources<'static>,
36    /// Spare line on the internal FPC connector.
37    pub fpc_io1: GPIO7<'static>,
38    /// Wi-Fi and Bluetooth radio.
39    pub radio: crate::radio::RadioResources<'static>,
40    /// Peripherals not tied to a board function.
41    pub system: SystemResources<'static>,
42    /// GPIOs and UART0 that the board leaves unrouted.
43    pub spare: SpareResources<'static>,
44    /// Register-block peripherals for low-level or `unsafe` work.
45    pub raw: RawResources<'static>,
46}
47
48/// Pins the Cardputer ADV schematic does not route to any connector, plus
49/// UART0. Kept rather than dropped so nothing is lost for good.
50#[allow(missing_docs)]
51pub struct SpareResources<'d> {
52    pub gpio16: GPIO16<'d>,
53    pub gpio17: GPIO17<'d>,
54    pub gpio18: GPIO18<'d>,
55    pub gpio45: GPIO45<'d>,
56    pub gpio47: GPIO47<'d>,
57    pub gpio48: GPIO48<'d>,
58    /// **Don't use on its default pins** (GPIO43/44 are taken here); see
59    /// [`crate::pins`].
60    pub uart0: UART0<'d>,
61}
62reborrow_group!(SpareResources {
63    gpio16,
64    gpio17,
65    gpio18,
66    gpio45,
67    gpio47,
68    gpio48,
69    uart0
70});
71
72/// Peripherals that are mostly register blocks, for low-level code.
73#[allow(missing_docs)]
74pub struct RawResources<'d> {
75    pub apb_ctrl: APB_CTRL<'d>,
76    pub assist_debug: ASSIST_DEBUG<'d>,
77    pub dma: DMA<'d>,
78    pub extmem: EXTMEM<'d>,
79    pub gpio: GPIO<'d>,
80    pub i2c_ana_mst: I2C_ANA_MST<'d>,
81    pub interrupt_core0: INTERRUPT_CORE0<'d>,
82    pub interrupt_core1: INTERRUPT_CORE1<'d>,
83    pub rtc_timer: RTC_TIMER<'d>,
84    pub peri_backup: PERI_BACKUP<'d>,
85    pub rtc_cntl: RTC_CNTL<'d>,
86    pub sens: SENS<'d>,
87    pub sensitive: SENSITIVE<'d>,
88    pub system: SYSTEM<'d>,
89    pub wcl: WCL<'d>,
90}
91reborrow_group!(RawResources {
92    apb_ctrl,
93    assist_debug,
94    dma,
95    extmem,
96    gpio,
97    i2c_ana_mst,
98    interrupt_core0,
99    interrupt_core1,
100    rtc_timer,
101    peri_backup,
102    rtc_cntl,
103    sens,
104    sensitive,
105    system,
106    wcl
107});
108
109/// The shared SPI bus and both of its chip selects. [`sd`](Self::sd) is in
110/// [`crate::sd`].
111#[allow(missing_docs)]
112pub struct SpiBusResources<'d> {
113    pub spi: SPI2<'d>,
114    pub dma: DMA_CH2<'d>,
115    pub sck: GPIO40<'d>,
116    pub mosi: GPIO14<'d>,
117    pub miso: GPIO39<'d>,
118    pub sd_cs: GPIO12<'d>,
119    pub ext_cs: GPIO5<'d>,
120}
121reborrow_group!(SpiBusResources {
122    spi,
123    dma,
124    sck,
125    mosi,
126    miso,
127    sd_cs,
128    ext_cs
129});
130
131/// EXT header lines other than SPI and I²C.
132#[allow(missing_docs)]
133pub struct ExtResources<'d> {
134    pub reset: GPIO3<'d>,
135    pub int: GPIO4<'d>,
136    pub busy: GPIO6<'d>,
137    pub uart: UART1<'d>,
138    pub uart_tx: GPIO13<'d>,
139    pub uart_rx: GPIO15<'d>,
140}
141reborrow_group!(ExtResources {
142    reset,
143    int,
144    busy,
145    uart,
146    uart_tx,
147    uart_rx
148});
149
150/// Grove port signal lines.
151#[allow(missing_docs)]
152pub struct GroveResources<'d> {
153    pub g1: GPIO1<'d>,
154    pub g2: GPIO2<'d>,
155}
156reborrow_group!(GroveResources { g1, g2 });
157
158/// Chip peripherals with no fixed board role.
159#[allow(missing_docs)]
160pub struct SystemResources<'d> {
161    pub timg1: TIMG1<'d>,
162    pub systimer: SYSTIMER<'d>,
163    pub i2c1: I2C1<'d>,
164    pub i2s1: I2S1<'d>,
165    pub uart2: UART2<'d>,
166    pub adc2: ADC2<'d>,
167    pub dma_ch3: DMA_CH3<'d>,
168    pub dma_ch4: DMA_CH4<'d>,
169    pub rng: RNG<'d>,
170    pub usb_device: USB_DEVICE<'d>,
171    pub lpwr: LPWR<'d>,
172    pub cpu_ctrl: CPU_CTRL<'d>,
173    pub sw_int1: FROM_CPU_INTR1<'d>,
174    pub sw_int2: FROM_CPU_INTR2<'d>,
175    pub sw_int3: FROM_CPU_INTR3<'d>,
176    pub pcnt: PCNT<'d>,
177    pub mcpwm0: MCPWM0<'d>,
178    pub mcpwm1: MCPWM1<'d>,
179    pub sha: SHA<'d>,
180    pub aes: AES<'d>,
181    pub rsa: RSA<'d>,
182    pub hmac: HMAC<'d>,
183    pub sdhost: SDHOST<'d>,
184    pub twai: TWAI0<'d>,
185    pub usb_otg: USB_FS<'d>,
186    pub lcd_cam: LCD_CAM<'d>,
187    pub flash: FLASH<'d>,
188    pub io_mux: IO_MUX<'d>,
189    pub rtc_io: RTC_IO<'d>,
190    pub ulp_riscv_core: ULP_RISCV_CORE<'d>,
191    pub lp_i2c0: LP_I2C0<'d>,
192    pub gpio_dedicated: GPIO_DEDICATED<'d>,
193    pub apb_saradc: APB_SARADC<'d>,
194    pub uhci0: UHCI0<'d>,
195    pub ds: DS<'d>,
196    pub xts_aes: XTS_AES<'d>,
197    pub gpio_sd: GPIO_SD<'d>,
198    pub sdm_ch0: SDM_CH0<'d>,
199    pub sdm_ch1: SDM_CH1<'d>,
200    pub sdm_ch2: SDM_CH2<'d>,
201    pub sdm_ch3: SDM_CH3<'d>,
202    pub sdm_ch4: SDM_CH4<'d>,
203    pub sdm_ch5: SDM_CH5<'d>,
204    pub sdm_ch6: SDM_CH6<'d>,
205    pub sdm_ch7: SDM_CH7<'d>,
206}
207reborrow_group!(SystemResources {
208    timg1,
209    systimer,
210    i2c1,
211    i2s1,
212    uart2,
213    adc2,
214    dma_ch3,
215    dma_ch4,
216    rng,
217    usb_device,
218    lpwr,
219    cpu_ctrl,
220    sw_int1,
221    sw_int2,
222    sw_int3,
223    pcnt,
224    mcpwm0,
225    mcpwm1,
226    sha,
227    aes,
228    rsa,
229    hmac,
230    sdhost,
231    twai,
232    usb_otg,
233    lcd_cam,
234    flash,
235    io_mux,
236    rtc_io,
237    ulp_riscv_core,
238    lp_i2c0,
239    gpio_dedicated,
240    apb_saradc,
241    uhci0,
242    ds,
243    xts_aes,
244    gpio_sd,
245    sdm_ch0,
246    sdm_ch1,
247    sdm_ch2,
248    sdm_ch3,
249    sdm_ch4,
250    sdm_ch5,
251    sdm_ch6,
252    sdm_ch7
253});
254
255/// What the `esp-rtos` scheduler needs. [`crate::init`] consumes it.
256#[allow(missing_docs)]
257pub struct RtosResources {
258    pub timg0: TIMG0<'static>,
259    pub sw_int0: FROM_CPU_INTR0<'static>,
260}
261
262impl RtosResources {
263    /// Starts the `esp-rtos` scheduler on TIMG0 timer 0.
264    pub fn start(self) {
265        let timg0 = esp_hal::timer::timg::TimerGroup::new(self.timg0);
266        esp_rtos::start(timg0.timer0, self.sw_int0);
267    }
268}
269
270impl Board {
271    /// Splits `esp_hal::init`'s peripherals into board resource groups.
272    ///
273    /// `Peripherals` tokens can't be recovered once dropped (short of
274    /// `unsafe` stealing), so every peripheral is forwarded except exactly
275    /// three: `SPI0`/`SPI1`, which serve the flash cache (using them would
276    /// crash execution), and `PSRAM`, which the ESP32-S3FN8 does not have.
277    pub fn new(p: Peripherals) -> (Self, RtosResources) {
278        let board = Board {
279            display: crate::display::DisplayResources {
280                spi: p.SPI3,
281                dma: p.DMA_CH0,
282                sck: p.GPIO36,
283                mosi: p.GPIO35,
284                cs: p.GPIO37,
285                dc: p.GPIO34,
286                rst: p.GPIO33,
287            },
288            backlight: crate::backlight::BacklightResources {
289                ledc: p.LEDC,
290                pin: p.GPIO38,
291            },
292            sys_i2c: crate::i2c::SysI2cResources {
293                i2c: p.I2C0,
294                sda: p.GPIO8,
295                scl: p.GPIO9,
296            },
297            keyboard: crate::keyboard::KeyboardResources { int: p.GPIO11 },
298            audio: crate::audio::AudioResources {
299                i2s: p.I2S0,
300                dma: p.DMA_CH1,
301                bclk: p.GPIO41,
302                ws: p.GPIO43,
303                dout: p.GPIO42,
304                din: p.GPIO46,
305            },
306            spi_bus: SpiBusResources {
307                spi: p.SPI2,
308                dma: p.DMA_CH2,
309                sck: p.GPIO40,
310                mosi: p.GPIO14,
311                miso: p.GPIO39,
312                sd_cs: p.GPIO12,
313                ext_cs: p.GPIO5,
314            },
315            ext: ExtResources {
316                reset: p.GPIO3,
317                int: p.GPIO4,
318                busy: p.GPIO6,
319                uart: p.UART1,
320                uart_tx: p.GPIO13,
321                uart_rx: p.GPIO15,
322            },
323            rmt: crate::rmt::RmtResources {
324                rmt: p.RMT,
325                rgb_led: p.GPIO21,
326                ir_tx: p.GPIO44,
327            },
328            battery: crate::battery::BatteryResources {
329                adc: p.ADC1,
330                pin: p.GPIO10,
331            },
332            imu: crate::imu::ImuResources { _private: () },
333            button: p.GPIO0,
334            grove: GroveResources {
335                g1: p.GPIO1,
336                g2: p.GPIO2,
337            },
338            fpc_io1: p.GPIO7,
339            radio: crate::radio::RadioResources {
340                wifi: p.WIFI,
341                bt: p.BT,
342            },
343            system: SystemResources {
344                timg1: p.TIMG1,
345                systimer: p.SYSTIMER,
346                i2c1: p.I2C1,
347                i2s1: p.I2S1,
348                uart2: p.UART2,
349                adc2: p.ADC2,
350                dma_ch3: p.DMA_CH3,
351                dma_ch4: p.DMA_CH4,
352                rng: p.RNG,
353                usb_device: p.USB_DEVICE,
354                lpwr: p.LPWR,
355                cpu_ctrl: p.CPU_CTRL,
356                sw_int1: p.FROM_CPU_INTR1,
357                sw_int2: p.FROM_CPU_INTR2,
358                sw_int3: p.FROM_CPU_INTR3,
359                pcnt: p.PCNT,
360                mcpwm0: p.MCPWM0,
361                mcpwm1: p.MCPWM1,
362                sha: p.SHA,
363                aes: p.AES,
364                rsa: p.RSA,
365                hmac: p.HMAC,
366                sdhost: p.SDHOST,
367                twai: p.TWAI0,
368                usb_otg: p.USB_FS,
369                lcd_cam: p.LCD_CAM,
370                flash: p.FLASH,
371                io_mux: p.IO_MUX,
372                rtc_io: p.RTC_IO,
373                ulp_riscv_core: p.ULP_RISCV_CORE,
374                lp_i2c0: p.LP_I2C0,
375                gpio_dedicated: p.GPIO_DEDICATED,
376                apb_saradc: p.APB_SARADC,
377                uhci0: p.UHCI0,
378                ds: p.DS,
379                xts_aes: p.XTS_AES,
380                gpio_sd: p.GPIO_SD,
381                sdm_ch0: p.SDM_CH0,
382                sdm_ch1: p.SDM_CH1,
383                sdm_ch2: p.SDM_CH2,
384                sdm_ch3: p.SDM_CH3,
385                sdm_ch4: p.SDM_CH4,
386                sdm_ch5: p.SDM_CH5,
387                sdm_ch6: p.SDM_CH6,
388                sdm_ch7: p.SDM_CH7,
389            },
390            spare: SpareResources {
391                gpio16: p.GPIO16,
392                gpio17: p.GPIO17,
393                gpio18: p.GPIO18,
394                gpio45: p.GPIO45,
395                gpio47: p.GPIO47,
396                gpio48: p.GPIO48,
397                uart0: p.UART0,
398            },
399            raw: RawResources {
400                apb_ctrl: p.APB_CTRL,
401                assist_debug: p.ASSIST_DEBUG,
402                dma: p.DMA,
403                extmem: p.EXTMEM,
404                gpio: p.GPIO,
405                i2c_ana_mst: p.I2C_ANA_MST,
406                interrupt_core0: p.INTERRUPT_CORE0,
407                interrupt_core1: p.INTERRUPT_CORE1,
408                rtc_timer: p.RTC_TIMER,
409                peri_backup: p.PERI_BACKUP,
410                rtc_cntl: p.RTC_CNTL,
411                sens: p.SENS,
412                sensitive: p.SENSITIVE,
413                system: p.SYSTEM,
414                wcl: p.WCL,
415            },
416        };
417        (
418            board,
419            RtosResources {
420                timg0: p.TIMG0,
421                sw_int0: p.FROM_CPU_INTR0,
422            },
423        )
424    }
425}