Skip to content

Commit 56aea2a

Browse files
committed
pbio/drv/adc/adc_ev3: Replace with new stub driver
This stub driver uses pbio rather than Contiki, and it is ready to be integrated with the SPI flash driver (including waiting for the SPI bus to be available), but the actual logic for talking to the ADC chip has not been implemented yet.
1 parent 6b4a928 commit 56aea2a

File tree

4 files changed

+65
-112
lines changed

4 files changed

+65
-112
lines changed

lib/pbio/drv/adc/adc_ev3.c

Lines changed: 45 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99
#include <stdint.h>
1010
#include <string.h>
1111

12-
#include <contiki.h>
13-
1412
#include <pbdrv/adc.h>
1513
#include <pbdrv/clock.h>
1614
#include <pbdrv/gpio.h>
1715

1816
#include <pbio/error.h>
17+
#include <pbio/os.h>
1918
#include <pbio/util.h>
2019

2120
#include <tiam1808/spi.h>
@@ -25,15 +24,20 @@
2524
#include <tiam1808/hw/hw_syscfg0_AM1808.h>
2625
#include <tiam1808/armv5/am1808/interrupt.h>
2726

27+
#include "adc_ev3.h"
28+
#include "../drv/block_device/block_device_ev3.h"
2829
#include "../drv/gpio/gpio_ev3.h"
2930

30-
PROCESS(pbdrv_adc_process, "ADC");
31+
#include "../sys/storage.h"
32+
33+
#define PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES (2)
3134

32-
#define PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES (4)
35+
static volatile uint16_t channel_data[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES];
3336

34-
static volatile uint16_t channel_data[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES] = {0};
35-
static volatile uint8_t channel_data_index = 0;
36-
static volatile bool adc_busy = false;
37+
static int adc_soon;
38+
// Used to block ADC from interfering with flash upon shutdown
39+
static int shut_down_hack = 0;
40+
static int shut_down_hack_done = 0;
3741

3842
static pbdrv_adc_callback_t pbdrv_adc_callbacks[1];
3943
static uint32_t pbdrv_adc_callback_count = 0;
@@ -48,127 +52,58 @@ pbio_error_t pbdrv_adc_get_ch(uint8_t ch, uint16_t *value) {
4852
if (ch >= PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS) {
4953
return PBIO_ERROR_INVALID_ARG;
5054
}
51-
// Values for the requested channel are received several samples later.
52-
// The data only appears 12-bit but the last 2 bits are always zero.
53-
*value = (channel_data[ch + PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES] - 4096 * ch) >> 2;
55+
// XXX We probably need to figure out how atomicity works between the DMA and the CPU.
56+
// For now, read the value twice and assume it's good (not torn) if the values are the same.
57+
uint16_t a, b;
58+
do {
59+
// Values for the requested channel are received several samples later.
60+
a = channel_data[ch + PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES];
61+
b = channel_data[ch + PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES];
62+
} while (a != b);
63+
64+
// Mask the data to 10 bits
65+
*value = (a >> 2) & 0x3ff;
5466
return PBIO_SUCCESS;
5567
}
5668

57-
static void spi0_isr(void) {
58-
uint32_t intCode = 0;
59-
IntSystemStatusClear(SYS_INT_SPINT0);
60-
61-
while ((intCode = SPIInterruptVectorGet(SOC_SPI_0_REGS))) {
62-
if (intCode != SPI_TX_BUF_EMPTY) {
63-
continue;
64-
}
65-
// Payload encoding comes from the original EV3 sources, but we
66-
// use the hardware SPI peripheral instead of bit-banging.
67-
uint16_t payload = 0x1840 | (((channel_data_index % PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS) & 0x000F) << 7);
68-
HWREG(SOC_SPI_0_REGS + SPI_SPIDAT0) = payload;
69-
channel_data[channel_data_index] = SPIDataReceive(SOC_SPI_0_REGS);
70-
71-
if (++channel_data_index == PBIO_ARRAY_SIZE(channel_data)) {
72-
SPIIntDisable(SOC_SPI_0_REGS, SPI_TRANSMIT_INT);
73-
adc_busy = false;
74-
process_poll(&pbdrv_adc_process);
75-
}
76-
}
77-
}
69+
static pbio_os_process_t pbdrv_adc_ev3_process;
7870

