Skip to content

Commit 0c4c305

Browse files
dimitrije-liliccfriedt
authored andcommitted
drivers: adc: max32: Support for RTIO stream
Updated MAX32 driver with RTIO stream functionality. Signed-off-by: Dimitrije Lilic <[email protected]>
1 parent bc0683b commit 0c4c305

File tree

4 files changed

+306
-3
lines changed

4 files changed

+306
-3
lines changed

drivers/adc/Kconfig.max32

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,11 @@ config ADC_MAX32
1010
select PINCTRL
1111
help
1212
Enable ADC driver for ADI MAX32xxx MCUs.
13+
14+
config ADC_MAX32_STREAM
15+
bool "Use FIFO to stream data"
16+
select ADC_ASYNC
17+
depends on ADC_MAX32
18+
depends on DT_HAS_ADI_MAX32_ADC_B_ME18_ENABLED
19+
help
20+
Use this configuration option to enable streaming ADC data via RTIO.

drivers/adc/adc_max32.c

Lines changed: 289 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <zephyr/drivers/adc.h>
1313
#include <zephyr/drivers/pinctrl.h>
1414
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
15+
#include <zephyr/sys/util.h>
16+
#include <zephyr/sys/byteorder.h>
1517

1618
#include <zephyr/logging/log.h>
1719
LOG_MODULE_REGISTER(adc_max32, CONFIG_ADC_LOG_LEVEL);
@@ -24,6 +26,16 @@ LOG_MODULE_REGISTER(adc_max32, CONFIG_ADC_LOG_LEVEL);
2426
/* reference voltage for the ADC */
2527
#define MAX32_ADC_VREF_MV DT_INST_PROP(0, vref_mv)
2628

