Skip to content

ADE9113 driver for IMX6ULL#670

Open
xvuko wants to merge 10 commits into
masterfrom
xvuko/msh-36
Open

ADE9113 driver for IMX6ULL#670
xvuko wants to merge 10 commits into
masterfrom
xvuko/msh-36

Conversation

@xvuko

@xvuko xvuko commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Driver for continuous sample reading from 4 x ADE9113 connected in SPI chain on IMX6ULL

Description

Motivation and Context

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Chore (refactoring, style fixes, git/CI config, submodule management, no code logic changes)

How Has This Been Tested?

  • Already covered by automatic testing.
  • New test added: (add PR link here).
  • Tested by hand on: (list targets here).

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing linter checks and tests passed.
  • My changes generate no new compilation warnings for any of the targets.

Special treatment

  • This PR needs additional PRs to work (list the PRs, preferably in merge-order).
  • I will merge this PR by myself when appropriate.

Comment thread adc/ade9113/dma.c Outdated
@xvuko xvuko changed the title Xvuko/msh 36 ADE9113 driver for IMX6ULL Jun 2, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a Phoenix-RTOS driver for the ADE9113 ADC (4 chained chips), featuring command/response handling, IMX6ULL DMA support, a message API server, and a sample ring buffer. It also updates the IMX6ULL SDMA driver to support automatic buffer descriptor completion options and word-aligned memory access. Critical feedback identifies a potential deadlock in sampleRead due to a missing unlock on an error path, a null pointer dereference in the message API when handling inactive sessions, and an incorrect mmap failure check. Other high-to-medium severity issues include a compilation warning from returning a value in a void function, a resource leak in sample_init on allocation failure, a leftover debug condition in the monitor thread, and the need to use static inline void for sample_write to prevent linker issues.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread adc/ade9113/sample.c
Comment thread adc/ade9113/msgapi.c
Comment on lines +68 to +71
struct sampleReader *reader = NULL;
if ((msg.oid.id > 0) && (msg.oid.id <= MSGAPI_READER_COUNT)) {
reader = &ctx->readers[msg.oid.id - 1];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-critical critical

If a client sends mtRead or mtClose with a valid msg.oid.id but for a session that is not open or already closed, reader->ctx is NULL. Calling sample_readBlock or sample_readerClose on such a reader will dereference NULL and crash the driver. We should validate that the reader is active before processing.

		struct sampleReader *reader = NULL;
		if ((msg.oid.id > 0) && (msg.oid.id <= MSGAPI_READER_COUNT)) {
			reader = &ctx->readers[msg.oid.id - 1];
			if (reader->ctx == NULL) {
				reader = NULL;
			}
		}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added separate sample_readerInit function so that ctx is always valid

Comment thread adc/ade9113/main.c
Comment thread adc/ade9113/sample.c Outdated
Comment thread adc/ade9113/main.c Outdated
Comment thread adc/ade9113/sample.c
Comment on lines +124 to +152
int sample_init(struct sampleCtx *ctx, unsigned expSize, unsigned sampleSize)
{
if ((expSize > 31) || (((uint32_t)sampleSize >> expSize) > 0)) {
return -1;
}

*ctx = (struct sampleCtx) {
.written = 0,
.sampleSize = sampleSize,
.mask = ((uint32_t)1 << expSize) - 1,
.buffer = malloc((uint32_t)1 << expSize)
};

if (mutexCreate(&ctx->lock) < 0) {
fprintf(stderr, "mutex create failed");
assert(false);
return -1;
}
if (condCreate(&ctx->cond) < 0) {
fprintf(stderr, "cond create failed");
assert(false);
return -1;
}

if (ctx->buffer == NULL) {
fprintf(stderr, "failed to allocate sample buffer");
return -1;
}
return 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In sample_init, if malloc fails to allocate ctx->buffer, the function returns -1 but does not destroy the previously created ctx->lock and ctx->cond. Allocating the buffer first avoids this leak entirely.

int sample_init(struct sampleCtx *ctx, unsigned expSize, unsigned sampleSize)
{
	if ((expSize > 31) || (((uint32_t)sampleSize >> expSize) > 0)) {
		return -1;
	}

	uint8_t *buffer = malloc((uint32_t)1 << expSize);
	if (buffer == NULL) {
		fprintf(stderr, "failed to allocate sample buffer");
		return -1;
	}

	*ctx = (struct sampleCtx) {
		.written = 0,
		.sampleSize = sampleSize,
		.mask = ((uint32_t)1 << expSize) - 1,
		.buffer = buffer
	};

	if (mutexCreate(&ctx->lock) < 0) {
		fprintf(stderr, "mutex create failed");
		free(buffer);
		assert(false);
		return -1;
	}
	if (condCreate(&ctx->cond) < 0) {
		fprintf(stderr, "cond create failed");
		free(buffer);
		assert(false);
		return -1;
	}

	return 0;
}

Comment thread adc/ade9113/sample.h Outdated
Comment thread adc/ade9113/sample.c Outdated
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

Unit Test Results

10 860 tests  ±0   10 190 ✅ ±0   53m 22s ⏱️ +21s
   670 suites ±0      670 💤 ±0 
     1 files   ±0        0 ❌ ±0 

Results for commit 59c2073. ± Comparison against base commit bccac7e.

♻️ This comment has been updated with latest results.

@xvuko xvuko force-pushed the xvuko/msh-36 branch 3 times, most recently from 63f4fb7 to e464da1 Compare June 2, 2026 19:33
@xvuko xvuko requested a review from anglov June 2, 2026 19:35
@xvuko xvuko force-pushed the xvuko/msh-36 branch 2 times, most recently from f67967c to 6247513 Compare June 9, 2026 15:45

@anglov anglov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit with generated headers should be added before implementation

Comment thread adc/ade9113/iomux_mux_enums.h Outdated
@@ -0,0 +1,1273 @@
/* clang-format off */
/* Auto-generated from iomux_enum_defs.xml */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refering to non-existing file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed, added header. For now added scripts to internal repo.

Comment thread adc/ade9113/imx6ull.h

unsigned i;
for (i = 1; i < NUM_OF_SDMA_CHANNELS; i++) {
sdma_channel_t *channel = &cmn->channel[i];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactoring could be done in separate commit (ok as-is)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added separate commit

Comment thread adc/ade9113/msgapi.c Outdated
Comment thread adc/ade9113/dma.c Outdated


struct sdmaCtx {
volatile bool enabled;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: using this flag in interrupt is safe because operation on bool is atomic on arm.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to sig_atomic_t.

Comment thread adc/ade9113/main.c
Comment on lines +396 to +397
ade9113_writeRegs(&ade, ADE9113_SYNC_SNAP, ADE9113_SYNC_SNAP_ENC(.align = 1));
ade9113_writeRegs(&ade, ADE9113_SYNC_SNAP, ADE9113_SYNC_SNAP_ENC(.snapshot = 1));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why two transaction required?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment. This sequence is required in datasheet

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please expand this comment. As described in datasheet doesn't provide much context. Explain what's happening here or cite the relevant part of the datasheet.

Comment thread adc/ade9113/main.c Outdated
ADE9113_CONFIG0_ENC(.stream_dbg = args->dbgMode, .crc_en_spi_write = 1, .clkout_en = 0));

/* scratch values will be checked in DMA responses to ensure there is no shift */
ade9113_writeRegsDifferent(&ade, ADE9113_SCRATCH, 0xA0, 0xA1, 0xA2, 0xA3);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider
`SCRATCH_VALUE, SCRATCH_VALUE + 1, SCRATCH_VALUE + 2, SCRATCH_VALUE + 3'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to

/* value written to SCRATCH registers to verify reads (arbitrary unique value for each ADC chip) */
static const uint8_t scratchValues[4] = { 0xa0, 0xa1, 0xa2, 0xa3 };

Comment thread adc/ade9113/main.c Outdated

msgapi_init(&ctx->msgapi, &ctx->samples, "ade9113");

static uint8_t msgStacks[2][_PAGE_SIZE] __attribute__((aligned(16)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why alignment needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to 8. Kernel's HAL adds padding if to stack if not padded to 8.

Comment thread adc/ade9113/msgapi.c Outdated
msg.o.err = -EBUSY;

if (mutexLock(ctx->lock) < 0) {
msg.o.err = -ENOSYS;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird errno?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to -EIO as there is no better code for internal (non temporary) errors

Comment thread adc/ade9113/ade9113_regs.h Outdated
@@ -0,0 +1,557 @@
/* ADE9113 register and field definitions. */
/* Auto-generated from ade9113.svd - do not edit manually. */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how and where to find?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now internal devtools repo. Proper way to upstream this and provide headers via library should be considered.

xvuko added 7 commits June 24, 2026 17:17
TASK: MSH-36
SDMA commands GET_DM and SET_DM take size in 32 bit words.

TASK: MSH-36
Lock is always released inside condWait

TASK: MSH-36
There is no need to `DSPOVR`o register. IMX6 does not have DSP core. It
is set to 0xffffffff after reset and there is no need for any explicit
writes from driver. Line `DSPOVR |= 1 << channel_id` looks like it might
do something important. It does not. It makes `sdma_init_core` harder
to understand without any benefit.

TASK: MSH-36
xvuko added 2 commits June 26, 2026 19:33
BD_DONE flags indicate that SDMA "owns" buffer described in BD and can
write into it. When SDMA returns ownership to processor/driver buffer
content should be read *before* setting BD_DONE flag. This ensures data
integrity (no read / write collisions). This description assumes RX
transfer, but same applies to TX with read / writes swapped.

Automatic BD_DONE set can still be useful in some cases like sending
fixed buffer repeatedaly (like read requests from ADC).

Backwards incompatible.
Use `channelCfg.options = sdma_chOption__auto_bd_done` to keep old
behaviour.

TASK: MSH-36
@xvuko xvuko requested a review from ziemleszcz June 26, 2026 17:54
@xvuko xvuko marked this pull request as ready for review June 26, 2026 17:54
Comment thread adc/ade9113/ade9113.h
*
* SPDX-License-Identifier: BSD-3-Clause
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add header guard.

Comment thread adc/ade9113/imx6ull.h
* SPDX-License-Identifier: BSD-3-Clause
*/


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add header guard.

Comment thread adc/ade9113/msgapi.h
*/


#ifndef MSGAPI_H

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ADE9113_MSGAPI_H?

Comment thread adc/ade9113/sample.h
*/


#ifndef SAMPLE_H

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ADE9113_SAMPLE_H?

Comment thread adc/ade9113/log.h

#define log_error(fmt, ...) \
do { \
fprintf(stdout, LOG_TAG fmt "\n", ##__VA_ARGS__); \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stderr?

Comment thread adc/ade9113/log.h
fprintf(stdout, LOG_TAG fmt "\n", ##__VA_ARGS__); \
} while (0)

#define log_info(fmt, ...) log_error(fmt, ##__VA_ARGS__);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fprintf(stdout, ...)?

Comment thread adc/ade9113/main.c
0
| (0x01 << 23) /* RXDEN = 1 */
| (15 << 16) /* RX_THRESHOLD = 15 */
| (0x01 << 7) /* TXDEN = 1 */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TXDEN -> TEDEN

Comment thread adc/ade9113/main.c
ade9113_readRegs(&ade, ADE9113_CONFIG_CRC, values, sizeof(values));
bool ready = true;
for (int i = 0; i < 4; ++i) {
if ((values[i] & 0x01) == 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0x1 is CRC_FORCE. According to the datasheet, it's automatically cleared when CRC recalculation completes. Did you mean to check CRC_DONE (0x2) instead?

Comment thread adc/ade9113/main.c
Comment on lines +396 to +397
ade9113_writeRegs(&ade, ADE9113_SYNC_SNAP, ADE9113_SYNC_SNAP_ENC(.align = 1));
ade9113_writeRegs(&ade, ADE9113_SYNC_SNAP, ADE9113_SYNC_SNAP_ENC(.snapshot = 1));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please expand this comment. As described in datasheet doesn't provide much context. Explain what's happening here or cite the relevant part of the datasheet.

Comment thread adc/ade9113/main.c
ADE9113_SWRST__SOFTWARE_RESET_COMMAND,
ADE9113_SWRST__SOFTWARE_RESET_COMMAND,
ADE9113_SWRST__SOFTWARE_RESET_COMMAND);
usleep(300 * 1000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: consider polling STATUS0 for RESET_DONE instead of using a fixed usleep.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants