FreeRTOS中,MCU驱动DMA寄存器来操作RAM

文章详细描述了在FreeRTOS环境中,如何通过配置DMA控制器、设置中断、确定传输大小和启动传输,以及在RISC-V和STM32F4架构的MCU上操作DMA寄存器,将数据从GMAC传输到RAM的示例代码流程。
摘要由CSDN通过智能技术生成

在FreeRTOS中,MCU驱动DMA寄存器来操作RAM的代码流程通常包括以下几个步骤:

  1. 配置DMA控制器:首先,MCU需要配置DMA控制器以指定传输的源地址和目标地址。这通常涉及设置DMA的通道、传输方向以及数据宽度等参数。

  2. 配置DMA中断:如果需要在传输完成后触发中断,MCU还需要配置DMA中断。这可以通过设置DMA中断使能位以及设置中断优先级等参数来实现。

  3. 设置传输大小:MCU需要设置传输的数据长度,以告知DMA何时停止传输。这可以通过配置DMA的传输长度寄存器来实现。

  4. 启动DMA传输:一旦所有的配置都完成,MCU可以启动DMA传输。这可以通过设置DMA的使能位来实现。

  5. 等待传输完成:MCU需要等待DMA传输完成。这可以通过轮询DMA的状态标志位或者启用DMA中断来实现。

  6. 处理数据:一旦DMA传输完成,MCU可以开始处理RAM中的数据。这可能涉及到解析、处理或者传输数据等操作。

需要注意的是,具体的代码实现会根据MCU的型号和DMA控制器的不同而有所差异。因此,上述流程仅为一般性的示例。在实际应用中,您需要查阅MCU和DMA控制器的文档,以了解具体的寄存器配置和操作方式

以下是一个示例代码,展示了如何在FreeRTOS中使用DMA来进行数据传输,适用于RISC-V架构的MCU:

#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "riscv_hal.h"

#define BUFFER_SIZE 100

// 定义RAM的起始地址
#define RAM_ADDRESS 0x20000000

// 定义DMA传输完成标志
volatile uint8_t dmaTransferComplete = 0;

// 定义DMA传输完成中断处理函数
void DMA_TransferComplete_IRQHandler(void)
{
    // 清除DMA传输完成标志
    DMA_ClearInterrupt(DMA_CHANNEL);

    // 设置传输完成标志
    dmaTransferComplete = 1;
}

