C语言模拟 DMA原理演示

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

// 定义常量
#define MEM_SIZE 256        // 模拟内存大小
#define MAX_TRANSFER_SIZE 64 // 最大传输字节数

// 模拟内存数组
uint8_t source_memory[MEM_SIZE];
uint8_t dest_memory[MEM_SIZE];

// DMA 控制寄存器结构体
typedef struct {
    uint32_t source_addr;      // 源地址
    uint32_t dest_addr;        // 目标地址
    uint16_t transfer_size;    // 传输字节数
    bool enable;               // DMA 使能位
    bool interrupt_enable;     // 中断使能位
    bool done;                 // 传输完成标志
} DMA_Control;

// DMA 模块结构体
typedef struct {
    DMA_Control control;       // 控制寄存器
    bool interrupt_pending;    // 中断状态
} DMA_Module;

// 全局 DMA 模块实例
DMA_Module dma;

// 初始化 DMA 模块
void dma_init(void) {
    memset(&dma, 0, sizeof(DMA_Module));
    dma.control.enable = false;
    dma.control.interrupt_enable = false;
    dma.control.done = false;
    dma.interrupt_pending = false;
}

// 配置 DMA 传输
bool dma_configure(uint32_t src, uint32_t dst, uint16_t size) {
    // 校验参数
    if (size > MAX_TRANSFER_SIZE || size == 0) {
        printf("错误:无效的传输大小\n");
        return false;
    }
    if (src + size > MEM_SIZE || dst + size > MEM_SIZE) {
        printf("错误:超出内存范围\n");
        return false;
    }

    // 设置控制寄存器
    dma.control.source_addr = src;
    dma.control.dest_addr = dst;
    dma.control.transfer_size = size;
    dma.control.done = false;
    dma.interrupt_pending = false;
    
    return true;
}

// 启动 DMA 传输
void dma_start(void) {
    if (!dma.control.enable) {
        dma.control.enable = true;
        // 模拟突发传输
        memcpy(&dest_memory[dma.control.dest_addr],
               &source_memory[dma.control.source_addr],
               dma.control.transfer_size);
        
        // 标记传输完成
        dma.control.done = true;
        dma.control.enable = false;
        
        // 如果使能中断则设置中断
        if (dma.control.interrupt_enable) {
            dma.interrupt_pending = true;
        }
    }
}

// 检查 DMA 传输是否完成
bool dma_is_done(void) {
    return dma.control.done;
}

// 检查并清除中断
bool dma_check_interrupt(void) {
    bool pending = dma.interrupt_pending;
    dma.interrupt_pending = false;
    return pending;
}

// 使能/禁止中断
void dma_set_interrupt(bool enable) {
    dma.control.interrupt_enable = enable;
}

// 用测试数据初始化内存
void init_memory(void) {
    for (int i = 0; i < MEM_SIZE; i++) {
        source_memory[i] = (uint8_t)i; // 源内存填充递增值
        dest_memory[i] = 0;           // 目标内存清零
    }
}

// 打印内存内容
void print_memory(uint32_t start, uint32_t size) {
    printf("内存内容:\n");
    for (uint32_t i = start; i < start + size; i++) {
        printf("地址 %u: 源 = %u, 目标 = %u\n",
               i, source_memory[i], dest_memory[i]);
    }
}

// 测试程序
int main(void) {
    // 初始化 DMA 和内存
    dma_init();
    init_memory();
    
    // 配置 DMA 传输
    uint32_t src_addr = 0;
    uint32_t dst_addr = 100;
    uint16_t size = 16;
    
    printf("配置 DMA: 源=%u, 目标=%u, 大小=%u\n",
           src_addr, dst_addr, size);
    
    if (!dma_configure(src_addr, dst_addr, size)) {
        printf("DMA 配置失败\n");
        return 1;
    }
    
    // 使能中断并启动传输
    dma_set_interrupt(true);
    dma_start();
    
    // 等待传输完成
    while (!dma_is_done()) {
        // 模拟轮询
    }
    
    // 检查中断
    if (dma_check_interrupt()) {
        printf("DMA 传输完成(中断)\n");
    }
    
    // 校验结果
    print_memory(dst_addr, size);
    
    // 检查数据是否正确传输
    bool success = true;
    for (uint32_t i = 0; i < size; i++) {
        if (dest_memory[dst_addr + i] != source_memory[src_addr + i]) {
            success = false;
            break;
        }
    }
    
    printf("传输%s\n", success ? "成功" : "失败");
    
    return 0;
}

