这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 行业应用 » 汽车电子 » 【S32K146车规级MCU】S32DS DMA 配置使用

共1条 1/1 1 跳转至

【S32K146车规级MCU】S32DS DMA 配置使用

工程师
2025-02-27 07:54:52     打赏

简介:

       S32K DMA 模块可以在发送数据时无需CPU搬运数据,释放CPU从而提高运行效率,S32 DS 中DMA 的配置方法也比较简单,只需要简单的配置DMA 通路即可,之前适配串口的时候我们使用的中断的方式,我们以串口配置为例来说明DMA模块的使用。

DMA 通路配置

在S32DS 中配置UART RX/TX的DMA 参数配置,对应配置如下:

image.png

对应的配置会生成如下的DMA 配置代码:

/***********************************************************************************************************************
 * This file was generated by the S32 Configuration Tools. Any manual edits made to this file
 * will be overwritten if the respective S32 Configuration Tools is used to update this file.
 **********************************************************************************************************************/

/* clang-format off */
/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!GlobalInfo
product: Peripherals v11.0
processor: S32K146
package_id: S32K146_LQFP144
mcu_data: s32sdk_s32k1xx_rtm_401
processor_version: 0.0.0
functionalGroups:
- name: BOARD_InitPeripherals
  UUID: 2d0c0af7-dbe7-4f00-821a-837510d6ab4e
  called_from_default_init: true
  selectedCore: core0
 * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
/* clang-format on */

/*******************************************************************************
 * Included files 
 ******************************************************************************/
#include "peripherals_edma_config_1.h"

/*******************************************************************************
 * edma_config_1 initialization code
 ******************************************************************************/
/* clang-format off */
/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
instance:
- name: 'edma_config_1'
- type: 'edma_config'
- mode: 'general'
- custom_name_enabled: 'false'
- type_id: 'edma'
- functional_group: 'BOARD_InitPeripherals'
- peripheral: 'EDMA'
- config_sets:
  - edma_driver:
    - settings_edmaUserCfg:
      - userStateStruct: 'dmaController_State'
      - userCfgName: 'dmaController_InitConfig'
      - readOnly: 'true'
      - chnArbitration: 'EDMA_ARBITRATION_FIXED_PRIORITY'
      - haltOnError: 'false'
    - settings_array_edmaChCfg:
      - array_chCfgStructs:
        - 0:
          - chStateStructName: 'dmaControllerChn0_State'
          - chConfigName: 'dmaControllerChn0_Config'
          - chType: 'edma_channel_config_t'
          - virtCh: '0'
          - chPrio: 'EDMA_CHN_DEFAULT_PRIORITY'
          - chReq: 'EDMA_REQ_LPUART1_RX'
          - chCallback: 'NULL'
          - chCallbackParam: 'NULL'
          - enableTrigger: 'false'
        - 1:
          - chStateStructName: 'dmaControllerChn1_State'
          - chConfigName: 'dmaControllerChn1_Config'
          - chType: 'edma_channel_config_t'
          - virtCh: '1'
          - chPrio: 'EDMA_CHN_DEFAULT_PRIORITY'
          - chReq: 'EDMA_REQ_LPUART1_TX'
          - chCallback: 'NULL'
          - chCallbackParam: 'NULL'
          - enableTrigger: 'false'
 * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
/* clang-format on */

/**
 * @page misra_violations MISRA-C:2012 violations
 *
 * @section [global]
 * Violates MISRA 2012 Advisory Rule 8.7, External variable could be made static.
 * The external variables will be used in other source files in application code.
 *
 */
edma_state_t dmaController_State;

edma_chn_state_t dmaControllerChn0_State;

edma_chn_state_t dmaControllerChn1_State;

edma_chn_state_t * const edmaChnStateArray[] = {
    &dmaControllerChn0_State,
    &dmaControllerChn1_State,
};

edma_channel_config_t dmaControllerChn0_Config = {
    .channelPriority = EDMA_CHN_DEFAULT_PRIORITY,
    .virtChnConfig = EDMA_CHN0_NUMBER,
    .source = EDMA_REQ_LPUART1_RX,
    .callback = NULL,
    .callbackParam = NULL,
    .enableTrigger = false,
};

edma_channel_config_t dmaControllerChn1_Config = {
    .channelPriority = EDMA_CHN_DEFAULT_PRIORITY,
    .virtChnConfig = EDMA_CHN1_NUMBER,
    .source = EDMA_REQ_LPUART1_TX,
    .callback = NULL,
    .callbackParam = NULL,
    .enableTrigger = false,
};

const edma_channel_config_t * const edmaChnConfigArray[] = {
    &dmaControllerChn0_Config,
    &dmaControllerChn1_Config,
};

const edma_user_config_t dmaController_InitConfig = {
    .chnArbitration = EDMA_ARBITRATION_FIXED_PRIORITY,
    .haltOnError = false
};

UART DMA参数配置

上面已经配置好了DMA 的传输通道,我们在UART的配置中选择使用DMA及通信的通路。

image.png

至此就完成UART 的DMA 配置,相对配置起来很简单。

UART 传输性能比较

我们之前的printf 输出使用的轮询非阻塞的方式传输,我们现在修改为DMA阻塞方式传输,我们添加如下测试代码来比较两种情况下连续输出10000次时CPU的使用率。

测试代码如下:

   for(int i = 0 ; i < 10000;i++)
       printf("hello world.\r\n");

   {
       extern unsigned int cpuusage(char argc,char ** argv);
       cpuusage(1,NULL);
   }

其中CPU 使用率的算法参照该文章(RA8使用perfcount计算freertos任务CPU使用率)在此就不额外赘述。

使用polling 方式时CPU 的使用率为81%

image.png

使用DMA 方式对应的使用率为28%,other 为中断等所占用的CPU使用,对应的使用率需要加上other 部分

image.png

从上面的数据可以看出DMA 相对polling的方式效率还是高很多,因为本地的DMA发送数据一次也是一字节发送本质上和中断的方式是没有区别的,要想进一步降低CPU使用率需使用DMA 一次多发送字节,降低中断次数来能相对中断发送进一步提高效率。

在此基础上我们继续修改代码,按照100字节为单位使用DMA来传输(本地debug 测试发现本地的环境__write每次按照一个字节喂数据来发送,使用最朴素的方式没有按照size 来填充buff ),这时CPU 的使用率明显下降,DMA比较适合大块数据传输的场景,会大大释放CPU的压力,从而提高效率。

size_t __write(int handle, const unsigned char *buffer, size_t size)
{
    static uint8_t buff[100];
    static uint8_t index;
    buff[index++] = buffer[0];
    
    if(index < 99)
      return 1;
    
    index = 0;
  
    status_t ret;
    do{
        ret = LPUART_DRV_SendDataBlocking(INST_LPUART_1,buff,100,500);
    }
    while( ret != STATUS_SUCCESS);

    return size;
}

image.png



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]