29+
#define ADC_MAX32_INT_FIFO_LVL_MSK BIT(7)
30+
#define ADC_MAX32_SAMPLE_SIZE 2
31+
#define ADC_MAX32_BYTE_COUNT 16
32+
33+
enum adc_max32_fifo_format {
34+
ADC_MAX32_DATA_STATUS_FIFO,
35+
ADC_MAX32_DATA_ONLY_FIFO,
36+
ADC_MAX32_RAW_DATA_ONLY_FIFO,
37+
};
38+
2739
struct max32_adc_config {
2840
uint8_t channel_count;
2941
mxc_adc_regs_t *regs;
@@ -44,8 +56,45 @@ struct max32_adc_data {
4456
uint32_t channels;
4557
uint32_t sample_channels;
4658
const uint8_t resolution;
59+
#ifdef CONFIG_ADC_MAX32_STREAM
60+
struct rtio_iodev_sqe *sqe;
61+
struct rtio *rtio_ctx;
62+
struct rtio_iodev *iodev;
63+
uint64_t timestamp;
64+
struct rtio *r_cb;
65+
uint32_t adc_sample;
66+
uint8_t data_ready_gpio;
67+
uint8_t no_mem;
68+
struct k_timer sample_timer;
69+
const struct adc_sequence *sequence;
70+
uint8_t fifo_full_irq;
71+
#endif /* CONFIG_ADC_MAX32_STREAM */
72+
};
73+
74+
75+
#ifdef CONFIG_ADC_MAX32_STREAM
76+
/** MAX32 qscale modes */
77+
enum max32_qscale_modes {
78+
MAX32_12B_MODE = 0,
79+
};
80+
81+
struct adc_max32_fifo_config {
82+
enum adc_max32_fifo_format fifo_format;
83+
uint16_t fifo_samples;
4784
};
4885

86+
struct adc_max32_fifo_data {
87+
uint16_t is_fifo: 1;
88+
uint16_t max32_qscale_mode: 1;
89+
uint16_t diff_mode: 1;
90+
uint16_t res: 4;
91+
uint16_t fifo_byte_count: 5;
92+
uint16_t sample_set_size: 4;
93+
uint16_t vref_mv;
94+
uint64_t timestamp;
95+
} __attribute__((__packed__));
96+
#endif /* CONFIG_ADC_MAX32_STREAM */
97+
4998
#ifdef CONFIG_ADC_ASYNC
5099
static void adc_complete_cb(void *req, int error)
51100
{
@@ -54,6 +103,16 @@ static void adc_complete_cb(void *req, int error)
54103
}
55104
#endif /* CONFIG_ADC_ASYNC */
56105

106+
#ifdef CONFIG_ADC_MAX32_STREAM
107+
static void adc_complete_rtio_cb(const struct device *dev)
108+
{
109+
struct max32_adc_data *data = dev->data;
110+
struct rtio_iodev_sqe *iodev_sqe = data->sqe;
111+
112+
rtio_iodev_sqe_ok(iodev_sqe, 0);
113+
}
114+
#endif /* CONFIG_ADC_MAX32_STREAM */
115+
57116
static void adc_max32_start_channel(const struct device *dev)
58117
{
59118
struct max32_adc_data *data = dev->data;
@@ -150,6 +209,159 @@ static int adc_max32_read(const struct device *dev, const struct adc_sequence *s
150209
return ret;
151210
}
152211

212+
#ifdef CONFIG_ADC_MAX32_STREAM
213+
static int start_read_stream(const struct device *dev, const struct adc_sequence *seq)
214+
{
215+
struct max32_adc_data *data = dev->data;
216+
int ret = 0;
217+
218+
if (seq->resolution != data->resolution) {
219+
LOG_ERR("Unsupported resolution (%d)", seq->resolution);
220+
return -ENOTSUP;
221+
}
222+
if (seq->channels == 0) {
223+
return -EINVAL;
224+
}
225+
if ((data->channels & seq->channels) != seq->channels) {
226+
return -EINVAL;
227+
}
228+
229+
ret = Wrap_MXC_ADC_AverageConfig(seq->oversampling);
230+
if (ret != 0) {
231+
return -EINVAL;
232+
}
233+
234+
data->ctx.asynchronous = 1;
235+
data->sample_channels = seq->channels;
236+
237+
/* Here we use regular cb that does nothing, it should be
238+
* adc_complete_rtio_cb but the problem is dev struct
239+
* cannot be passed to HAL without some big changes
240+
* in the HAL layers, for now it is set like this
241+
*/
242+
ret = Wrap_MXC_ADC_StartConversionAsyncStream(&data->sample_channels, adc_complete_cb);
243+
if (ret != 0) {
244+
return -EINVAL;
245+
}
246+
247+
return adc_context_wait_for_completion(&data->ctx);
248+
}
249+
250+
void adc_max32_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
251+
{
252+
struct max32_adc_data *data = (struct max32_adc_data *)dev->data;
253+
const struct adc_read_config *read_cfg = iodev_sqe->sqe.iodev->data;
254+
int rc;
255+
256+
if (data->no_mem == 1) {
257+
data->no_mem = 0;
258+
return;
259+
}
260+
data->sqe = iodev_sqe;
261+
262+
adc_context_lock(&data->ctx, false, NULL);
263+
rc = start_read_stream(dev, read_cfg->sequence);
264+
265+
adc_context_release(&data->ctx, rc);
266+
267+
if (rc < 0) {
268+
LOG_ERR("Error starting conversion (%d)", rc);
269+
}
270+
}
271+
272+
static const uint32_t adc_max32_resolution[] = {
273+
[MAX32_12B_MODE] = 12,
274+
};
275+
276+
static inline int adc_max32_convert_q31(q31_t *out, const uint8_t *buff,
277+
enum max32_qscale_modes mode, uint8_t diff_mode,
278+
uint16_t vref_mv, uint8_t adc_shift)
279+
{
280+
int32_t data_in = 0;
281+
uint32_t scale = BIT(adc_max32_resolution[mode]);
282+
283+
/* No Differential mode */
284+
if (diff_mode) {
285+
return -EINVAL;
286+
}
287+
288+
uint32_t sensitivity = (vref_mv * (scale - 1)) / scale
289+
* 1000 / scale; /* uV / LSB */
290+
291+
if (mode == MAX32_12B_MODE) {
292+
data_in = (buff[1] << 8) | buff[0];
293+
if (diff_mode && (data_in & (BIT(adc_max32_resolution[mode] - 1)))) {
294+
data_in |= ~BIT_MASK(adc_max32_resolution[mode]);
295+
}
296+
} else {
297+
data_in = sys_get_be16(buff);
298+
}
299+
300+
*out = BIT(31 - adc_shift) * sensitivity / 1000000 * data_in;
301+
return 0;
302+
}
303+
304+
static int adc_max32_decoder_get_frame_count(const uint8_t *buffer, uint32_t channel,
305+
uint16_t *frame_count)
306+
{
307+
const struct adc_max32_fifo_data *data = (const struct adc_max32_fifo_data *)buffer;
308+
309+
*frame_count = data->fifo_byte_count/ADC_MAX32_SAMPLE_SIZE;
310+
311+
return 0;
312+
}
313+
314+
static int adc_max32_decoder_decode(const uint8_t *buffer, uint32_t channel, uint32_t *fit,
315+
uint16_t max_count, void *data_out)
316+
{
317+
const struct adc_max32_fifo_data *enc_data = (const struct adc_max32_fifo_data *)buffer;
318+
const uint8_t *buffer_end =
319+
buffer + sizeof(struct adc_max32_fifo_data) + enc_data->fifo_byte_count;
320+
int count = 0;
321+
uint8_t sample_num = 0;
322+
323+
if (buffer_end <= (buffer + *fit + sizeof(struct adc_max32_fifo_data))) {
324+
return 0;
325+
}
326+
327+
struct adc_data *data = (struct adc_data *)data_out;
328+
329+
memset(data, 0, sizeof(struct adc_data));
330+
data->header.base_timestamp_ns = enc_data->timestamp;
331+
data->header.reading_count = 1;
332+
333+
/* 32 is used because input parameter for __builtin_clz func is
334+
* unsigneg int (32 bits) and func will consider any input value
335+
* as 32 bit.
336+
*/
337+
data->shift = 32 - __builtin_clz(enc_data->vref_mv);
338+
339+
buffer += sizeof(struct adc_max32_fifo_data);
340+
uint8_t sample_set_size = enc_data->sample_set_size;
341+
/* Calculate which sample is decoded. */
342+
if (*fit) {
343+
sample_num = *fit / sample_set_size;
344+
}
345+
346+
while (count < max_count && buffer < buffer_end) {
347+
/* 125 KSPS - this can be calculated from
348+
* cnt and idle dts parameters but it is hardcoded for now
349+
*/
350+
data->readings[count].timestamp_delta = sample_num * (UINT32_C(1000000000) / 62500);
351+
adc_max32_convert_q31(&data->readings[count].value, (buffer + *fit),
352+
enc_data->max32_qscale_mode, enc_data->diff_mode,
353+
enc_data->vref_mv, data->shift);
354+
355+
sample_num++;
356+
*fit += sample_set_size;
357+
count++;
358+
}
359+
360+
return 0;
361+
362+
}
363+
#endif /* CONFIG_ADC_MAX32_STREAM */
364+
153365
#ifdef CONFIG_ADC_ASYNC
154366
static int adc_max32_read_async(const struct device *dev, const struct adc_sequence *seq,
155367
struct k_poll_signal *async)
@@ -276,6 +488,73 @@ static int adc_max32_init(const struct device *dev)
276488
return 0;
277489
}
278490

491+
#ifdef CONFIG_ADC_MAX32_STREAM
492+
static void adc_max32_rtio_isr(const struct device *dev)
493+
{
494+
struct max32_adc_data *const data = dev->data;
495+
uint32_t flags = MXC_ADC_GetFlags();
496+
uint32_t int_req = BIT(3);
497+
498+
MXC_ADC_Handler();
499+
if (flags & int_req) {
500+
MXC_ADC_Free();
501+
}
502+
MXC_ADC_ClearFlags(flags);
503+
504+
if (flags & WRAP_MXC_F_ADC_CONV_DONE_IF) {
505+
506+
data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks());
507+
508+
const size_t min_read_size = 64;
509+
510+
uint8_t *buf;
511+
uint32_t buf_len;
512+
513+
if (rtio_sqe_rx_buf(data->sqe, min_read_size, min_read_size,
514+
&buf, &buf_len) != 0) {
515+
data->no_mem = 1;
516+
rtio_iodev_sqe_err(data->sqe, -ENOMEM);
517+
return;
518+
}
519+
struct adc_max32_fifo_data *hdr = (struct adc_max32_fifo_data *)buf;
520+
521+
hdr->is_fifo = 1;
522+
hdr->timestamp = data->timestamp;
523+
hdr->vref_mv = MAX32_ADC_VREF_MV;
524+
hdr->max32_qscale_mode = MAX32_12B_MODE;
525+
hdr->fifo_byte_count = ADC_MAX32_BYTE_COUNT;
526+
hdr->sample_set_size = ADC_MAX32_SAMPLE_SIZE;
527+
528+
uint8_t *read_buf = buf + sizeof(*hdr);
529+
530+
Wrap_MXC_ADC_GetData((uint16_t **)&read_buf);
531+
532+
if (data->sample_channels != 0) {
533+
adc_max32_start_channel(dev);
534+
} else {
535+
Wrap_MXC_ADC_DisableConversion();
536+
adc_context_on_sampling_done(&data->ctx, dev);
537+
}
538+
}
539+
if (flags & int_req) {
540+
541+
adc_complete_rtio_cb(dev);
542+
}
543+
}
544+
545+
ADC_DECODER_API_DT_DEFINE() = {
546+
.get_frame_count = adc_max32_decoder_get_frame_count,
547+
.decode = adc_max32_decoder_decode,
548+
};
549+
550+
int adc_max32_get_decoder(const struct device *dev, const struct adc_decoder_api **api)
551+
{
552+
ARG_UNUSED(dev);
553+
*api = &ADC_DECODER_NAME();
554+
555+
return 0;
556+
}
557+
#else
279558
static void adc_max32_isr(const struct device *dev)
280559
{
281560
struct max32_adc_data *const data = dev->data;
@@ -295,6 +574,7 @@ static void adc_max32_isr(const struct device *dev)
295574
}
296575
}
297576
}
577+
#endif /* CONFIG_ADC_MAX32_STREAM */
298578

