Skip to content

Commit 6fdc7e1

Browse files
committed
pbio/drv/block_device: Drive ADC loop with fewer events.
We yielded and polled immediately after initiating the ADC transfer to give other awaitables a chance to start waiting on the transfer. This leads to many extra events and could theoretically introduce a race condition if the DMA operation completes before it gets into the right wait state. Instead, higher level code can await new samples by waiting until the DMA completion timestamp has passed the time of interest, without inducing more events. While we do this, we can conveniently introduce a handle to wait until a specified future sample, which can be used if signals need to settle before measuring the ADC value.
1 parent ee203b3 commit 6fdc7e1

File tree

5 files changed

+31
-32
lines changed

5 files changed

+31
-32
lines changed

lib/pbio/drv/adc/adc_stm32_hal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static uint32_t pbdrv_adc_last_error;
4747

4848
PROCESS(pbdrv_adc_process, "ADC");
4949

50-
pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state) {
50+
pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state, pbio_os_timer_t *timer, uint32_t future) {
5151
return PBIO_ERROR_NOT_SUPPORTED;
5252
}
5353

lib/pbio/drv/adc/adc_stm32f0.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ void pbdrv_adc_init(void) {
6666
process_start(&pbdrv_adc_process);
6767
}
6868

69-
pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state) {
69+
pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state, pbio_os_timer_t *timer, uint32_t future) {
7070
return PBIO_ERROR_NOT_SUPPORTED;
7171
}
7272

lib/pbio/drv/block_device/block_device_ev3.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "../core.h"
2424

2525
#include <pbdrv/block_device.h>
26+
#include <pbdrv/clock.h>
2627
#include <pbdrv/gpio.h>
2728

2829
#include <tiam1808/edma.h>
@@ -103,26 +104,32 @@ static struct {
103104
uint8_t spi_cmd_buf_rx[SPI_CMD_BUF_SZ];
104105
} spi_dev;
105106

107+
static uint32_t last_spi_dma_complete_time;
108+
109+
static void spi_dma_complete(void) {
110+
// Only complete once RX and TX complete.
111+
if (spi_dev.status & SPI_STATUS_WAIT_ANY) {
112+
return;
113+
}
114+
SPIIntDisable(SOC_SPI_0_REGS, SPI_DMA_REQUEST_ENA_INT);
115+
pbio_os_request_poll();
116+
last_spi_dma_complete_time = pbdrv_clock_get_ms();
117+
}
118+
106119
/**
107120
* Tx transfer complete.
108121
*/
109122
void pbdrv_block_device_ev3_spi_tx_complete(void) {
110123
spi_dev.status &= ~SPI_STATUS_WAIT_TX;
111-
if (!(spi_dev.status & SPI_STATUS_WAIT_ANY)) {
112-
SPIIntDisable(SOC_SPI_0_REGS, SPI_DMA_REQUEST_ENA_INT);
113-
pbio_os_request_poll();
114-
}
124+
spi_dma_complete();
115125
}
116126

117127
/**
118128
* Rx transfer complete.
119129
*/
120130
void pbdrv_block_device_ev3_spi_rx_complete(void) {
121131
spi_dev.status &= ~SPI_STATUS_WAIT_RX;
122-
if (!(spi_dev.status & SPI_STATUS_WAIT_ANY)) {
123-
SPIIntDisable(SOC_SPI_0_REGS, SPI_DMA_REQUEST_ENA_INT);
124-
pbio_os_request_poll();
125-
}
132+
spi_dma_complete();
126133
}
127134

