Skip to content

Commit c1e0ad6

Browse files
committed
pbio/drv/adc_ev3: Give control to block device.
The block device initiates the ADC polling process when it is fully loaded, and awaits the ADC process to exit before it writes. Fixes pybricks/support#2264
1 parent 930be09 commit c1e0ad6

File tree

4 files changed

+42
-44
lines changed

4 files changed

+42
-44
lines changed

lib/pbio/drv/adc/adc_ev3.c

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,6 @@ static const uint32_t channel_cmd[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_
9191
static volatile uint16_t channel_data[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES];
9292

9393
static int adc_soon;
94-
// Used to block ADC from interfering with flash upon shutdown
95-
static int shut_down_hack = 0;
96-
static int shut_down_hack_done = 0;
9794

9895
static pbdrv_adc_callback_t pbdrv_adc_callbacks[1];
9996
static uint32_t pbdrv_adc_callback_count = 0;
@@ -124,24 +121,30 @@ pbio_error_t pbdrv_adc_get_ch(uint8_t ch, uint16_t *value) {
124121

125122
static pbio_os_process_t pbdrv_adc_ev3_process;
126123

124+
/**
125+
* Request ADC process to exit and await until it does.
126+
*/
127+
pbio_error_t pbdrv_adc_ev3_exit(pbio_os_state_t *state) {
128+
PBIO_OS_ASYNC_BEGIN(state);
129+
130+
pbio_os_process_make_request(&pbdrv_adc_ev3_process, PBIO_OS_PROCESS_REQUEST_TYPE_CANCEL);
131+
PBIO_OS_AWAIT_UNTIL(state, pbdrv_adc_ev3_process.err == PBIO_SUCCESS);
132+
133+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
134+
}
135+
127136
pbio_error_t pbdrv_adc_ev3_process_thread(pbio_os_state_t *state, void *context) {
128137
static pbio_os_timer_t timer;
129138

130139
PBIO_OS_ASYNC_BEGIN(state);
131140

132-
// HACK: This waits until storage is completely done with SPI flash before we start
133-
PBIO_OS_AWAIT_UNTIL(state, pbsys_storage_settings_get_settings());
134-
135-
// Once SPI flash init is finished, there is nothing further for us to do.
136-
// We are ready to start sampling.
137-
138141
pbio_os_timer_set(&timer, ADC_SAMPLE_PERIOD);
139142

140143
for (;;) {
141-
PBIO_OS_AWAIT_UNTIL(state, shut_down_hack || adc_soon || pbio_os_timer_is_expired(&timer));
144+
PBIO_OS_AWAIT_UNTIL(state, pbdrv_adc_ev3_process.request || adc_soon || pbio_os_timer_is_expired(&timer));
142145

143-
if (shut_down_hack) {
144-
shut_down_hack_done = 1;
146+
// Here we can exit gracefully since no SPI operation is in progress.
147+
if (pbdrv_adc_ev3_process.request & PBIO_OS_PROCESS_REQUEST_TYPE_CANCEL) {
145148
break;
146149
}
147150

@@ -165,22 +168,26 @@ pbio_error_t pbdrv_adc_ev3_process_thread(pbio_os_state_t *state, void *context)
165168
}
166169
}
167170

168-
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
169-
}
170-
171-
void pbdrv_adc_init(void) {
172-
// Immediately go into async mode so that we can wait for the SPI flash driver.
173-
// We *don't* want to block the initial init phase, or else things will deadlock.
171+
// Processes may be waiting on us to complete, so kick when done.
172+
pbio_os_request_poll();
174173

175-
pbio_os_process_start(&pbdrv_adc_ev3_process, pbdrv_adc_ev3_process_thread, NULL);
174+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
176175
}
177176

178177
void pbdrv_adc_update_soon(void) {
179178
adc_soon = 1;
180179
pbio_os_request_poll();
181180
}
182181

183-
void pbdrv_adc_ev3_configure_data_format() {
182+
// Public init is not used.
183+
void pbdrv_adc_init(void) {
184+
}
185+
186+
// Init starts here instead. Called by SPI flash driver when it is done initializing.
187+
void pbdrv_adc_ev3_init(void) {
188+
189+
// Most of the SPI initialization is already done by the SPI flash driver.
190+
184191
SPIClkConfigure(SOC_SPI_0_REGS, SOC_SYSCLK_2_FREQ, SPI_CLK_SPEED_ADC, SPI_DATA_FORMAT1);
185192
// NOTE: Cannot be CPOL=1 CPHA=1 like SPI flash
186193
// The ADC seems to use the last falling edge to trigger conversions (see Figure 1 in the datasheet).
@@ -193,14 +200,9 @@ void pbdrv_adc_ev3_configure_data_format() {
193200
// as well as the CS-assert-to-clock-start and clock-end-to-CS-deassert delays
194201
// (which are global and set in block_device_ev3.c).
195202
SPIWdelaySet(SOC_SPI_0_REGS, 0x3f << SPI_SPIFMT_WDELAY_SHIFT, SPI_DATA_FORMAT1);
196-
}
197203

198-
void pbdrv_adc_ev3_shut_down_hack() {
199-
shut_down_hack = 1;
200-
pbio_os_request_poll();
201-
}
202-
int pbdrv_adc_ev3_is_shut_down_hack() {
203-
return shut_down_hack_done;
204+
// Begin polling.
205+
pbio_os_process_start(&pbdrv_adc_ev3_process, pbdrv_adc_ev3_process_thread, NULL);
204206
}
205207

206208
#endif // PBDRV_CONFIG_ADC_EV3

lib/pbio/drv/adc/adc_ev3.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
#ifndef _INTERNAL_PBDRV_ADC_EV3_H_
55
#define _INTERNAL_PBDRV_ADC_EV3_H_
66

7-
void pbdrv_adc_ev3_configure_data_format();
8-
9-
void pbdrv_adc_ev3_shut_down_hack();
10-
int pbdrv_adc_ev3_is_shut_down_hack();
7+
void pbdrv_adc_ev3_init(void);
8+
pbio_error_t pbdrv_adc_ev3_exit(pbio_os_state_t *state);
119

1210
#endif // _INTERNAL_PBDRV_ADC_EV3_H_

lib/pbio/drv/block_device/block_device_ev3.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,9 @@ pbio_error_t pbdrv_block_device_write_all(pbio_os_state_t *state, uint32_t used_
616616

617617
PBIO_OS_ASYNC_BEGIN(state);
618618

619+
// Need to await the ADC process to exit before we can write to flash.
620+
PBIO_OS_AWAIT(state, &sub, pbdrv_adc_ev3_exit(&sub));
621+
619622
// Exit on invalid size.
620623
if (size == 0 || size > PBDRV_CONFIG_BLOCK_DEVICE_EV3_SIZE) {
621624
return PBIO_ERROR_INVALID_ARG;
@@ -624,13 +627,6 @@ pbio_error_t pbdrv_block_device_write_all(pbio_os_state_t *state, uint32_t used_
624627
// Store the new size so we know how much to load on next boot.
625628
ramdisk.saved_size = size;
626629

627-
#if PBDRV_CONFIG_ADC_EV3
628-
// HACK
629-
// We only store on shutdown. Block ADC.
630-
pbdrv_adc_ev3_shut_down_hack();
631-
PBIO_OS_AWAIT_UNTIL(state, pbdrv_adc_ev3_is_shut_down_hack());
632-
#endif
633-
634630
// Erase sector by sector.
635631
for (offset = 0; offset < size; offset += FLASH_SIZE_ERASE) {
636632
// Enable writing
@@ -719,6 +715,9 @@ pbio_error_t pbdrv_block_device_ev3_init_process_thread(pbio_os_state_t *state,
719715
// properly on shutdown.
720716
pbdrv_init_busy_down();
721717

718+
// ADC may start polling now.
719+
pbdrv_adc_ev3_init();
720+
722721
PBIO_OS_ASYNC_END(err);
723722
}
724723

@@ -743,9 +742,8 @@ void pbdrv_block_device_init(void) {
743742
SPIConfigClkFormat(SOC_SPI_0_REGS, SPI_CLK_POL_LOW | SPI_CLK_OUTOFPHASE, SPI_DATA_FORMAT0);
744743
SPIShiftMsbFirst(SOC_SPI_0_REGS, SPI_DATA_FORMAT0);
745744
SPICharLengthSet(SOC_SPI_0_REGS, 8, SPI_DATA_FORMAT0);
746-
#if PBDRV_CONFIG_ADC_EV3
747-
pbdrv_adc_ev3_configure_data_format();
748-
#endif
745+
746+
// Additional SPI configuration ADC is done when the ADC driver starts.
749747

750748
// Configure the GPIO pins.
751749
pbdrv_gpio_alt(&pin_spi0_mosi, SYSCFG_PINMUX3_PINMUX3_15_12_SPI0_SIMO0);

lib/pbio/drv/block_device/block_device_ev3.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
#define PBDRV_EV3_SPI0_FLASH_CS (0)
1111
#define PBDRV_EV3_SPI0_ADC_CS (3)
1212

13-
void pbdrv_block_device_ev3_spi_tx_complete();
14-
void pbdrv_block_device_ev3_spi_rx_complete();
13+
void pbdrv_block_device_ev3_spi_tx_complete(void);
14+
void pbdrv_block_device_ev3_spi_rx_complete(void);
1515

1616
// XXX The SPI flash and ADC both use the SPI0 peripheral.
1717
// Since we do not have a fully-fledged "bus" abstraction,
1818
// these two drivers have tight dependencies on each other.
1919
// These functions orchestrate the connection.
2020

21-
int pbdrv_block_device_ev3_is_busy();
21+
int pbdrv_block_device_ev3_is_busy(void);
2222
pbio_error_t pbdrv_block_device_ev3_spi_begin_for_adc(const uint32_t *cmds, volatile uint16_t *data, unsigned int len);
2323

2424
#endif // _INTERNAL_PBDRV_BLOCK_DEVICE_EV3_H_

0 commit comments

Comments
 (0)