299579
static DEVICE_API(adc, adc_max32_driver_api) = {
300580
.channel_setup = adc_max32_channel_setup,
@@ -303,14 +583,21 @@ static DEVICE_API(adc, adc_max32_driver_api) = {
303583
.read_async = adc_max32_read_async,
304584
#endif /* CONFIG_ADC_ASYNC */
305585
.ref_internal = MAX32_ADC_VREF_MV,
586+
#ifdef CONFIG_ADC_MAX32_STREAM
587+
.submit = adc_max32_submit_stream,
588+
.get_decoder = adc_max32_get_decoder,
589+
#endif /* CONFIG_ADC_MAX32_STREAM */
306590
};
307591

308592
#define MAX32_ADC_INIT(_num) \
309593
PINCTRL_DT_INST_DEFINE(_num); \
310594
static void max32_adc_irq_init_##_num(void) \
311595
{ \
312-
IRQ_CONNECT(DT_INST_IRQN(_num), DT_INST_IRQ(_num, priority), adc_max32_isr, \
313-
DEVICE_DT_INST_GET(_num), 0); \
596+
COND_CODE_1(CONFIG_ADC_MAX32_STREAM, \
597+
(IRQ_CONNECT(DT_INST_IRQN(_num), DT_INST_IRQ(_num, priority), adc_max32_rtio_isr, \
598+
DEVICE_DT_INST_GET(_num), 0)), \
599+
(IRQ_CONNECT(DT_INST_IRQN(_num), DT_INST_IRQ(_num, priority), adc_max32_isr, \
600+
DEVICE_DT_INST_GET(_num), 0))); \
314601
irq_enable(DT_INST_IRQN(_num)); \
315602
}; \
316603
static const struct max32_adc_config max32_adc_config_##_num = { \
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2023-2024 Analog Devices, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ADI MAX32 ADC that supports revB and me18
5+
6+
compatible: "adi,max32-adc-b-me18"
7+
8+
include: adi,max32-adc.yaml

west.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ manifest:
144144
groups:
145145
- fs
146146
- name: hal_adi
147-
revision: d2886b8b8e3f71058a221f6351a8200fba80f229
147+
revision: 15a333d46cea1bb9d34f5f3deba4c255fd652528
148148
path: modules/hal/adi
149149
groups:
150150
- hal

0 commit comments

Comments
 (0)