RTT-STM32F407-PWM-DMA

前言

  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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值