Skip to content

Commit 23cde1b

Browse files
committed
pbio/drv/adc/adc_ev3: Implement new DMA-based ADC sampling
1 parent ea42de9 commit 23cde1b

File tree

1 file changed

+70
-3
lines changed

1 file changed

+70
-3
lines changed

lib/pbio/drv/adc/adc_ev3.c

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,47 @@ enum {
4646
ADC_SAMPLE_PERIOD = 10,
4747
};
4848

49+
// Construct both SPI peripheral settings (data format, chip select)
50+
// and ADC chip settings (manual mode, 2xVref) in one go,
51+
// so that DMA can be used efficiently.
52+
//
53+
// NOTE: CSHOLD is *not* set here, so that CS is deasserted between each 16-bit unit
54+
#define MANUAL_ADC_CHANNEL(x) \
55+
(SPI_SPIDAT1_DFSEL_FORMAT1 << SPI_SPIDAT1_DFSEL_SHIFT) | \
56+
(0 << (SPI_SPIDAT1_CSNR_SHIFT + PBDRV_EV3_SPI0_ADC_CS)) | \
57+
(1 << (SPI_SPIDAT1_CSNR_SHIFT + PBDRV_EV3_SPI0_FLASH_CS)) | \
58+
(1 << 12) | \
59+
(1 << 11) | \
60+
(((x) & 0xf) << 7) | \
61+
(1 << 6)
62+
63+
static const uint32_t channel_cmd[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES] = {
64+
MANUAL_ADC_CHANNEL(0),
65+
MANUAL_ADC_CHANNEL(1),
66+
MANUAL_ADC_CHANNEL(2),
67+
MANUAL_ADC_CHANNEL(3),
68+
MANUAL_ADC_CHANNEL(4),
69+
MANUAL_ADC_CHANNEL(5),
70+
MANUAL_ADC_CHANNEL(6),
71+
MANUAL_ADC_CHANNEL(7),
72+
MANUAL_ADC_CHANNEL(8),
73+
MANUAL_ADC_CHANNEL(9),
74+
MANUAL_ADC_CHANNEL(10),
75+
MANUAL_ADC_CHANNEL(11),
76+
MANUAL_ADC_CHANNEL(12),
77+
MANUAL_ADC_CHANNEL(13),
78+
MANUAL_ADC_CHANNEL(14),
79+
MANUAL_ADC_CHANNEL(15),
80+
// We need two additional commands here because of how the ADC works.
81+
// In every given command frame, a new analog channel is selected in the ADC frontend multiplexer.
82+
// In frame n+1, that value actually gets converted to a digital value.
83+
// In frame n+2, the converted digital value is finally output, and we are able to receive it.
84+
// These requests are _pipelined_, so there is a latency of 2 frames, but we get a new sample on each frame.
85+
//
86+
// For more information, see figures 1 and 51 in the ADS7957 datasheet.
87+
MANUAL_ADC_CHANNEL(15),
88+
MANUAL_ADC_CHANNEL(15),
89+
};
4990
static volatile uint16_t channel_data[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES];
5091

5192
static int adc_soon;
@@ -85,8 +126,6 @@ static pbio_os_process_t pbdrv_adc_ev3_process;
85126
pbio_error_t pbdrv_adc_ev3_process_thread(pbio_os_state_t *state, void *context) {
86127
static pbio_os_timer_t timer;
87128

88-
(void)timer;
89-
90129
PBIO_OS_ASYNC_BEGIN(state);
91130

92131
// HACK: This waits until storage is completely done with SPI flash before we start
@@ -95,7 +134,35 @@ pbio_error_t pbdrv_adc_ev3_process_thread(pbio_os_state_t *state, void *context)
95134
// Once SPI flash init is finished, there is nothing further for us to do.
96135
// We are ready to start sampling.
97136

98-
// TODO: Actually start sampling
137+
pbio_os_timer_set(&timer, ADC_SAMPLE_PERIOD);
138+
139+
for (;;) {
140+
PBIO_OS_AWAIT_UNTIL(state, shut_down_hack || adc_soon || pbio_os_timer_is_expired(&timer));
141+
142+
if (shut_down_hack) {
143+
shut_down_hack_done = 1;
144+
break;
145+
}
146+
147+
if (adc_soon) {
148+
adc_soon = 0;
149+
pbio_os_timer_set(&timer, ADC_SAMPLE_PERIOD);
150+
} else {
151+
// TODO: There should probably be a pbio OS function for this
152+
timer.start += timer.duration;
153+
}
154+
155+
// Do a sample of all channels
156+
pbdrv_block_device_ev3_spi_begin_for_adc(
157+
channel_cmd,
158+
channel_data,
159+
PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_CONFIG_ADC_EV3_NUM_DELAY_SAMPLES);
160+
PBIO_OS_AWAIT_WHILE(state, pbdrv_block_device_ev3_is_busy());
161+
162+
for (uint32_t i = 0; i < pbdrv_adc_callback_count; i++) {
163+
pbdrv_adc_callbacks[i]();
164+
}
165+
}
99166

100167
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
101168
}

0 commit comments

Comments
 (0)