DMA (Direct Memory Access) 允许外设直接与内存交换数据,无需 CPU 介入。
/* device tree example */
&dma {
status = "okay";
};
&spi0 {
dmas = <&dma 0>, <&dma 1>;
dma-names = "tx", "rx";
};
CONFIG_DMA=y
# 具体控制器配置取决于 SoC / 板卡
# 例如某些 STM32 平台会启用:
# CONFIG_DMAMUX_STM32=y
# CONFIG_STM32_DMA1=y
#include <zephyr/drivers/dma.h>
// 设备句柄
const struct device *dma_dev;
// 初始化 DMA
int dma_init(void) {
dma_dev = device_get_binding("DMA_0");
if (!dma_dev) {
return -ENODEV;
}
return 0;
}
struct dma_config cfg = {
.block_size = 256,
.channel_direction = MEMORY_TO_MEMORY,
.source_data_size = 1,
.dest_data_size = 1,
.source_burst_length = 1,
.dest_burst_length = 1,
.dma_slot = 0,
.channel_priority = 0,
};
uint8_t src_buf[256];
uint8_t dst_buf[256];
// 配置通道
int ret = dma_config(dma_dev, 0, &cfg);
if (ret) {
return ret;
}
// 启动传输
ret = dma_start(dma_dev, 0);
if (ret) {
return ret;
}
// 等待完成
k_sem_take(&dma_sem, K_FOREVER);
static void dma_callback(const struct device *dev, void *arg,
uint32_t channel, int status) {
if (status == 0) {
printk("DMA transfer complete\n");
}
k_sem_give(&dma_sem);
}
// 在配置中设置回调
cfg.callback = dma_callback;
&spi0 {
status = "okay";
dmas = <&dma 1>, <&dma 2>;
dma-names = "tx", "rx";
};
// SPI 发送数据(DMA 模式)
int spi_dma_send(const struct device *spi, uint8_t *tx_buf,
size_t len) {
struct spi_buf buf = {
.buf = tx_buf,
.len = len
};
struct spi_buf_set tx = {
.buffers = &buf,
.count = 1
};
return spi_write(spi, &spi_cfg, &tx);
}
&uart1 {
status = "okay";
dmas = <&dma 3>, <&dma 4>;
dma-names = "tx", "rx";
};
uint8_t rx_buf[256];
// 配置 DMA 接收
struct dma_config dma_cfg = {
.block_size = sizeof(rx_buf),
.channel_direction = PERIPHERAL_TO_MEMORY,
.dest_data_size = 1,
.source_data_size = 1,
};
// 启动 DMA 接收
dma_config(dma_dev, rx_channel, &dma_cfg);
memcpy(rx_buf, rx_dma_buf, sizeof(rx_buf));
dma_start(dma_dev, rx_channel);
&adc {
status = "okay";
dmas = <&dma 5>;
dma-names = "rx";
};
int16_t adc_buf[256];
// 读取 ADC(DMA 模式)
adc_read_async(adc_dev, &sequence, adc_buf, sizeof(adc_buf));
nRF 系列使用 EasyDMA,简化 DMA 配置:
/* 较新的 Nordic 平台通常会优先考虑 DPPI / nrfx 触发链路;
* 具体写法依 SoC 家族而定,不建议把旧 PPI 调用当成通用模板。
*/
# 查看 DMA 设备
ls /dev/dma*
# 内核日志
dmesg | grep dma