前言
RT-Thread 的pwm设备没有dma方式,目前项目中要使用ws281x,最开始直接配置了pwm+dma直接使用,但是不方便移植扩展,决定按照rtthread设备框架做一套PWM+DMA设备,由于项目时间比较紧目前仅测试了TIM3_CH1(项目里面用的就是这个通道)
目前已知问题,启动之后第一个脉冲是上次最后一个脉冲的波形,原因是:dma需要通道1去触发,然后定时器使能之后,会发出第一个脉冲,即上次设置的比较值。下个版本可以增加一个根据pwm模式,方向提前设置一下比较值,再启动dma。
不建议直接修改rt-thread库,可以先按照下面修改,成功之后再把这些修改文件移出去。
环境
- rt-thread 3.1.4
- stm32f407
修改RT-Thread库
1. 新建: rt-thread/ components / drivers / include / drivers /rt_drv_pwm_dma.h
/**
* @file drv_pwm_dma.h
* @author Jomb
* @brief
* @version 0.1
* @date 2022-08-05
*
* @copyright Copyright (c) 2022
*
*/
#ifndef __DRV_PWM_DMA_H_INCLUDE__
#define __DRV_PWM_DMA_H_INCLUDE__
#include <rtthread.h>
#include <rtdevice.h>
#define PWM_DMA_CMD_SET (128 + 0)
#define PWM_DMA_OCPOLARITY_HIGH 0
#define PWM_DMA_OCPOLARITY_LOW 2
struct rt_pwm_dma_configuration
{
rt_uint32_t period; /* unit:ns 1ns~4.29s:1Ghz~0.23hz */
rt_uint32_t pulse; /* unit:ns (pulse<=period) */
rt_uint16_t * mem;
rt_uint8_t polarity ;
};
struct rt_device_pwm_dma
{
struct rt_device parent; // inherit base A
struct rt_device_pwm * parent_pwm; //inherit base B
const struct rt_pwm_dma_ops *ops;
};
struct rt_device_pwm_dma;
struct rt_pwm_dma_ops
{
rt_err_t (*write)(struct rt_device_pwm_dma *device, const void *data, uint16_t size);
rt_err_t (*control)(struct rt_device_pwm_dma *device, int cmd, void *arg);
};
rt_err_t rt_device_pwm_dma_register(struct rt_device_pwm_dma *device, const char *name, const struct rt_pwm_dma_ops *ops, const void *user_data);
#endif /* __DRV_PWM_DMA_H_INCLUDE__ */
2. 新建:components/drivers/misc/rt_drv_pwm_dma.c
/**
* @file rt_drv_pwm_dma.c
* @author Jomb
* @brief
* @version 0.1
* @date 2022-08-08
*
* @copyright Copyright (c) 2022
*
*/
#include <string.h>
#include <drivers/rt_drv_pwm_dma.h>
static rt_err_t rt_pwm_dma_open(struct rt_device *dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t rt_pwm_dma_control(rt_device_t dev, int cmd, void *arg)
{
rt_err_t err = RT_EOK;
struct rt_device_pwm_dma *pwm_dma = (struct rt_device_pwm_dma *)dev;
if (pwm_dma->ops->control)
{
err = pwm_dma->ops->control(pwm_dma, cmd , arg);
}
return err;
}
static rt_size_t _pwm_dma_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
rt_size_t result = size;
rt_err_t err = RT_EOK;
struct rt_device_pwm_dma *pwm_dma = (struct rt_device_pwm_dma *)dev;
rt_uint32_t * compare = (rt_uint32_t *)buffer;
if (pwm_dma->ops->write)
{
err = pwm_dma->ops->write(pwm_dma, compare + pos , size);
if (err != RT_EOK)
{
return 0;
}
}
return result;
}
rt_err_t rt_device_pwm_dma_register(struct rt_device_pwm_dma *pwm_dma, const char *name, const struct rt_pwm_dma_ops *ops, const void *user_data)
{
rt_err_t result = RT_EOK;
struct rt_device *device;
RT_ASSERT(pwm_dma != NULL);
device = &(pwm_dma->parent);
rt_memset(device,0,sizeof(struct rt_device_pwm_dma));
device->tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->parent.ops = &rt_pwm_dma_ops;
#else
device->init = RT_NULL;
device->open = rt_pwm_dma_open;
device->close = RT_NULL;
device->read = RT_NULL;
device->write = _pwm_dma_write;
device->control = rt_pwm_dma_control;
#endif
device->parent.type = RT_Device_Class_Miscellaneous;
device->user_data = (void *)user_data;
pwm_dma->ops = ops;
result = rt_device_register(device, name, RT_DEVICE_FLAG_WRONLY);
return result;
}
修改: components/drivers/include/rtdevice.h
找个地方增加
#ifdef RT_USING_PWM_DMA
#include "drivers/rt_drv_pwm_dma.h"
#endif
修改驱动库
1. 新建:libraries/HAL_Drivers/drv_pwm_dma.c
只加了tim3_ch1,后面会补充
/**
* @file drv_pwm_dma.c
* @author Jomb
* @brief
* @version 0.1
* @date 2022-08-09
*
* @copyright Copyright (c) 2022
*
*/
#include <board.h>
#if defined(RT_USING_PWM_DMA) && defined(RT_USING_PWM)
#include "drv_config.h"
//#define DRV_DEBUG
#define LOG_TAG "drv.pwm.dma"
#include <drv_log.h>
enum
{
#ifdef BSP_TIM3_CH1_USING_DMA //
PWM3_DMA_INDEX,
#endif
/// XXX TODO: Other timer dma settings
};
enum
{
#ifdef BSP_TIM3_CH1_USING_DMA
PWM3_CH1_INDEX,
#endif
};
struct stm32_pwm_ch_dma
{
char *name;
char *parent_name;
DMA_HandleTypeDef tim_dma_handle;
struct rt_device_pwm_dma pwm_dma_device;
IRQn_Type irq;
char channel;
rt_uint16_t * mem; // dma 数据空间
};
static struct stm32_pwm_ch_dma stm32_pwm_ch_dma_obj[] =
{
#ifdef BSP_TIM3_CH1_USING_DMA
PWM3_DMA_CONFIG,
#endif
};
static rt_err_t drv_pwm_dma_write(struct rt_device_pwm_dma *device, const void *data, uint16_t size);
static rt_err_t drv_pwm_dma_control(struct rt_device_pwm_dma *device, int cmd, void *arg);
static const struct rt_pwm_dma_ops drv_ops =
{
drv_pwm_dma_write,
drv_pwm_dma_control};
#ifdef BSP_TIM3_CH1_USING_DMA
void TIM3_CH1_DMA_IRQHandler(void)
{
HAL_DMA_IRQHandler(&(stm32_pwm_ch_dma_obj[PWM3_CH1_INDEX].tim_dma_handle));
}
#endif
static rt_err_t drv_pwm_dma_write(struct rt_device_pwm_dma *device, const void *data, uint16_t size)
{
rt_err_t result = RT_EOK;
TIM_HandleTypeDef *htim = RT_NULL;
rt_device_t pwm_dev;
char channel = 0;
rt_uint64_t tim_clock, psc ,period;
rt_uint32_t * pulse_in = (rt_uint32_t *) data;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(((struct stm32_pwm_ch_dma*)(device->parent.user_data))->mem != RT_NULL);
rt_uint16_t * pulse_out = ((struct stm32_pwm_ch_dma*)(device->parent.user_data))->mem;
pwm_dev = rt_device_find(((struct stm32_pwm_ch_dma *)(device->parent.user_data))->parent_name);
if (pwm_dev == RT_NULL)
{
result = -RT_ERROR;
return result;
}
htim = (TIM_HandleTypeDef *)(pwm_dev->user_data);
channel = ((struct stm32_pwm_ch_dma *)(device->parent.user_data))->channel;
#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7)
if (htim->Instance == TIM9 || htim->Instance == TIM10 || htim->Instance == TIM11)
#elif defined(SOC_SERIES_STM32L4)
if (htim->Instance == TIM15 || htim->Instance == TIM16 || htim->Instance == TIM17)
#elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0)
if (0)
#endif
{
#if !defined(SOC_SERIES_STM32F0) && !defined(SOC_SERIES_STM32G0)
tim_clock = HAL_RCC_GetPCLK2Freq() * 2;
#endif
}
else
{
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0)
tim_clock = HAL_RCC_GetPCLK1Freq();
#else
tim_clock = HAL_RCC_GetPCLK1Freq() * 2;
#endif
}
tim_clock /= 1000000UL;
psc = htim->Init.Prescaler + 1;
period = htim->Init.Period + 1;
for (int i = 0; i < size ; i++)
{
pulse_out[i] = (unsigned long long)pulse_in[i] * tim_clock / psc / 1000ULL;
if (pulse_out[i] > period)
{
pulse_out[i] = period;
}
}
HAL_TIM_PWM_Start_DMA(htim, channel,(rt_uint32_t *)pulse_out, size);
return result;
}
static rt_err_t drv_pwm_dma_control(struct rt_device_pwm_dma *device, int cmd, void *arg)
{
rt_err_t result = RT_EOK;
struct rt_pwm_dma_configuration *configuration = (struct rt_pwm_dma_configuration *)arg;
struct rt_device_pwm *pwm_dev;
char channel = 0;
char polar = 0;
RT_ASSERT(configuration->mem != RT_NULL);
((struct stm32_pwm_ch_dma*)(device->parent.user_data))->mem = configuration->mem;
pwm_dev = (struct rt_device_pwm *)rt_device_find(((struct stm32_pwm_ch_dma *)(device->parent.user_data))->parent_name);
if (pwm_dev == RT_NULL)
{
result = -RT_ERROR;
return result;
}
channel = ((struct stm32_pwm_ch_dma *)(device->parent.user_data))->channel;
switch (cmd)
{
case PWM_DMA_CMD_SET:
polar = configuration->polarity;
__HAL_TIM_SET_CAPTUREPOLARITY((TIM_HandleTypeDef *)pwm_dev->parent.user_data, channel, polar );
return rt_pwm_set(pwm_dev, channel, configuration->period, configuration->pulse);
default:
return RT_EINVAL;
}
}
static rt_err_t stm32_hw_pwm_dma_init(struct stm32_pwm_ch_dma *device)
{
rt_err_t result = RT_EOK;
rt_device_t pwm_dev;
rt_uint8_t channel_dma_id = 0;
RT_ASSERT(device != RT_NULL);
if (rt_strcmp(device->parent_name, "pwm1") != 0 && rt_strcmp(device->parent_name, "pwm8") != 0)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
}
else
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
}
/* DMA interrupt init */
HAL_NVIC_SetPriority(device->irq, 0, 0);
HAL_NVIC_EnableIRQ(device->irq);
// find the parent class of pwm dma device
pwm_dev = rt_device_find(device->parent_name);
if (pwm_dev == RT_NULL)
{
result = -RT_ERROR;
return result;
}
// get the parent class point
device->pwm_dma_device.parent_pwm = (struct rt_device_pwm *)pwm_dev;
device->tim_dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;
device->tim_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;
device->tim_dma_handle.Init.MemInc = DMA_MINC_ENABLE;
device->tim_dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
device->tim_dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
device->tim_dma_handle.Init.Mode = DMA_NORMAL;
device->tim_dma_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH;
device->tim_dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&device->tim_dma_handle) != HAL_OK)
{
// Error_Handler();
result = -RT_ERROR;
return result;
}
/* Several peripheral DMA handle pointers point to the same DMA handle.
Be aware that there is only one stream to perform all the requested DMAs. */
switch (device->channel)
{
case TIM_CHANNEL_1:
channel_dma_id = TIM_DMA_ID_CC1;
break;
case TIM_CHANNEL_2:
channel_dma_id = TIM_DMA_ID_CC2;
break;
case TIM_CHANNEL_3:
channel_dma_id = TIM_DMA_ID_CC3;
break;
case TIM_CHANNEL_4:
channel_dma_id = TIM_DMA_ID_CC4;
break;
default:
break;
}
__HAL_LINKDMA((TIM_HandleTypeDef *)(pwm_dev->user_data), hdma[channel_dma_id], device->tim_dma_handle);
return result;
}
static int stm32_pwm_dma_init(void)
{
int i = 0;
int result = RT_EOK;
for (i = 0; i < sizeof(stm32_pwm_ch_dma_obj) / sizeof(stm32_pwm_ch_dma_obj[0]); i++)
{
if (stm32_hw_pwm_dma_init(&stm32_pwm_ch_dma_obj[i]) != RT_EOK)
{
result = -RT_ERROR;
goto __exit;
}
else
{
if (rt_device_pwm_dma_register(&stm32_pwm_ch_dma_obj[i].pwm_dma_device,
stm32_pwm_ch_dma_obj[i].name,
&drv_ops,
&stm32_pwm_ch_dma_obj[i]) == RT_EOK)
{
result = RT_EOK;
}
else
{
result = -RT_ERROR;
goto __exit;
}
}
}
__exit:
return result;
}
INIT_COMPONENT_EXPORT(stm32_pwm_dma_init); // Depends on pwm_dev init
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
char channel = 0;
switch (htim->Channel)
{
case HAL_TIM_ACTIVE_CHANNEL_1:
channel = TIM_CHANNEL_1;
break;
case HAL_TIM_ACTIVE_CHANNEL_2:
channel = TIM_CHANNEL_2;
break;
case HAL_TIM_ACTIVE_CHANNEL_3:
channel = TIM_CHANNEL_3;
break;
case HAL_TIM_ACTIVE_CHANNEL_4:
channel = TIM_CHANNEL_4;
break;
default:
break;
}
HAL_TIM_PWM_Stop_DMA(htim, channel);
}
#endif
2. 新建:libraries/HAL_Drivers/config/f4/pwm_dma_config.h
/**
* @file pwm_dma_config.h
* @author Jomb
* @brief
* @version 0.1
* @date 2022-08-09
*
* @copyright Copyright (c) 2022
*
*/
#ifndef __PWM_DMA_CONFIG_H__
#define __PWM_DMA_CONFIG_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef BSP_TIM3_CH1_USING_DMA
#ifndef PWM3_DMA_CONFIG
#define PWM3_DMA_CONFIG \
{ \
.name = "pwm3_dma_ch1", \
.parent_name = "pwm3", \
.tim_dma_handle.Instance = TIM3_CH1_DMA_INSTANCE,\
.tim_dma_handle.Init.Channel = TIM3_CH1_DMA_CHANNEL,\
.channel = TIM_CHANNEL_1, \
.irq = TIM3_CH1_DMA_IRQ,\
}
#endif /* PWM2_CONFIG */
#endif /* BSP_TIM3_CH1_USING_DMA */
#ifdef __cplusplus
}
#endif
#endif /* __PWM_CONFIG_H__ */
3. 修改libraries\HAL_Drivers\config\f4\dma_config.h
主要添加定时器通道对应dma流和通道,这里配置了一部分,还需要完善
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-01-02 zylx first version
* 2019-01-08 SummerGift clean up the code
*/
#ifndef __DMA_CONFIG_H__
#define __DMA_CONFIG_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
/* DMA1 stream0 */
#if defined(BSP_SPI3_RX_USING_DMA) && !defined(SPI3_RX_DMA_INSTANCE)
#define SPI3_DMA_RX_IRQHandler DMA1_Stream0_IRQHandler
#define SPI3_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define SPI3_RX_DMA_INSTANCE DMA1_Stream0
#define SPI3_RX_DMA_CHANNEL DMA_CHANNEL_0
#define SPI3_RX_DMA_IRQ DMA1_Stream0_IRQn
#elif defined(BSP_UART5_RX_USING_DMA) && !defined(UART5_RX_DMA_INSTANCE)
#define UART5_DMA_RX_IRQHandler DMA1_Stream0_IRQHandler
#define UART5_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART5_RX_DMA_INSTANCE DMA1_Stream0
#define UART5_RX_DMA_CHANNEL DMA_CHANNEL_4
#define UART5_RX_DMA_IRQ DMA1_Stream0_IRQn
#elif defined(BSP_UART8_TX_USING_DMA) && !defined(UART8_TX_DMA_INSTANCE)
#define UART8_DMA_TX_IRQHandler DMA1_Stream0_IRQHandler
#define UART8_TX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART8_TX_DMA_INSTANCE DMA1_Stream0
#define UART8_TX_DMA_CHANNEL DMA_CHANNEL_5
#define UART8_TX_DMA_IRQ DMA1_Stream0_IRQn
#elif defined(BSP_TIM4_CH1_USING_DMA) && !defined(TIM4_CH1_DMA_INSTANCE)
#define TIM4_CH1_DMA_IRQHandler DMA1_Stream0_IRQHandler
#define TIM4_CH1_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM4_CH1_DMA_INSTANCE DMA1_Stream0
#define TIM4_CH1_DMA_CHANNEL DMA_CHANNEL_2
#define TIM4_CH1_DMA_IRQ DMA1_Stream0_IRQn
#elif defined(BSP_TIM5_CH3_USING_DMA) && !defined(TIM5_CH3_DMA_INSTANCE)
#define TIM5_CH3_DMA_IRQHandler DMA1_Stream0_IRQHandler
#define TIM5_CH3_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM5_CH3_DMA_INSTANCE DMA1_Stream0
#define TIM5_CH3_DMA_CHANNEL DMA_CHANNEL_6
#define TIM5_CH3_DMA_IRQ DMA1_Stream0_IRQn
#endif
/* DMA1 stream1 */
#if defined(BSP_UART3_RX_USING_DMA) && !defined(UART3_RX_DMA_INSTANCE)
#define UART3_DMA_RX_IRQHandler DMA1_Stream1_IRQHandler
#define UART3_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART3_RX_DMA_INSTANCE DMA1_Stream1
#define UART3_RX_DMA_CHANNEL DMA_CHANNEL_4
#define UART3_RX_DMA_IRQ DMA1_Stream1_IRQn
#elif defined(BSP_UART7_RX_USING_DMA) && !defined(UART7_RX_DMA_INSTANCE)
#define UART7_DMA_RX_IRQHandler DMA1_Stream1_IRQHandler
#define UART7_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART7_RX_DMA_INSTANCE DMA1_Stream1
#define UART7_RX_DMA_CHANNEL DMA_CHANNEL_5
#define UART7_RX_DMA_IRQ DMA1_Stream1_IRQn
#elif defined(BSP_TIM5_CH4_USING_DMA) && !defined(TIM5_CH4_DMA_INSTANCE)
#define TIM5_CH4_DMA_IRQHandler DMA1_Stream1_IRQHandler
#define TIM5_CH4_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM5_CH4_DMA_INSTANCE DMA1_Stream1
#define TIM5_CH4_DMA_CHANNEL DMA_CHANNEL_6
#define TIM5_CH4_DMA_IRQ DMA1_Stream1_IRQn
#endif
/* DMA1 stream2 */
#if defined(BSP_SPI3_RX_USING_DMA) && !defined(SPI3_RX_DMA_INSTANCE)
#define SPI3_DMA_RX_IRQHandler DMA1_Stream2_IRQHandler
#define SPI3_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define SPI3_RX_DMA_INSTANCE DMA1_Stream2
#define SPI3_RX_DMA_CHANNEL DMA_CHANNEL_0
#define SPI3_RX_DMA_IRQ DMA1_Stream2_IRQn
#elif defined(BSP_UART4_RX_USING_DMA) && !defined(UART4_RX_DMA_INSTANCE)
#define UART4_DMA_RX_IRQHandler DMA1_Stream2_IRQHandler
#define UART4_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART4_RX_DMA_INSTANCE DMA1_Stream2
#define UART4_RX_DMA_CHANNEL DMA_CHANNEL_4
#define UART4_RX_DMA_IRQ DMA1_Stream2_IRQn
#elif defined(BSP_TIM3_CH4_USING_DMA) && !defined(TIM3_CH4_DMA_INSTANCE)
#define TIM3_CH4_DMA_IRQHandler DMA1_Stream2_IRQHandler
#define TIM3_CH4_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM3_CH4_DMA_INSTANCE DMA1_Stream2
#define TIM3_CH4_DMA_CHANNEL DMA_CHANNEL_5
#define TIM3_CH4_DMA_IRQ DMA1_Stream2_IRQn
#elif defined(BSP_TIM5_CH1_USING_DMA) && !defined(TIM5_CH1_DMA_INSTANCE)
#define TIM5_CH1_DMA_IRQHandler DMA1_Stream2_IRQHandler
#define TIM5_CH1_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM5_CH1_DMA_INSTANCE DMA1_Stream2
#define TIM5_CH1_DMA_CHANNEL DMA_CHANNEL_6
#define TIM5_CH1_DMA_IRQ DMA1_Stream2_IRQn
#endif
/* DMA1 stream3 */
#if defined(BSP_SPI2_RX_USING_DMA) && !defined(SPI2_RX_DMA_INSTANCE)
#define SPI2_DMA_RX_IRQHandler DMA1_Stream3_IRQHandler
#define SPI2_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define SPI2_RX_DMA_INSTANCE DMA1_Stream3
#define SPI2_RX_DMA_CHANNEL DMA_CHANNEL_0
#define SPI2_RX_DMA_IRQ DMA1_Stream3_IRQn
#elif defined(BSP_UART3_TX_USING_DMA) && !defined(UART3_TX_DMA_INSTANCE)
#define UART3_DMA_TX_IRQHandler DMA1_Stream3_IRQHandler
#define UART3_TX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART3_TX_DMA_INSTANCE DMA1_Stream3
#define UART3_TX_DMA_CHANNEL DMA_CHANNEL_4
#define UART3_TX_DMA_IRQ DMA1_Stream3_IRQn
#elif defined(BSP_UART7_TX_USING_DMA) && !defined(UART7_TX_DMA_INSTANCE)
#define UART7_DMA_RX_IRQHandler DMA1_Stream3_IRQHandler
#define UART7_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART7_RX_DMA_INSTANCE DMA1_Stream3
#define UART7_RX_DMA_CHANNEL DMA_CHANNEL_5
#define UART7_RX_DMA_IRQ DMA1_Stream3_IRQn
#elif defined(BSP_TIM4_CH2_USING_DMA) && !defined(TIM4_CH2_DMA_INSTANCE)
#define TIM4_CH2_DMA_IRQHandler DMA1_Stream3_IRQHandler
#define TIM4_CH2_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM4_CH2_DMA_INSTANCE DMA1_Stream3
#define TIM4_CH2_DMA_CHANNEL DMA_CHANNEL_2
#define TIM4_CH2_DMA_IRQ DMA1_Stream3_IRQn
#elif defined(BSP_TIM5_CH4_USING_DMA) && !defined(TIM5_CH4_DMA_INSTANCE)
#define TIM5_CH4_DMA_IRQHandler DMA1_Stream3_IRQHandler
#define TIM5_CH4_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM5_CH4_DMA_INSTANCE DMA1_Stream3
#define TIM5_CH4_DMA_CHANNEL DMA_CHANNEL_6
#define TIM5_CH4_DMA_IRQ DMA1_Stream3_IRQn
#endif
/* DMA1 stream4 */
#if defined(BSP_SPI2_TX_USING_DMA) && !defined(SPI2_TX_DMA_INSTANCE)
#define SPI2_DMA_TX_IRQHandler DMA1_Stream4_IRQHandler
#define SPI2_TX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define SPI2_TX_DMA_INSTANCE DMA1_Stream4
#define SPI2_TX_DMA_CHANNEL DMA_CHANNEL_0
#define SPI2_TX_DMA_IRQ DMA1_Stream4_IRQn
#elif defined(BSP_UART4_TX_USING_DMA) && !defined(UART4_TX_DMA_INSTANCE)
#define UART4_DMA_TX_IRQHandler DMA1_Stream4_IRQHandler
#define UART4_TX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART4_TX_DMA_INSTANCE DMA1_Stream4
#define UART4_TX_DMA_CHANNEL DMA_CHANNEL_4
#define UART4_TX_DMA_IRQ DMA1_Stream4_IRQn
#elif defined(BSP_TIM3_CH1_USING_DMA) && !defined(TIM3_CH1_DMA_INSTANCE)
#define TIM3_CH1_DMA_IRQHandler DMA1_Stream4_IRQHandler
#define TIM3_CH1_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM3_CH1_DMA_INSTANCE DMA1_Stream4
#define TIM3_CH1_DMA_CHANNEL DMA_CHANNEL_5
#define TIM3_CH1_DMA_IRQ DMA1_Stream4_IRQn
#elif defined(BSP_TIM5_CH2_USING_DMA) && !defined(TIM5_CH2_DMA_INSTANCE)
#define TIM5_CH2_DMA_IRQHandler DMA1_Stream4_IRQHandler
#define TIM5_CH2_DMA_RCC RCC_AHB1ENR_DMA1EN
#define TIM5_CH2_DMA_INSTANCE DMA1_Stream4
#define TIM5_CH2_DMA_CHANNEL DMA_CHANNEL_6
#define TIM5_CH2_DMA_IRQ DMA1_Stream4_IRQn
#endif
/* DMA1 stream5 */
#if defined(BSP_SPI3_TX_USING_DMA) && !defined(SPI3_TX_DMA_INSTANCE)
#define SPI3_DMA_TX_IRQHandler DMA1_Stream5_IRQHandler
#define SPI3_TX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define SPI3_TX_DMA_INSTANCE DMA1_Stream5
#define SPI3_TX_DMA_CHANNEL DMA_CHANNEL_0
#define SPI3_TX_DMA_IRQ DMA1_Stream5_IRQn
#elif defined(BSP_UART2_RX_USING_DMA) && !defined(UART2_RX_DMA_INSTANCE)
#define UART2_DMA_RX_IRQHandler DMA1_Stream5_IRQHandler
#define UART2_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART2_RX_DMA_INSTANCE DMA1_Stream5
#define UART2_RX_DMA_CHANNEL DMA_CHANNEL_4
#define UART2_RX_DMA_IRQ DMA1_Stream5_IRQn
#endif
///TODO: Add support other steam for timer
/* DMA1 stream6 */
#if defined(BSP_UART2_TX_USING_DMA) && !defined(UART2_TX_DMA_INSTANCE)
#define UART2_DMA_TX_IRQHandler DMA1_Stream6_IRQHandler
#define UART2_TX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART2_TX_DMA_INSTANCE DMA1_Stream6
#define UART2_TX_DMA_CHANNEL DMA_CHANNEL_4
#define UART2_TX_DMA_IRQ DMA1_Stream6_IRQn
#elif defined(BSP_UART8_RX_USING_DMA) && !defined(UART8_RX_DMA_INSTANCE)
#define UART8_DMA_RX_IRQHandler DMA1_Stream6_IRQHandler
#define UART8_RX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART8_RX_DMA_INSTANCE DMA1_Stream6
#define UART8_RX_DMA_CHANNEL DMA_CHANNEL_5
#define UART8_RX_DMA_IRQ DMA1_Stream6_IRQn
#endif
/* DMA1 stream7 */
#if defined(BSP_SPI3_TX_USING_DMA) && !defined(SPI3_TX_DMA_INSTANCE)
#define SPI3_DMA_TX_IRQHandler DMA1_Stream7_IRQHandler
#define SPI3_TX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define SPI3_TX_DMA_INSTANCE DMA1_Stream7
#define SPI3_TX_DMA_CHANNEL DMA_CHANNEL_0
#define SPI3_TX_DMA_IRQ DMA1_Stream7_IRQn
#elif defined(BSP_UART5_TX_USING_DMA) && !defined(UART5_TX_DMA_INSTANCE)
#define UART5_DMA_TX_IRQHandler DMA1_Stream7_IRQHandler
#define UART5_TX_DMA_RCC RCC_AHB1ENR_DMA1EN
#define UART5_TX_DMA_INSTANCE DMA1_Stream7
#define UART5_TX_DMA_CHANNEL DMA_CHANNEL_4
#define UART5_TX_DMA_IRQ DMA1_Stream7_IRQn
#endif
/* DMA2 stream0 */
#if defined(BSP_SPI1_RX_USING_DMA) && !defined(SPI1_RX_DMA_INSTANCE)
#define SPI1_DMA_RX_IRQHandler DMA2_Stream0_IRQHandler
#define SPI1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI1_RX_DMA_INSTANCE DMA2_Stream0
#define SPI1_RX_DMA_CHANNEL DMA_CHANNEL_3
#define SPI1_RX_DMA_IRQ DMA2_Stream0_IRQn
#elif defined(BSP_SPI4_TX_USING_DMA) && !defined(SPI4_TX_DMA_INSTANCE)
#define SPI4_DMA_TX_IRQHandler DMA2_Stream0_IRQHandler
#define SPI4_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI4_TX_DMA_INSTANCE DMA2_Stream0
#define SPI4_TX_DMA_CHANNEL DMA_CHANNEL_4
#define SPI4_TX_DMA_IRQ DMA2_Stream0_IRQn
#endif
/* DMA2 stream1 */
#if defined(BSP_SPI4_TX_USING_DMA) && !defined(SPI4_TX_DMA_INSTANCE)
#define SPI4_DMA_TX_IRQHandler DMA2_Stream1_IRQHandler
#define SPI4_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI4_TX_DMA_INSTANCE DMA2_Stream1
#define SPI4_TX_DMA_CHANNEL DMA_CHANNEL_4
#define SPI4_TX_DMA_IRQ DMA2_Stream1_IRQn
#elif defined(BSP_UART6_RX_USING_DMA) && !defined(UART6_RX_DMA_INSTANCE)
#define UART6_DMA_RX_IRQHandler DMA2_Stream1_IRQHandler
#define UART6_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define UART6_RX_DMA_INSTANCE DMA2_Stream1
#define UART6_RX_DMA_CHANNEL DMA_CHANNEL_5
#define UART6_RX_DMA_IRQ DMA2_Stream1_IRQn
#endif
/* DMA2 stream2 */
#if defined(BSP_SPI1_RX_USING_DMA) && !defined(SPI1_RX_DMA_INSTANCE)
#define SPI1_DMA_RX_IRQHandler DMA2_Stream2_IRQHandler
#define SPI1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI1_RX_DMA_INSTANCE DMA2_Stream2
#define SPI1_RX_DMA_CHANNEL DMA_CHANNEL_3
#define SPI1_RX_DMA_IRQ DMA2_Stream2_IRQn
#elif defined(BSP_UART1_RX_USING_DMA) && !defined(UART1_RX_DMA_INSTANCE)
#define UART1_DMA_RX_IRQHandler DMA2_Stream2_IRQHandler
#define UART1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define UART1_RX_DMA_INSTANCE DMA2_Stream2
#define UART1_RX_DMA_CHANNEL DMA_CHANNEL_4
#define UART1_RX_DMA_IRQ DMA2_Stream2_IRQn
#endif
/* DMA2 stream3 */
#if defined(BSP_SPI5_RX_USING_DMA) && !defined(SPI5_RX_DMA_INSTANCE)
#define SPI5_DMA_RX_IRQHandler DMA2_Stream3_IRQHandler
#define SPI5_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI5_RX_DMA_INSTANCE DMA2_Stream3
#define SPI5_RX_DMA_CHANNEL DMA_CHANNEL_2
#define SPI5_RX_DMA_IRQ DMA2_Stream3_IRQn
#elif defined(BSP_SPI1_TX_USING_DMA) && !defined(SPI1_TX_DMA_INSTANCE)
#define SPI1_DMA_TX_IRQHandler DMA2_Stream3_IRQHandler
#define SPI1_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI1_TX_DMA_INSTANCE DMA2_Stream3
#define SPI1_TX_DMA_CHANNEL DMA_CHANNEL_3
#define SPI1_TX_DMA_IRQ DMA2_Stream3_IRQn
#elif defined(BSP_SPI4_TX_USING_DMA) && !defined(SPI4_TX_DMA_INSTANCE)
#define SPI4_DMA_TX_IRQHandler DMA2_Stream3_IRQHandler
#define SPI4_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI4_TX_DMA_INSTANCE DMA2_Stream3
#define SPI4_TX_DMA_CHANNEL DMA_CHANNEL_5
#define SPI4_TX_DMA_IRQ DMA2_Stream3_IRQn
#endif
/* DMA2 stream4 */
#if defined(BSP_SPI5_TX_USING_DMA) && !defined(SPI5_TX_DMA_INSTANCE)
#define SPI5_DMA_TX_IRQHandler DMA2_Stream4_IRQHandler
#define SPI5_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI5_TX_DMA_INSTANCE DMA2_Stream4
#define SPI5_TX_DMA_CHANNEL DMA_CHANNEL_2
#define SPI5_TX_DMA_IRQ DMA2_Stream4_IRQn
#elif defined(BSP_SPI4_TX_USING_DMA) && !defined(SPI4_TX_DMA_INSTANCE)
#define SPI4_DMA_TX_IRQHandler DMA2_Stream4_IRQHandler
#define SPI4_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI4_TX_DMA_INSTANCE DMA2_Stream4
#define SPI4_TX_DMA_CHANNEL DMA_CHANNEL_5
#define SPI4_TX_DMA_IRQ DMA2_Stream4_IRQn
#endif
/* DMA2 stream5 */
#if defined(BSP_SPI1_TX_USING_DMA) && !defined(SPI1_TX_DMA_INSTANCE)
#define SPI1_DMA_TX_IRQHandler DMA2_Stream5_IRQHandler
#define SPI1_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI1_TX_DMA_INSTANCE DMA2_Stream5
#define SPI1_TX_DMA_CHANNEL DMA_CHANNEL_3
#define SPI1_TX_DMA_IRQ DMA2_Stream5_IRQn
#elif defined(BSP_UART1_RX_USING_DMA) && !defined(UART1_RX_DMA_INSTANCE)
#define UART1_DMA_RX_IRQHandler DMA2_Stream5_IRQHandler
#define UART1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define UART1_RX_DMA_INSTANCE DMA2_Stream5
#define UART1_RX_DMA_CHANNEL DMA_CHANNEL_4
#define UART1_RX_DMA_IRQ DMA2_Stream5_IRQn
#elif defined(BSP_SPI5_RX_USING_DMA) && !defined(SPI5_RX_DMA_INSTANCE)
#define SPI5_DMA_RX_IRQHandler DMA2_Stream5_IRQHandler
#define SPI5_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI5_RX_DMA_INSTANCE DMA2_Stream5
#define SPI5_RX_DMA_CHANNEL DMA_CHANNEL_7
#define SPI5_RX_DMA_IRQ DMA2_Stream5_IRQn
#endif
/* DMA2 stream6 */
#if defined(BSP_SPI5_TX_USING_DMA) && !defined(SPI5_TX_DMA_INSTANCE)
#define SPI5_DMA_TX_IRQHandler DMA2_Stream6_IRQHandler
#define SPI5_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define SPI5_TX_DMA_INSTANCE DMA2_Stream6
#define SPI5_TX_DMA_CHANNEL DMA_CHANNEL_7
#define SPI5_TX_DMA_IRQ DMA2_Stream6_IRQn
#elif defined(BSP_UART6_TX_USING_DMA) && !defined(UART6_TX_DMA_INSTANCE)
#define UART6_DMA_TX_IRQHandler DMA2_Stream6_IRQHandler
#define UART6_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define UART6_TX_DMA_INSTANCE DMA2_Stream6
#define UART6_TX_DMA_CHANNEL DMA_CHANNEL_5
#define UART6_TX_DMA_IRQ DMA2_Stream6_IRQn
#endif
/* DMA2 stream7 */
#if defined(BSP_UART1_TX_USING_DMA) && !defined(UART1_TX_DMA_INSTANCE)
#define UART1_DMA_TX_IRQHandler DMA2_Stream7_IRQHandler
#define UART1_TX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define UART1_TX_DMA_INSTANCE DMA2_Stream7
#define UART1_TX_DMA_CHANNEL DMA_CHANNEL_4
#define UART1_TX_DMA_IRQ DMA2_Stream7_IRQn
#endif
#ifdef __cplusplus
}
#endif
#endif /* __DMA_CONFIG_H__ */
4. 修改libraries/HAL_Drivers/drv_config.h
在SOC_SERIES_STM32F4下面
#include "f4/pwm_dma_config.h"
5. 修改libraries/HAL_Drivers/drv_pwm.c
把这些改成0,会有警告,可以不管,也可以屏蔽警告的地方
#define MIN_PERIOD 0
#define MIN_PULSE 0
ENV 环境
建议使用ENV工具配置
测试 : test_pwm_dma.c
/**
* @file test_pwm_dma.c
* @author Jomb
* @brief
* @version 0.1
* @date 2022-08-09
*
* @copyright Copyright (c) 2022
*
*/
#include <rtthread.h>
#include <rtdevice.h>
#define PWM_DEV_NAME "pwm3_dma_ch1"
rt_device_t pwm_dma_dev;
uint32_t test_data[] = {900,900,900,900,900,900,900,900,900,900,900,900};
uint16_t dma_mem[sizeof(test_data)/sizeof(uint32_t)];
static int pwm_dma_sample(int argc, char *argv[])
{
struct rt_pwm_dma_configuration config;
static uint16_t init_flag = 0;
if (init_flag == 0)
{
init_flag = 1;
pwm_dma_dev = rt_device_find(PWM_DEV_NAME);
if (pwm_dma_dev == RT_NULL)
{
rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
return RT_ERROR;
}
config.period = 1250;
config.pulse = 1250;
config.mem = dma_mem;
config.polarity = PWM_DMA_OCPOLARITY_LOW;
rt_device_control(pwm_dma_dev,PWM_DMA_CMD_SET,(void *)&config);
rt_device_open(pwm_dma_dev,RT_NULL);
}
rt_device_write(pwm_dma_dev,0,test_data,11);
return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(pwm_dma_sample, pwm sample);
逻辑分析仪:
图示第一个周期波形为上次的比较值
代码地址:https://gitee.com/liujianbaoself/rtt_dma_pwm-stm32f407.git