79-
static void pbdrv_adc_exit(void) {
80-
SPIIntDisable(SOC_SPI_0_REGS, SPI_RECV_INT | SPI_TRANSMIT_INT);
81-
}
71+
pbio_error_t pbdrv_adc_ev3_process_thread(pbio_os_state_t *state, void *context) {
72+
static pbio_os_timer_t timer;
8273

83-
// ADC / Flash SPI0 data MOSI
84-
static const pbdrv_gpio_t pin_spi0_mosi = PBDRV_GPIO_EV3_PIN(3, 15, 12, 8, 5);
74+
(void)timer;
8575

86-
// ADC / Flash SPI0 data MISO
87-
static const pbdrv_gpio_t pin_spi0_miso = PBDRV_GPIO_EV3_PIN(3, 11, 8, 8, 6);
76+
PBIO_OS_ASYNC_BEGIN(state);
8877

89-
// LCD SPI0 Clock
90-
static const pbdrv_gpio_t pin_spi0_clk = PBDRV_GPIO_EV3_PIN(3, 3, 0, 1, 8);
78+
// HACK: This waits until storage is completely done with SPI flash before we start
79+
PBIO_OS_AWAIT_UNTIL(state, pbsys_storage_settings_get_settings());
9180

92-
// ADC / Flash SPI0 chip select (active low).
93-
static const pbdrv_gpio_t pin_spi0_cs = PBDRV_GPIO_EV3_PIN(3, 27, 24, 8, 2);
81+
// Once SPI flash init is finished, there is nothing further for us to do.
82+
// We are ready to start sampling.
9483

95-
// ADCACK PIN
96-
static const pbdrv_gpio_t pin_adc_ack = PBDRV_GPIO_EV3_PIN(19, 19, 16, 6, 2);
84+
// TODO: Actually start sampling
9785

98-
// ADCBATEN
99-
static const pbdrv_gpio_t pin_adc_bat_en = PBDRV_GPIO_EV3_PIN(1, 7, 4, 0, 6);
86+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
87+
}
10088

10189
void pbdrv_adc_init(void) {
90+
// Immediately go into async mode so that we can wait for the SPI flash driver.
91+
// We *don't* want to block the initial init phase, or else things will deadlock.
10292

103-
// Configure the GPIO pins.
104-
pbdrv_gpio_alt(&pin_spi0_mosi, SYSCFG_PINMUX3_PINMUX3_15_12_SPI0_SIMO0);
105-
pbdrv_gpio_alt(&pin_spi0_miso, SYSCFG_PINMUX3_PINMUX3_11_8_SPI0_SOMI0);
106-
pbdrv_gpio_alt(&pin_spi0_clk, SYSCFG_PINMUX3_PINMUX3_3_0_SPI0_CLK);
107-
pbdrv_gpio_alt(&pin_spi0_cs, SYSCFG_PINMUX3_PINMUX3_27_24_NSPI0_SCS3);
108-
109-
pbdrv_gpio_input(&pin_adc_ack);
110-
111-
pbdrv_gpio_out_high(&pin_adc_bat_en);
112-
113-
// Waking up the SPI1 instance.
114-
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_SPI0, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
115-
116-
// Register the ISR in the Interrupt Vector Table.
117-
IntRegister(SYS_INT_SPINT0, spi0_isr);
118-
IntChannelSet(SYS_INT_SPINT0, 2);
119-
IntSystemEnable(SYS_INT_SPINT0);
120-
121-
// Reset.
122-
SPIReset(SOC_SPI_0_REGS);
123-
SPIOutOfReset(SOC_SPI_0_REGS);
124-
125-
// Mode.
126-
uint32_t spipc0 = SPI_SPIPC0_SOMIFUN | SPI_SPIPC0_SIMOFUN | SPI_SPIPC0_CLKFUN | SPI_SPIPC0_SCS0FUN3;
127-
SPIModeConfigure(SOC_SPI_0_REGS, SPI_MASTER_MODE);
128-
SPIPinControl(SOC_SPI_0_REGS, 0, 0, (unsigned int *)&spipc0);
129-
130-
// Config.
131-
SPIClkConfigure(SOC_SPI_0_REGS, SOC_SYSCLK_2_FREQ, 2000000, SPI_DATA_FORMAT0);
132-
SPIConfigClkFormat(SOC_SPI_0_REGS, SPI_CLK_OUTOFPHASE | 0x00000010, SPI_DATA_FORMAT0);
133-
SPIDelayConfigure(SOC_SPI_0_REGS, 10, 10, 10, 10);
134-
SPIIntLevelSet(SOC_SPI_0_REGS, SPI_RECV_INTLVL | SPI_TRANSMIT_INTLVL);
135-
SPIDefaultCSSet(SOC_SPI_0_REGS, 8);
136-
137-
// Enable and loop around all channels.
138-
SPIEnable(SOC_SPI_0_REGS);
139-
140-
process_start(&pbdrv_adc_process);
93+
pbio_os_process_start(&pbdrv_adc_ev3_process, pbdrv_adc_ev3_process_thread, NULL);
14194
}
14295

