首页 » 智能 » STM32F1/F7运用HAL库DMA办法输出PWM详解_函数_数据

STM32F1/F7运用HAL库DMA办法输出PWM详解_函数_数据

乖囧猫 2024-10-21 13:13:23 0

扫一扫用手机浏览

文章目录 [+]

STM32F1系列有两个DMA,分别有7个通道和5个通道(Channel)。
F7系列每个DMA分别有8个数据流(StreamX),每个数据流对应8个通道(CHannel),这里轻微区分一下两个系列的表述,F1所说的Channel该当对应F7中的Stream。
例如DMA1的通道对应表如下。
STM32的ADC、SPI、IIS、USART、IIC、TIM、DAC等数据传输外设都可以设置为DMA办法传输,在手动配置的时候查表选择通道即可,当然如果用Cubemx工具的话就会自动选择了。

DMA传输有什么好处?举个例子,利用HAL_UART_Transmit()和HAL_UART_Transmit_DMA(),前者利用普通模式,CPU会进入实行函数,直到数据传输完成退出,然后才实行下一条指令。
后者利用DMA传输,DMA启动传输之后CPU就不管了,直接往下实行其他指令。
CPU干什么呢?只须要处理DMA传输完成、半传输完成、传输缺点等中断,或者通过查询寄存器检讨DMA传输到啥情形了。
是不是瞬间快起来了!

STM32F1/F7运用HAL库DMA办法输出PWM详解_函数_数据 智能

2. DMA办法输出PWM是怎么回事

利用DMA传输数据很好理解,为什么DMA可以掌握PWM脉冲数量和占空比呢?这里我们回归实质,在DMA掌握PWM输出的过程中,DMA依然传输的是数据,只不过它送过去的是比较值,即TIMx_CCRx的值,这个值不用多阐明了,和自动重装载寄存器(TIMx_ARR)的值分别决定周期和占空比。
看一下手册中定时器的DMA连续传送模式的阐明。

把稳黄色部分,什么是更新事宜?回顾一下,在向上计数模式下当计数到自动重装载值就会发生更新事宜(溢出)。
也便是说每单个PWM波结束后就会自动将比较值设置成DMA传输来的数据。
以本例设置的周期1ms为例,设置send_Buf[] = {10,20,30,…,100},终极的波形便是高电平时间分别为10,20,30,…100us的十个方波。
很大略有木有!

3. HAL库DMA配置PWM的几个函数

说实话利用HAL库还是有点弯弯绕,很多操作层层封装,可能用寄存器几句代码的事情到了HAL库要调用好几个函数转几道弯,但这也是大势所趋吧,将底层都封装起来,让用户专注于运用程序。
最近用Cubemx自动天生代码的觉得便是,真喷鼻香!

搬运stm32F7xx_hal_tim.h中的函数定义,以下分别因此壅塞模式、中断模式、DMA模式启动和停滞PWM。

HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef htim, uint32_t Channel);HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef htim, uint32_t Channel);HAL_StatusTypeDef HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef htim, uint32_t Channel);HAL_StatusTypeDef HAL_TIM_PWM_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef htim, uint32_t Channel, uint32_t pData, uint16_t Length);HAL_StatusTypeDef HAL_TIM_PWM_Stop_DMA(TIM_HandleTypeDef htim, uint32_t Channel);

以下是中断回调函数的声明,这里我们只关注void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef htim);每次PWM输出完成之后调用这个函数,在中断里面我们须要调用HAL_TIM_PWM_Stop_DMA(TIM_HandleTypeDef htim, uint32_t Channel)停滞DMA传输,否则它不会自己停滞的。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef htim);void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef htim);void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef htim);void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef htim);void HAL_TIM_TriggerCallback(TIM_HandleTypeDef htim);void HAL_TIM_ErrorCallback(TIM_HandleTypeDef htim);二. STM32CubeMx配置 DMA PWM