// 定义DMA初始化函数
void DMA_Init(void)
{
    // 使能DMA时钟
    DMA_EnableClock();

    // 配置DMA通道
    DMA_ConfigTypeDef dmaConfig;
    dmaConfig.channelNumber = DMA_CHANNEL;
    dmaConfig.sourceAddress = (uint32_t)&GMAC->GMAC_TSA; // 设置DMA的源地址为GMAC的寄存器地址
    dmaConfig.destinationAddress = RAM_ADDRESS; // 设置DMA的目标地址为RAM起始地址
    dmaConfig.transferSize = BUFFER_SIZE; // 设置DMA传输的数据长度
    dmaConfig.sourceIncrement = 0; // 外设地址不递增
    dmaConfig.destinationIncrement = 1; // 内存地址递增
    dmaConfig.sourceWidth = DMA_WIDTH_WORD; // 外设数据类型为32位
    dmaConfig.destinationWidth = DMA_WIDTH_WORD; // 内存数据类型为32位
    dmaConfig.transferMode = DMA_MODE_NORMAL; // 设置DMA传输模式为正常
    dmaConfig.priority = DMA_PRIORITY_HIGH; // 设置DMA优先级为高
    dmaConfig.sourceBurst = 1; // 一次只传输一个数据
    dmaConfig.destinationBurst = 1; // 一次只传输一个数据

    // 初始化DMA
    DMA_Init(DMA_CHANNEL, &dmaConfig);

    // 使能DMA传输完成中断
    DMA_EnableInterrupt(DMA_CHANNEL, DMA_INTERRUPT_TRANSFER_COMPLETE);

    // 配置DMA传输完成中断优先级
    NVIC_SetPriority(DMA_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
    NVIC_EnableIRQ(DMA_IRQ);
}

// 定义任务函数,用于启动DMA传输并等待传输完成
void DMA_TransferTask(void *pvParameters)
{
    // 初始化DMA
    DMA_Init();

    // 启动DMA传输
    DMA_StartTransfer(DMA_CHANNEL);

    // 等待传输完成
    while (!dmaTransferComplete)
    {
        taskYIELD(); // 释放CPU资源,运行其他任务
    }

    // 传输完成后的处理操作
    printf("DMA transfer completed.\n");

    vTaskDelete(NULL);
}

int main(void)
{
    xTaskCreate(DMA_TransferTask, "DMA_TransferTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    vTaskStartScheduler();

    return 0;
}

上述代码假设使用的是RISC-V架构的MCU,并且使用了DMA通道来进行数据传输。其中,DMA相关的初始化和配置操作在DMA_Init()函数中完成。任务函数DMA_TransferTask用于启动DMA传输并等待传输完成,传输完成后可以添加相应的数据处理操作。在传输完成中断处理函数DMA_TransferComplete_IRQHandler中,通过检查DMA传输完成标志来判断是否传输完成,并进行相应的处理操作。

请注意,上述代码仅为示例,实际应用中需要根据具体的MCU型号和DMA控制器的寄存器定义进行适当的修改。

----------------------------------------------------------------------------------------------------------------------------

以下是一个简单的示例代码,演示了如何在FreeRTOS中使用DMA来进行数据传输:

#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "stm32f4xx.h"

#define BUFFER_SIZE 100

// 定义RAM的起始地址
#define RAM_ADDRESS 0x20000000

// 定义DMA通道号
#define DMA_CHANNEL 1

// 定义DMA传输完成标志
volatile uint8_t dmaTransferComplete = 0;

// 定义DMA传输完成中断处理函数
void DMA_TransferComplete_IRQHandler(void)
{
    // 清除DMA传输完成标志
    DMA_ClearFlag(DMA_Channel, DMA_FLAG_TC);

    // 设置传输完成标志
    dmaTransferComplete = 1;
}

// 定义DMA初始化函数
void DMA_Init(void)
{
    // 使能DMA时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

    // 配置DMA通道
    DMA_InitTypeDef dmaInitStruct;
    dmaInitStruct.DMA_Channel = DMA_CHANNEL;
    dmaInitStruct.DMA_PeripheralBaseAddr = (uint32_t)&GMAC->GMAC_TSA; // 设置DMA的源地址为GMAC的寄存器地址
    dmaInitStruct.DMA_Memory0BaseAddr = RAM_ADDRESS; // 设置DMA的目标地址为RAM起始地址
    dmaInitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory; // 设置DMA传输方向为外设到内存
    dmaInitStruct.DMA_BufferSize = BUFFER_SIZE; // 设置DMA传输的数据长度
    dmaInitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增
    dmaInitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增
    dmaInitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; // 外设数据类型为32位
    dmaInitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; // 内存数据类型为32位
    dmaInitStruct.DMA_Mode = DMA_Mode_Normal; // 设置DMA传输模式为正常
    dmaInitStruct.DMA_Priority = DMA_Priority_High; // 设置DMA优先级为高
    dmaInitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; // 禁止FIFO模式
    dmaInitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    dmaInitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single; // 一次只传输一个数据
    dmaInitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 一次只传输一个数据

    // 初始化DMA
    DMA_Init(DMA_Channel, &dmaInitStruct);

    // 使能DMA传输完成中断
    DMA_ITConfig(DMA_Channel, DMA_IT_TC, ENABLE);

    // 配置DMA传输完成中断优先级
    NVIC_InitTypeDef nvicInitStruct;
    nvicInitStruct.NVIC_IRQChannel = DMA_Channel_IRQn;
    nvicInitStruct.NVIC_IRQChannelPreemptionPriority = configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1;
    nvicInitStruct.NVIC_IRQChannelSubPriority = 0;
    nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvicInitStruct);
}

// 定义任务函数,用于启动DMA传输并等待传输完成
void DMA_TransferTask(void *pvParameters)
{
    // 初始化DMA
    DMA_Init();

    // 启动DMA传输
    DMA_Cmd(DMA_Channel, ENABLE);

    // 等待传输完成
    while (!dmaTransferComplete)
    {
        taskYIELD(); // 释放CPU资源,允许其他任务运行
    }

    // 传输完成后的处理操作
    printf("DMA transfer completed.\n");

    vTaskDelete(NULL);
}

int main(void)
{
    xTaskCreate(DMA_TransferTask, "DMA_TransferTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    vTaskStartScheduler();

    return 0;
}

上述代码假设使用的是STM32F4系列的MCU,并且使用了DMA1通道1来进行数据传输。其中,DMA相关的初始化和配置操作在DMA_Init()函数中完成。任务函数DMA_TransferTask用于启动DMA传输并等待传输完成,传输完成后可以添加相应的数据处理操作。在传输完成中断处理函数DMA_TransferComplete_IRQHandler中,通过检查DMA传输完成标志来判断是否传输完成,并进行相应的处理操作。

请注意,上述代码仅为示例,实际应用中需要根据具体的MCU型号和DMA控制器的寄存器定义进行适当的修改。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

以下是一个示例代码,展示了FreeRTOS中RISC-V架构的MCU接收到GMAC接收以太网数据包的中断后,驱动DMA寄存器操作将数据搬运到RAM的指定位置的整个代码流程:

#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "riscv_hal.h"

#define BUFFER_SIZE 100

// 定义RAM的起始地址
#define RAM_ADDRESS 0x20000000

// 定义DMA传输完成标志
volatile uint8_t dmaTransferComplete = 0;

// 定义DMA初始化函数
void DMA_Init(void)
{
    // 使能DMA时钟
    DMA_EnableClock();

    // 配置DMA通道
    DMA_ConfigTypeDef dmaConfig;
    dmaConfig.channelNumber = DMA_CHANNEL;
    dmaConfig.sourceAddress = (uint32_t)&GMAC->GMAC_RDA; // 设置DMA的源地址为GMAC的寄存器地址
    dmaConfig.destinationAddress = RAM_ADDRESS; // 设置DMA的目标地址为RAM起始地址
    dmaConfig.transferSize = BUFFER_SIZE; // 设置DMA传输的数据长度
    dmaConfig.sourceIncrement = 0; // 外设地址不递增
    dmaConfig.destinationIncrement = 1; // 内存地址递增
    dmaConfig.sourceWidth = DMA_WIDTH_WORD; // 外设数据类型为32位
    dmaConfig.destinationWidth = DMA_WIDTH_WORD; // 内存数据类型为32位
    dmaConfig.transferMode = DMA_MODE_NORMAL; // 设置DMA传输模式为正常
    dmaConfig.priority = DMA_PRIORITY_HIGH; // 设置DMA优先级为高
    dmaConfig.sourceBurst = 1; // 一次只传输一个数据
    dmaConfig.destinationBurst = 1; // 一次只传输一个数据

    // 初始化DMA
    DMA_Init(DMA_CHANNEL, &dmaConfig);

    // 使能DMA传输完成中断
    DMA_EnableInterrupt(DMA_CHANNEL, DMA_INTERRUPT_TRANSFER_COMPLETE);
}

// 定义DMA传输完成中断处理函数
void DMA_TransferComplete_IRQHandler(void)
{
    // 清除DMA传输完成标志
    DMA_ClearInterrupt(DMA_CHANNEL);

    // 设置传输完成标志
    dmaTransferComplete = 1;

    // 唤醒等待传输完成的任务
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    vTaskNotifyGiveFromISR(NULL, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

// 定义任务函数,用于启动DMA传输并等待传输完成
void DMA_TransferTask(void *pvParameters)
{
    // 初始化DMA
    DMA_Init();

    // 启动DMA传输
    DMA_StartTransfer(DMA_CHANNEL);

    // 等待传输完成
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

    // 传输完成后的处理操作
    printf("DMA transfer completed.\n");

    // 在RAM的指定位置处理数据
    uint32_t *ramPtr = (uint32_t *)(RAM_ADDRESS + 0x100); // RAM指针偏移0x100字节
    for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++)
    {
        printf("Data[%d]: 0x%08X\n", i, *ramPtr++);
    }

    vTaskDelete(NULL);
}

int main(void)
{
    // 初始化中断控制器
    NVIC_Init();

    // 注册DMA传输完成中断处理函数
    NVIC_RegisterInterrupt(DMA_IRQ, DMA_TransferComplete_IRQHandler);

    xTaskCreate(DMA_TransferTask, "DMA_TransferTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    vTaskStartScheduler();

    return 0;
}

上述代码中,在DMA传输完成中断处理函数DMA_TransferComplete_IRQHandler中,除了清除DMA传输完成标志和设置传输完成标志外,还使用vTaskNotifyGiveFromISR函数唤醒等待传输完成的任务。

在任务函数DMA_TransferTask中,通过ulTaskNotifyTake函数等待传输完成的通知。一旦收到通知,任务会继续执行传输完成后的处理操作。

请注意,上述代码仅为示例,实际应用中需要根据具体的MCU型号和DMA控制器的寄存器定义进行适当的修改。另外,还需要根据具体的中断控制器和DMA控制器的操作方式进行相应的初始化和配置。

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值