14396
void pbdrv_adc_update_soon(void) {
144-
process_poll(&pbdrv_adc_process);
97+
adc_soon = 1;
98+
pbio_os_request_poll();
14599
}
146100

147-
PROCESS_THREAD(pbdrv_adc_process, ev, data) {
148-
PROCESS_EXITHANDLER(pbdrv_adc_exit());
149-
150-
static struct etimer etimer;
151-
152-
PROCESS_BEGIN();
153-
154-
etimer_set(&etimer, 10);
155-
for (;;) {
156-
PROCESS_WAIT_EVENT_UNTIL((ev == PROCESS_EVENT_TIMER && etimer_expired(&etimer)) || ev == PROCESS_EVENT_POLL);
157-
158-
channel_data_index = 0;
159-
adc_busy = true;
160-
SPIEnable(SOC_SPI_0_REGS);
161-
SPIIntEnable(SOC_SPI_0_REGS, SPI_TRANSMIT_INT);
162-
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_POLL && !adc_busy);
163-
164-
for (uint32_t i = 0; i < pbdrv_adc_callback_count; i++) {
165-
pbdrv_adc_callbacks[i]();
166-
}
167-
168-
etimer_reset(&etimer);
169-
}
170-
171-
PROCESS_END();
101+
void pbdrv_adc_ev3_shut_down_hack() {
102+
shut_down_hack = 1;
103+
pbio_os_request_poll();
104+
}
105+
int pbdrv_adc_ev3_is_shut_down_hack() {
106+
return shut_down_hack_done;
172107
}
173108

174109
#endif // PBDRV_CONFIG_ADC_EV3

lib/pbio/drv/adc/adc_ev3.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 The Pybricks Authors
3+
4+
#ifndef _INTERNAL_PBDRV_ADC_EV3_H_
5+
#define _INTERNAL_PBDRV_ADC_EV3_H_
6+
7+
void pbdrv_adc_ev3_shut_down_hack();
8+
int pbdrv_adc_ev3_is_shut_down_hack();
9+
10+
#endif // _INTERNAL_PBDRV_ADC_EV3_H_

lib/pbio/drv/block_device/block_device_ev3.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "block_device_ev3.h"
2929
#include "../drv/gpio/gpio_ev3.h"
30+
#include "../drv/adc/adc_ev3.h"
3031

3132
#include <pbio/error.h>
3233
#include <pbio/int_math.h>
@@ -581,6 +582,13 @@ pbio_error_t pbdrv_block_device_store(pbio_os_state_t *state, uint8_t *buffer, u
581582
return PBIO_ERROR_INVALID_ARG;
582583
}
583584

585+
#if PBDRV_CONFIG_ADC_EV3
586+
// HACK
587+
// We only store on shutdown. Block ADC.
588+
pbdrv_adc_ev3_shut_down_hack();
589+
PBIO_OS_AWAIT_UNTIL(state, pbdrv_adc_ev3_is_shut_down_hack());
590+
#endif
591+
584592
// Erase sector by sector.
585593
for (offset = 0; offset < size; offset += FLASH_SIZE_ERASE) {
586594
// Enable writing

lib/pbio/platform/ev3/pbdrvconfig.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
// platform-specific configuration for LEGO MINDSTORMS EV3
55

6-
#define PBDRV_CONFIG_ADC (0)
7-
#define PBDRV_CONFIG_ADC_EV3 (0)
6+
#define PBDRV_CONFIG_ADC (1)
7+
#define PBDRV_CONFIG_ADC_EV3 (1)
88
#define PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS (16)
99

1010
#define PBDRV_CONFIG_CLOCK (1)

0 commit comments

Comments
 (0)