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

对应的配置会生成如下的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及通信的通路。

至此就完成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%

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

从上面的数据可以看出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;
}
我要赚赏金
