2026-01-20 9:19 PM
I'm trying to read ADC1 on channel 12 using ADC with DMA in a Zephyr OS environment, but I'm getting a BUS FAULT error when using the adc_read_async() API.
This is my prj.conf file
CONFIG_LOG=y
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_ADC=y
CONFIG_ADC_ASYNC=y
CONFIG_DMA=y
CONFIG_ADC_STM32_DMA=y
CONFIG_DMA_STM32=y
CONFIG_DMA_STM32U5=n
CONFIG_ARM_MPU=n
CONFIG_DCACHE=n
CONFIG_NO_OPTIMIZATIONS=y
CONFIG_CACHE_MANAGEMENT=y
CONFIG_NOCACHE_MEMORY=y
CONFIG_FAULT_DUMP=2
CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_ISR_STACK_SIZE=2048
CONFIG_ADC_LOG_LEVEL_DBG=y
CONFIG_DMA_LOG_LEVEL_DBG=yOverlay
/ {
zephyr,user {
io-channels = <&adc1 0>;
};
aliases {
adc1 = &adc1;
};
};
&dma1 {
status = "okay";
};
&dma2 {
status = "okay";
};
&dmamux1 {
status = "okay";
};
&adc1 {
status = "okay";
compatible = "st,stm32-adc";
st,adc-clock-source = "SYNC";
st,adc-prescaler = <4>;
// pinctrl-0 = <&adc1_in12_pc0>;
// pinctrl-names = "default";
dmas = <&dmamux1 0 9 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_MEM_INC | STM32_DMA_PRIORITY_HIGH | STM32_DMA_MEM_16BITS | STM32_DMA_PERIPH_16BITS)>;
// dma-names = "adc";
dma-names = "rx";
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>; /* Channel */
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,resolution = <16>;
zephyr,oversampling = <0>; /* Oversampling setting to be used for the channel. When specified, each sample is averaged from 2^N conversion results (where N is the provided value). */
};
};
main.c
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/dma.h>
#define LOG_LEVEL LOG_LEVEL_INF
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app);
#define ADC_NODE DT_PATH(zephyr_user)
static const struct adc_dt_spec adc_chan0 = ADC_DT_SPEC_GET_BY_IDX(ADC_NODE, 0);
const struct device *dma_dev = DEVICE_DT_GET(DT_NODELABEL(dmamux1));
struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig);
struct k_poll_event async_evt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &async_sig);
static int16_t sample_buffer[16] __aligned(32) __nocache;
static const struct adc_sequence_options options = {
.interval_us = 0,
.extra_samplings = 15,
.callback = NULL,
};
static struct adc_sequence sequence = {
.options = NULL,
.buffer = sample_buffer,
.buffer_size = sizeof(sample_buffer),
.resolution = 16,
};
int adc_dma_init(void) {
int err;
if (!adc_is_ready_dt(&adc_chan0.dev) || !device_is_ready(dma_dev)) {
LOG_INF("ADC controller device %s not ready\n",
adc_chan0.dev->name);
return 0;
}
if (adc_chan0.dev->api == NULL) {
LOG_ERR("ADC API is NULL - driver init/DMA binding failed!");
return -ENODEV;
}
err = adc_sequence_init_dt(&adc_chan0, &sequence);
if (err != 0) {
LOG_ERR("adc_read_async failed: %d", err);
return err;
}
LOG_INF("ADC initialized");
return 0;
}
int adc_dma_read_data(void) {
int err;
struct device *dev = adc_chan0.dev;
const struct adc_driver_api *api_ptr = (const struct adc_driver_api *)dev->api;
LOG_INF("API address: %p", api_ptr);
LOG_INF("read function: %p", api_ptr->read);
LOG_INF("read_async function: %p", api_ptr->read_async);
if (api_ptr->read_async == NULL) {
LOG_ERR("read_async is NULL! DMA not supported.");
return -ENOTSUP;
}
// LOG_INF("Starting blocking ADC read...");
// err = adc_read_dt(&adc_chan0, &sequence);
// if (err == 0) {
// LOG_INF("Blocking read OK");
// // sys_cache_data_invd_range(sample_buffer, sizeof(sample_buffer)); // safety
// LOG_HEXDUMP_INF(sample_buffer, sizeof(sample_buffer), "Blocking samples:");
// } else {
// LOG_ERR("adc_read_dt failed: %d", err);
// }
LOG_INF("Calling read_async...");
err = adc_read_async(&adc_chan0, &sequence, &async_sig); // note: use &adc_chan0 (dt_spec), not &adc_chan0.dev
if (err != 0) {
LOG_ERR("adc_read_async failed: %d", err);
return err;
}
LOG_INF("ADC conversion started, waiting for completion...");
// Wait for the signal (timeout 2 seconds)
struct k_poll_event events[1] = { async_evt };
err = k_poll(events, 1, K_MSEC(2000));
if (err == 0 && events[0].signal->signaled) {
// Optional: invalidate cache if you ever enable it later
// sys_cache_data_invd_range(sample_buffer, sizeof(sample_buffer));
LOG_INF("ADC conversion COMPLETE!");
LOG_HEXDUMP_INF(sample_buffer, sizeof(sample_buffer), "ADC samples:");
// Optional: convert first sample to mV (assuming single-ended, Vref=3300 mV)
int32_t raw = (int32_t)sample_buffer[0];
int32_t mv = (raw * 3300) / 65536; // for 16-bit resolution
LOG_INF("Channel 0: %d raw %d mV", raw, mv);
} else {
LOG_ERR("Timeout waiting for ADC completion: %d", err);
if (err == -EAGAIN) {
LOG_ERR("No signal raised (DMA/callback issue?)");
}
}
return err;
}
int main(void)
{
int err;
LOG_INF("Main app");
LOG_INF("DMA (Buffer Address): %p\n", (void *)sample_buffer);
LOG_INF("sequence Address: %p\n", &sequence);
adc_dma_init();
adc_dma_read_data();
while (1) {
k_sleep(K_MSEC(500));
}
}