以STM32F1和F7系列板子为例进行测试,经由测试两者配置基本是一样的,结果也是一样,以是这里以F1为例讲解。

如图,新建基于STM32F103ZET6的工程,前辈行时钟配置,系统时钟设定到最大72MHz。

然后设置定时器,我利用的是T2,四个通道都选上了,根据须要来即可。
分频系数设为71,即72分频,pwm频率1MHz,自动重装载值为1000,得到周期为1ms.

接下来设置DMA,如图,四个通道DMA都选上了,这里CH2和CH4共用了一个通道,暂且不管它。

可以看到此时DMA中断已经开启

此外如果利用ST-Link下载程序,把稳图示这个地方设置debug模式为Serial Wire,不然会涌现ST-Link只能下载一次程序的情形。

到此设置完毕,点击GENERATE CODE即可。

三. 波形调试过程剖析

打开工程,可以看到TIM的初始化和DMA的初始化函数,这里在main函数中调用HAL_TIM_PWM_Start函数就可以正常输出连续波形了。

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1)

调用__HAL_TIM_SET_COMPARE函数可以改变占空比

__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,200);

如设置成200,则高电平时间为200us,占空比为200/1000。

由于我们要利用DMA办法,在main函数中定义一个发送数据缓冲区

#define NUM 21uint32_t send_Buf[NUM] = { 0};

在main函数中增加以下代码

for (i = 0; i < NUM; i++){ send_Buf[i] = 20 (i + 1);}while (1){ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET); HAL_Delay(200); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET); HAL_Delay(200); HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_3,(uint32_t)send_Buf,NUM);}

添加如下函数

// PWM DMA 完成回调函数void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef htim){ HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_3);}

这便是第一部分讲的须要在回调函数中调用HAL_TIM_PWM_Stop_DMA函数停滞PWM输出。
理论上讲到这里该当如我们所愿输出期望波形了,也便是占空比递增的21个波。
但遗憾的是我的波是这样的:

三个问题:(1)数据只有一半;(2)波的周期变成了正常的两倍(2ms)(3)末了一个数据跑到最前边了。

生气ing…

于是开始调bug,第一个问题创造了,由于HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef htim, uint32_t Channel, uint32_t pData, uint16_t Length);函数中的发送数据指针是指向32位的,我的send_Buf也是定义的32位,但是DMA传输我的设置是半字16位,如图示。

也便是从uint32_t pData开始指针每移一位,地址偏移两个字节。
这样就能阐明上面的第一二问题,由于希望传输的数据是{sendBuf[0],sendBuf[1], …,sendBuf[20]},实际传输的数据却是:sendBuf[0]低16位sendBuf[0]高16位(即0)…sendBuf[9]低16位sendBuf[9]高16位(即0)sendBuf[10]低16位

接下来修正传输字宽为Word(32)位,或者把send_Buf改为uint16_t型,经测试结果都对了,如图所示。
以是提醒朋友们,DMA传输位宽和定义的缓冲区位宽一定要同等!

DMA传输位宽和定义的缓冲区位宽一定要同等!

DMA传输位宽和定义的缓冲区位宽一定要同等!

问题3依然存在,于是把末了一个数据改为0试试,添加send_Buf[NUM - 1] = 0;波形正常了。

缘故原由尚不清楚,是不是由于DMA传输的起始和结束有什么不稳定成分,既然如此,那就每次在正常数据后面补一个或者多个0就行了。
不影相应用。

至此DMA掌握PWM输出成功,下一篇用HAL-DMA-PWM点亮WS2812灯珠。

标签:

相关文章

潜渊证,探索深海奥秘的科技利器

随着科技的不断发展,人类对海洋的探索愈发深入。深海,这个神秘而广阔的世界,蕴藏着无尽的奥秘。潜渊证,作为一种先进的深海探测技术,成...

智能 2025-01-06 阅读0 评论0