DMA 模块设计文档

1. 功能描述

本 DMA(直接内存访问)模块是一个用于教学目的的简化 C 语言仿真。它模拟了 DMA 控制器的基本功能,实现了在无需 CPU 干预的情况下,在两个内存区域之间进行数据传输。主要特性包括:

  • 突发模式传输:一次性传输一块数据(最多 64 字节)。
  • 可配置参数:支持用户自定义源地址、目标地址和传输大小。
  • 中断仿真:传输完成后可选择产生中断信号。
  • 控制/状态接口:使用结构体模拟硬件寄存器进行配置和状态监控。
  • 内存模型:用 C 数组模拟源内存和目标内存。

该模块设计简洁,避免了复杂的硬件细节(如时序或总线协议),适合初学者学习嵌入式系统相关概念。

2. 主要函数与数据结构

数据结构

  • DMA_Control 结构体
    • source_addr (uint32_t):源内存地址
    • dest_addr (uint32_t):目标内存地址
    • transfer_size (uint16_t):传输字节数
    • enable (bool):DMA 使能/禁止
    • interrupt_enable (bool):中断使能/禁止
    • done (bool):传输完成标志
  • DMA_Module 结构体
    • control (DMA_Control):控制与状态寄存器
    • interrupt_pending (bool):中断状态标志
  • 内存数组
    • source_memory (uint8_t[256]):模拟源内存
    • dest_memory (uint8_t[256]):模拟目标内存

函数

  • dma_init():初始化 DMA 模块,重置所有寄存器
  • dma_configure(src, dst, size):配置 DMA 的源、目标和大小,并校验输入
  • dma_start():启动突发传输,使用 memcpy 模拟数据移动
  • dma_is_done():检查传输是否完成
  • dma_check_interrupt():检查并清除中断状态
  • dma_set_interrupt(enable):使能/禁止中断
  • init_memory():用测试数据初始化源内存并清零目标内存
  • print_memory(start, size):显示内存内容以便验证

3. DMA 工作流程

  1. 初始化
    • 调用 dma_init() 重置 DMA 模块
    • 用 init_memory() 初始化内存以便测试
  2. 配置
    • 调用 dma_configure(src, dst, size) 设置传输参数
    • 校验地址和大小,确保在合法范围内
  3. 传输
    • 如需中断,先用 dma_set_interrupt(true) 使能
    • 调用 dma_start() 执行突发传输(用 memcpy 仿真)
    • 设置 done 标志,如使能中断则触发中断
  4. 完成检查
    • 轮询 dma_is_done() 或用 dma_check_interrupt() 检查完成状态
  5. 结果验证
    • 用 print_memory() 检查结果
    • 比较源数据和目标数据,验证传输正确性

4. 测试用例

提供的 main() 函数演示了完整的 DMA 传输流程:

  • 初始化:初始化 DMA 和内存,源内存填充递增值(0, 1, 2, ...)
  • 配置:配置从地址 0 到地址 100 的 16 字节传输
  • 执行:使能中断,启动传输,等待完成
  • 验证:打印目标内存内容,并检查数据是否与源一致
  • 预期输出
    • 配置信息(源、目标、大小)
    • 传输完成时的中断提示
    • 显示已传输的数据内容(如 dest_memory[100]=0, dest_memory[101]=1, ...)
    • 若数据一致则输出“传输成功”
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值