I am trying to configure DMA to work with ADC. After building and flashing my program I get following messages:
[00:00:10.000,000] adc_sample_dma: Timer handler called
[00:00:10.000,000] adc_sample_dma: ADC work handler called
[00:00:10.000,000] adc_sample_dma: Source address: 0x42028040, Destination address: 0x20000cd8, Block size: 20
[00:00:10.000,000] adc_sample_dma: Source address adjustment: 2, Destination address adjustment: 0
[00:00:10.000,000] dma_stm32: dma_stm32_configure: Channel (1) src inc (0).
[00:00:10.000,000] dma_stm32: dma_stm32_configure: Channel (1) dest inc (80000).
[00:00:10.000,000] adc_sample_dma: Starting DMA transfer…
Strangely dest inc is set to 80000. here is my source code:
#include <zephyr/device.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(adc_sample_dma, LOG_LEVEL_INF);
#define ADC_NODE DT_NODELABEL(adc1)
#define ADC_CHANNEL_ID 3
#define BUFFER_SIZE 10
#define SAMPLE_INTERVAL K_SECONDS(10)
#define DMA_NODE DT_NODELABEL(gpdma1)
#define DMA_CHANNEL 1
static uint16_t adc_buffer[BUFFER_SIZE];
static const struct device *adc_dev;
static const struct device *dma_dev;
static struct dma_config dma_cfg;
static struct dma_block_config dma_block_cfg;
static struct k_timer my_timer;
static struct k_work adc_work;
static const struct adc_channel_cfg my_channel_cfg = {
.gain = ADC_GAIN_1,
.reference = ADC_REF_INTERNAL,
.acquisition_time = ADC_ACQ_TIME_DEFAULT,
.channel_id = ADC_CHANNEL_ID,
.differential = 0,
};
static void dma_callback(const struct device *dev, void *user_data, uint32_t channel, int status)
{
if (status == 0) {
LOG_INF("DMA transfer completed successfully.");
} else {
LOG_ERR("DMA transfer error: %d", status);
}
for (int i = 0; i < BUFFER_SIZE; i++) {
LOG_INF("adc_buffer[%d] = %d", i, adc_buffer[i]);
}
}
void adc_work_handler(struct k_work *work)
{
LOG_INF("ADC work handler called");
dma_block_cfg.source_address = (uint32_t)&ADC1->DR; // Assuming ADC1 is the ADC instance in use
dma_block_cfg.dest_address = (uint32_t)adc_buffer;
dma_block_cfg.block_size = BUFFER_SIZE * sizeof(adc_buffer[0]);
dma_block_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
dma_block_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
LOG_INF("Source address: 0x%08x, Destination address: 0x%08x, Block size: %d",
dma_block_cfg.source_address, dma_block_cfg.dest_address, dma_block_cfg.block_size);
LOG_INF("Source address adjustment: %d, Destination address adjustment: %d",
dma_block_cfg.source_addr_adj, dma_block_cfg.dest_addr_adj);
dma_cfg.head_block = &dma_block_cfg;
int ret;
ret = dma_stop(dma_dev, DMA_CHANNEL);
if (ret < 0 && ret != -EALREADY) {
LOG_ERR("Failed to stop DMA: %d", ret);
return;
}
ret = dma_config(dma_dev, DMA_CHANNEL, &dma_cfg);
if (ret < 0) {
LOG_ERR("Failed to configure DMA: %d", ret);
return;
}
LOG_INF("Starting DMA transfer...");
ret = dma_start(dma_dev, DMA_CHANNEL);
if (ret < 0) {
LOG_ERR("Failed to start DMA: %d", ret);
}
}
void timer_handler(struct k_timer *dummy)
{
LOG_INF("Timer handler called");
k_work_submit(&adc_work);
}
void main(void)
{
int ret;
LOG_INF("Initializing ADC...");
adc_dev = DEVICE_DT_GET(ADC_NODE);
if (!device_is_ready(adc_dev)) {
LOG_ERR("ADC device not ready");
return;
}
LOG_INF("Setting up ADC channel...");
ret = adc_channel_setup(adc_dev, &my_channel_cfg);
if (ret < 0) {
LOG_ERR("ADC channel setup failed with error %d", ret);
return;
}
LOG_INF("Initializing DMA...");
dma_dev = DEVICE_DT_GET(DMA_NODE);
if (!device_is_ready(dma_dev)) {
LOG_ERR("DMA device not ready");
return;
}
dma_cfg = (struct dma_config){
.channel_direction = PERIPHERAL_TO_MEMORY,
.complete_callback_en = true,
.error_callback_en = true,
.source_data_size = 2,
.dest_data_size = 2,
.source_burst_length = 1,
.dest_burst_length = 1,
.dma_callback = dma_callback,
.block_count = 1,
};
LOG_INF("Initializing timer...");
k_timer_init(&my_timer, timer_handler, NULL);
k_timer_start(&my_timer, SAMPLE_INTERVAL, SAMPLE_INTERVAL);
k_work_init(&adc_work, adc_work_handler);
LOG_INF("ADC sampling application with DMA has started.");
while (1) {
k_sleep(K_FOREVER);
}
}
I have tried to configure both, ADC and DMA directly in the source code using information from dma.h and adc.h, built and flashed the program on my stm32u5, but it did not work.