|
1 | 1 | // SPDX-License-Identifier: MIT |
2 | | -// Copyright (c) 2024 The Pybricks Authors |
| 2 | +// Copyright (c) 2024-2025 The Pybricks Authors |
3 | 3 |
|
4 | 4 | #include <pbdrv/config.h> |
5 | 5 |
|
|
9 | 9 | #error "EV3 block device driver must be enabled" |
10 | 10 | #endif |
11 | 11 |
|
12 | | -#include <stdbool.h> |
13 | | -#include <stdint.h> |
14 | | -#include <string.h> |
| 12 | +// NB: This driver is implemented by pbdrv/block_device because it is on the |
| 13 | +// same SPI bus. |
15 | 14 |
|
16 | | -#include <pbdrv/adc.h> |
17 | | -#include <pbdrv/clock.h> |
18 | | -#include <pbdrv/gpio.h> |
19 | | - |
20 | | -#include <pbio/error.h> |
21 | | -#include <pbio/os.h> |
22 | | -#include <pbio/util.h> |
23 | | - |
24 | | -#include <tiam1808/spi.h> |
25 | | -#include <tiam1808/psc.h> |
26 | | -#include <tiam1808/hw/soc_AM1808.h> |
27 | | -#include <tiam1808/hw/hw_types.h> |
28 | | -#include <tiam1808/hw/hw_syscfg0_AM1808.h> |
29 | | -#include <tiam1808/armv5/am1808/interrupt.h> |
30 | | - |
31 | | -#include "adc_ev3.h" |
32 | | -#include "../drv/block_device/block_device_ev3.h" |
33 | | -#include "../drv/gpio/gpio_ev3.h" |
34 | | - |
35 | | -#include "../sys/storage.h" |
36 | | - |
37 | | -#define PBDRV_ADC_EV3_NUM_DELAY_SAMPLES (2) |
38 | | - |
39 | | -/** |
40 | | - * Constants. |
41 | | - */ |
42 | | -enum { |
43 | | - // The maximum ADC clock speed according to the datasheet is 20 MHz. |
44 | | - // However, because the SPI peripheral does not have a fractional clock generator, |
45 | | - // the closest achievable in-spec speed is a division factor of 8. |
46 | | - // |
47 | | - // 150 MHz / 8 = 18.75 MHz actual |
48 | | - SPI_CLK_SPEED_ADC = 20000000, |
49 | | - |
50 | | - ADC_SAMPLE_PERIOD = 2, |
51 | | -}; |
52 | | - |
53 | | -// Construct both SPI peripheral settings (data format, chip select) |
54 | | -// and ADC chip settings (manual mode, 2xVref) in one go, |
55 | | -// so that DMA can be used efficiently. |
56 | | -// |
57 | | -// NOTE: CSHOLD is *not* set here, so that CS is deasserted between each 16-bit unit |
58 | | -#define MANUAL_ADC_CHANNEL(x) \ |
59 | | - (1 << 26) | \ |
60 | | - (SPI_SPIDAT1_DFSEL_FORMAT1 << SPI_SPIDAT1_DFSEL_SHIFT) | \ |
61 | | - (0 << (SPI_SPIDAT1_CSNR_SHIFT + PBDRV_EV3_SPI0_ADC_CS)) | \ |
62 | | - (1 << (SPI_SPIDAT1_CSNR_SHIFT + PBDRV_EV3_SPI0_FLASH_CS)) | \ |
63 | | - (1 << 12) | \ |
64 | | - (1 << 11) | \ |
65 | | - (((x) & 0xf) << 7) | \ |
66 | | - (1 << 6) |
67 | | - |
68 | | -static const uint32_t channel_cmd[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES] = { |
69 | | - MANUAL_ADC_CHANNEL(0), |
70 | | - MANUAL_ADC_CHANNEL(1), |
71 | | - MANUAL_ADC_CHANNEL(2), |
72 | | - MANUAL_ADC_CHANNEL(3), |
73 | | - MANUAL_ADC_CHANNEL(4), |
74 | | - MANUAL_ADC_CHANNEL(5), |
75 | | - MANUAL_ADC_CHANNEL(6), |
76 | | - MANUAL_ADC_CHANNEL(7), |
77 | | - MANUAL_ADC_CHANNEL(8), |
78 | | - MANUAL_ADC_CHANNEL(9), |
79 | | - MANUAL_ADC_CHANNEL(10), |
80 | | - MANUAL_ADC_CHANNEL(11), |
81 | | - MANUAL_ADC_CHANNEL(12), |
82 | | - MANUAL_ADC_CHANNEL(13), |
83 | | - MANUAL_ADC_CHANNEL(14), |
84 | | - MANUAL_ADC_CHANNEL(15), |
85 | | - // We need two additional commands here because of how the ADC works. |
86 | | - // In every given command frame, a new analog channel is selected in the ADC frontend multiplexer. |
87 | | - // In frame n+1, that value actually gets converted to a digital value. |
88 | | - // In frame n+2, the converted digital value is finally output, and we are able to receive it. |
89 | | - // These requests are _pipelined_, so there is a latency of 2 frames, but we get a new sample on each frame. |
90 | | - // |
91 | | - // For more information, see figures 1 and 51 in the ADS7957 datasheet. |
92 | | - MANUAL_ADC_CHANNEL(15), |
93 | | - MANUAL_ADC_CHANNEL(15), |
94 | | -}; |
95 | | -static volatile uint16_t channel_data[PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES]; |
96 | | - |
97 | | -pbio_error_t pbdrv_adc_get_ch(uint8_t ch, uint16_t *value) { |
98 | | - if (ch >= PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS) { |
99 | | - return PBIO_ERROR_INVALID_ARG; |
100 | | - } |
101 | | - // XXX We probably need to figure out how atomicity works between the DMA and the CPU. |
102 | | - // For now, read the value twice and assume it's good (not torn) if the values are the same. |
103 | | - uint16_t a, b; |
104 | | - do { |
105 | | - // Values for the requested channel are received several samples later. |
106 | | - a = channel_data[ch + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES]; |
107 | | - b = channel_data[ch + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES]; |
108 | | - } while (a != b); |
109 | | - |
110 | | - // Mask the data to 10 bits |
111 | | - *value = (a >> 2) & 0x3ff; |
112 | | - return PBIO_SUCCESS; |
113 | | -} |
114 | | - |
115 | | -static pbio_os_process_t pbdrv_adc_ev3_process; |
116 | | - |
117 | | -/** |
118 | | - * Request ADC process to exit and await until it does. |
119 | | - */ |
120 | | -pbio_error_t pbdrv_adc_ev3_exit(pbio_os_state_t *state) { |
121 | | - PBIO_OS_ASYNC_BEGIN(state); |
122 | | - |
123 | | - pbio_os_process_make_request(&pbdrv_adc_ev3_process, PBIO_OS_PROCESS_REQUEST_TYPE_CANCEL); |
124 | | - PBIO_OS_AWAIT_UNTIL(state, pbdrv_adc_ev3_process.err == PBIO_SUCCESS); |
125 | | - |
126 | | - PBIO_OS_ASYNC_END(PBIO_SUCCESS); |
127 | | -} |
128 | | - |
129 | | -static pbio_error_t pbdrv_adc_ev3_process_thread(pbio_os_state_t *state, void *context) { |
130 | | - static pbio_os_timer_t timer; |
131 | | - |
132 | | - PBIO_OS_ASYNC_BEGIN(state); |
133 | | - |
134 | | - // Poll continuously until cancellation is requested. |
135 | | - while (!(pbdrv_adc_ev3_process.request & PBIO_OS_PROCESS_REQUEST_TYPE_CANCEL)) { |
136 | | - |
137 | | - // Start a sample of all channels |
138 | | - pbdrv_block_device_ev3_spi_begin_for_adc( |
139 | | - channel_cmd, |
140 | | - channel_data, |
141 | | - PBDRV_CONFIG_ADC_EV3_ADC_NUM_CHANNELS + PBDRV_ADC_EV3_NUM_DELAY_SAMPLES); |
142 | | - |
143 | | - // Allow event loop to run once so that processes that await new |
144 | | - // samples can begin awaiting completion of the transfer. |
145 | | - PBIO_OS_AWAIT_ONCE_AND_POLL(state); |
146 | | - |
147 | | - // Await for actual transfer to complete. |
148 | | - PBIO_OS_AWAIT_WHILE(state, pbdrv_block_device_ev3_is_busy()); |
149 | | - |
150 | | - pbio_os_timer_set(&timer, ADC_SAMPLE_PERIOD); |
151 | | - PBIO_OS_AWAIT_UNTIL(state, pbdrv_adc_ev3_process.request || pbio_os_timer_is_expired(&timer)); |
152 | | - } |
153 | | - |
154 | | - // Processes may be waiting on us to complete, so kick when done. |
155 | | - pbio_os_request_poll(); |
156 | | - |
157 | | - PBIO_OS_ASYNC_END(PBIO_SUCCESS); |
158 | | -} |
159 | | - |
160 | | -pbio_error_t pbdrv_adc_await_new_samples(pbio_os_state_t *state) { |
161 | | - PBIO_OS_ASYNC_BEGIN(state); |
162 | | - PBIO_OS_AWAIT_UNTIL(state, pbdrv_block_device_ev3_is_busy()); |
163 | | - PBIO_OS_AWAIT_UNTIL(state, !pbdrv_block_device_ev3_is_busy()); |
164 | | - PBIO_OS_ASYNC_END(PBIO_SUCCESS); |
165 | | -} |
166 | | - |
167 | | -// Public init is not used. |
168 | 15 | void pbdrv_adc_init(void) { |
169 | 16 | } |
170 | 17 |
|
171 | | -// Init starts here instead. Called by SPI flash driver when it is done initializing. |
172 | | -void pbdrv_adc_ev3_init(void) { |
173 | | - |
174 | | - // Most of the SPI initialization is already done by the SPI flash driver. |
175 | | - |
176 | | - SPIClkConfigure(SOC_SPI_0_REGS, SOC_SYSCLK_2_FREQ, SPI_CLK_SPEED_ADC, SPI_DATA_FORMAT1); |
177 | | - // NOTE: Cannot be CPOL=1 CPHA=1 like SPI flash |
178 | | - // The ADC seems to use the last falling edge to trigger conversions (see Figure 1 in the datasheet). |
179 | | - SPIConfigClkFormat(SOC_SPI_0_REGS, SPI_CLK_POL_LOW | SPI_CLK_OUTOFPHASE, SPI_DATA_FORMAT1); |
180 | | - SPIShiftMsbFirst(SOC_SPI_0_REGS, SPI_DATA_FORMAT1); |
181 | | - SPICharLengthSet(SOC_SPI_0_REGS, 16, SPI_DATA_FORMAT1); |
182 | | - // In order to compensate for analog impedance issues and capacitor charging time, |
183 | | - // we set all SPI delays to the maximum for the ADC. This helps get more accurate readings. |
184 | | - // This includes both this delay (the delay where CS is held inactive), |
185 | | - // as well as the CS-assert-to-clock-start and clock-end-to-CS-deassert delays |
186 | | - // (which are global and set in block_device_ev3.c). |
187 | | - SPIWdelaySet(SOC_SPI_0_REGS, 0x3f << SPI_SPIFMT_WDELAY_SHIFT, SPI_DATA_FORMAT1); |
188 | | - |
189 | | - // Begin polling. |
190 | | - pbio_os_process_start(&pbdrv_adc_ev3_process, pbdrv_adc_ev3_process_thread, NULL); |
191 | | -} |
192 | | - |
193 | 18 | #endif // PBDRV_CONFIG_ADC_EV3 |
0 commit comments