128135
/**
@@ -735,10 +742,10 @@ pbio_error_t pbdrv_adc_get_ch(uint8_t ch, uint16_t *value) {
735742
return PBIO_SUCCESS;
736743
}
737744

738-
pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state) {
745+
pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state, pbio_os_timer_t *timer, uint32_t future) {
739746
PBIO_OS_ASYNC_BEGIN(state);
740-
PBIO_OS_AWAIT_UNTIL(state, (spi_dev.status & SPI_STATUS_WAIT_ANY));
741-
PBIO_OS_AWAIT_UNTIL(state, !(spi_dev.status & SPI_STATUS_WAIT_ANY));
747+
pbio_os_timer_set(timer, 0);
748+
PBIO_OS_AWAIT_UNTIL(state, pbio_util_time_has_passed(last_spi_dma_complete_time, timer->start + future));
742749
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
743750
}
744751

@@ -887,11 +894,7 @@ pbio_error_t ev3_spi_process_thread(pbio_os_state_t *state, void *context) {
887894
channel_data,
888895
PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES);
889896

890-
// Allow event loop to run once so that processes that await new
891-
// samples can begin awaiting completion of the transfer.
892-
PBIO_OS_AWAIT_ONCE_AND_POLL(state);
893-
894-
// Await for actual transfer to complete.
897+
// Await for transfer to complete.
895898
PBIO_OS_AWAIT_WHILE(state, (spi_dev.status & SPI_STATUS_WAIT_ANY));
896899

897900
pbio_os_timer_set(&timer, ADC_SAMPLE_PERIOD);

lib/pbio/include/pbdrv/adc.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ pbio_error_t pbdrv_adc_get_ch(uint8_t ch, uint16_t *value);
3535
* Not implemented on all platforms.
3636
*
3737
* @param [in] state Protothread state.
38+
* @param [in] timer Parent process timer, used to store time of calling this.
39+
* @param [in] future How far into the future the sample should be (ms).
3840
*/
39-
pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state);
41+
pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state, pbio_os_timer_t *timer, uint32_t future);
4042

4143
#else
4244

@@ -45,7 +47,7 @@ static inline pbio_error_t pbdrv_adc_get_ch(uint8_t ch, uint16_t *value) {
4547
return PBIO_ERROR_NOT_SUPPORTED;
4648
}
4749

48-
static inline pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state) {
50+
static inline pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state, pbio_os_timer_t *timer, uint32_t future) {
4951
return PBIO_ERROR_NOT_SUPPORTED;
5052
}
5153

lib/pbio/src/port_dcm_ev3.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -374,14 +374,12 @@ pbio_error_t pbio_port_dcm_thread(pbio_os_state_t *state, pbio_os_timer_t *timer
374374
while (!pbdrv_gpio_input(&pins->p2)) {
375375
// Reflected intensity.
376376
pbdrv_gpio_out_high(&pins->p5);
377-
PBIO_OS_AWAIT_MS(state, timer, 2);
378-
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child));
377+
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child, timer, 2));
379378
dcm->nxt_rgba.r = pbio_port_dcm_get_mv(pins, 1);
380379

381380
// Ambient intensity.
382381
pbdrv_gpio_out_low(&pins->p5);
383-
PBIO_OS_AWAIT_MS(state, timer, 2);
384-
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child));
382+
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child, timer, 2));
385383
dcm->nxt_rgba.a = pbio_port_dcm_get_mv(pins, 1);
386384
}
387385
continue;
@@ -412,23 +410,19 @@ pbio_error_t pbio_port_dcm_thread(pbio_os_state_t *state, pbio_os_timer_t *timer
412410
while (!pbdrv_gpio_input(&pins->p2)) {
413411

414412
pbdrv_gpio_out_low(&pins->p5);
415-
PBIO_OS_AWAIT_MS(state, timer, 2);
416-
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child));
413+
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child, timer, 2));
417414
dcm->nxt_rgba.a = pbio_port_dcm_get_mv(pins, 6);
418415

419416
pbdrv_gpio_out_high(&pins->p5);
420-
PBIO_OS_AWAIT_MS(state, timer, 2);
421-
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child));
417+
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child, timer, 2));
422418
dcm->nxt_rgba.r = pbio_port_dcm_get_mv(pins, 6);
423419

424420
pbdrv_gpio_out_low(&pins->p5);
425-
PBIO_OS_AWAIT_MS(state, timer, 2);
426-
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child));
421+
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child, timer, 2));
427422
dcm->nxt_rgba.g = pbio_port_dcm_get_mv(pins, 6);
428423

429424
pbdrv_gpio_out_high(&pins->p5);
430-
PBIO_OS_AWAIT_MS(state, timer, 2);
431-
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child));
425+
PBIO_OS_AWAIT(state, &dcm->child, pbdrv_adc_await_new_samples(&dcm->child, timer, 2));
432426
dcm->nxt_rgba.b = pbio_port_dcm_get_mv(pins, 6);
433427
}
434428
pbdrv_gpio_out_low(&pins->p5);

0 commit comments

Comments
 (0)