cancel
Showing results for 
Search instead for 
Did you mean: 

Problem: Bus Fault error when using ADC + DMA on STM32H747i with Zephyr OS

HuongNg
Visitor

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=y

 Overlay

/ {
    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));
	}
}
Please let me know any configuration/source code is miss.
Thanks in Advance!
 
0 REPLIES 0