打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

PWM—脉宽调制

PWM模块可以在GPIO上产生脉宽调制信号。 该模块实现了一个上行或上下计数器,具有四个PWM通道,驱动分配的gpio。
三个PWM模块可以提供多达12个PWM通道与单独的频率控制组多达4个通道。 此外,内置的解码器和EasyDMA功能可以在没有CPU干预的情况下操纵PWM占空比。 任意占空比序列可从数据RAM中读取,并可链接以实现循环缓冲或重复进入复杂循环。

这里列出了一个PWM模块的主要特点:

  • 固定的PWM基频与可编程时钟分频器
  • 多达四个PWM通道,各自的极性和占空比值
  • 沿PWM通道或中心对齐的脉冲
  • Data RAM中定义的多个占空比阵列(序列)
  • 通过EasyDMA从内存直接自动和无故障更新占空比值
  • 在每个PWM周期上可能改变极性、占空比和基频
  • 数据RAM序列可以重复或连接到循环

图141:PWM模块
波计数器
波计数器负责产生占空比取决于比较值,频率取决于COUNTERTOP。

有一个普通的15位计数器与四个比较通道。 因此,所有四个通道将共享相同的周期(PWM频率),但可以有各自的占空比和极性。 极性由从RAM读取的值设置(参见第498页图144:解码器内存访问模式),而MODE寄存器控制计数器是向上计数还是向上和向下计数。 计时器的顶部值由COUNTERTOP寄存器控制。 这个寄存器值与PWM_CLK的所选PRESCALER结合将产生一个给定的PWM周期。 COUNTERTOP值小于比较设置将导致不产生PWM边缘的状态。 考虑到极性设置为FallingEdge,则将OUT[n]设置为高值。

所有的比较寄存器都是内部的,只能通过后面提供的解码器进行配置。

台面可随时安全书写。 它将在START任务之后进行采样。 如果解码器。 LOAD不是波形,它也会在STARTSEQ[n]任务之后采样,以及在序列回放期间从RAM加载新值时采样。 如果解码器。 LOAD=波形,寄存器值将被忽略,并从RAM中获取(参见下面498页的译码器和 EasyDMA)。

[nrf52] low_power_pwm pwm_library pwm_driver 三者区别

/********************************************************************************
* @file    bsp_pwm.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-08-10
* @brief   NULL
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "RTE_Components.h"
#include CMSIS_device_header
#include "nrf_drv_pwm.h"

#include "bsp_gpio.h"
#include "bsp_pwm.h"

/* Private includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"

/* Private variables ---------------------------------------------------------*/
static bool g_pwm_init = false;

#if BS_TIM1_EN
static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
static uint16_t const              m_pwm0_top   = BS_TIM1_PERIOD;
//static uint16_t const              m_pwm0_step  = 1;
static nrf_pwm_values_individual_t m_pwm0_seq_values;
static nrf_pwm_sequence_t const    m_pwm0_seq =
{
    .values.p_individual = &m_pwm0_seq_values,
    .length              = NRF_PWM_VALUES_LENGTH(m_pwm0_seq_values),
    .repeats             = 0,
    .end_delay           = 0
};
#endif

#if BS_TIM2_EN
static nrf_drv_pwm_t m_pwm1 = NRF_DRV_PWM_INSTANCE(1);
static uint16_t const              m_pwm1_top   = BS_TIM2_PERIOD;
//static uint16_t const              m_pwm1_step  = 1;
static nrf_pwm_values_individual_t m_pwm1_seq_values;
static nrf_pwm_sequence_t const    m_pwm1_seq =
{
    .values.p_individual = &m_pwm1_seq_values,
    .length              = NRF_PWM_VALUES_LENGTH(m_pwm1_seq_values),
    .repeats             = 0,
    .end_delay           = 0
};
#endif

#if BS_TIM3_EN
static nrf_drv_pwm_t m_pwm2 = NRF_DRV_PWM_INSTANCE(2);
static uint16_t const              m_pwm2_top   = BS_TIM3_PERIOD;
//static uint16_t const              m_pwm2_step  = 1;
static nrf_pwm_values_individual_t m_pwm2_seq_values;
static nrf_pwm_sequence_t const    m_pwm2_seq =
{
    .values.p_individual = &m_pwm2_seq_values,
    .length              = NRF_PWM_VALUES_LENGTH(m_pwm2_seq_values),
    .repeats             = 0,
    .end_delay           = 0
};
#endif

void bsp_pwm_init(void)
{
    if (g_pwm_init)
    {
        return;
    }
#if BS_TIM1_EN
    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
#if BS_TIM1_CH0_PIN != NULL
            BS_TIM1_CH0_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 0
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 0
#endif
#if BS_TIM1_CH1_PIN != NULL
            BS_TIM1_CH1_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 1
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 1
#endif
#if BS_TIM1_CH2_PIN != NULL
            BS_TIM1_CH2_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 2
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 2
#endif
#if BS_TIM1_CH3_PIN != NULL
            BS_TIM1_CH3_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 3
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 3
#endif
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = (nrf_pwm_clk_t)BS_TIM1_PRESCALER,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = m_pwm0_top,
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));

    m_pwm0_seq_values.channel_0 = 0x8000;
    m_pwm0_seq_values.channel_1 = 0x8000;
    m_pwm0_seq_values.channel_2 = 0x8000;
    m_pwm0_seq_values.channel_3 = 0x8000;

    (void)nrf_drv_pwm_simple_playback(&m_pwm0, &m_pwm0_seq, 1, NRF_DRV_PWM_FLAG_LOOP);
	g_pwm_init = true;
#endif

#if BS_TIM2_EN
    nrf_drv_pwm_config_t const config1 =
    {
        .output_pins =
        {
#if BS_TIM2_CH0_PIN != NULL
            BS_TIM2_CH0_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 0
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 0
#endif
#if BS_TIM2_CH1_PIN != NULL
            BS_TIM2_CH1_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 1
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 1
#endif
#if BS_TIM2_CH2_PIN != NULL
            BS_TIM2_CH2_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 2
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 2
#endif
#if BS_TIM2_CH3_PIN != NULL
            BS_TIM2_CH3_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 3
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 3
#endif
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = (nrf_pwm_clk_t)BS_TIM2_PRESCALER,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = m_pwm1_top,
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm1, &config1, NULL));

    m_pwm1_seq_values.channel_0 = 0x8000;
    m_pwm1_seq_values.channel_1 = 0x8000;
    m_pwm1_seq_values.channel_2 = 0x8000;
    m_pwm1_seq_values.channel_3 = 0x8000;

    (void)nrf_drv_pwm_simple_playback(&m_pwm1, &m_pwm1_seq, 1, NRF_DRV_PWM_FLAG_LOOP);
	g_pwm_init = true;
#endif

#if BS_TIM3_EN
    nrf_drv_pwm_config_t const config2 =
    {
        .output_pins =
        {
#if BS_TIM3_CH0_PIN != NULL
            BS_TIM3_CH0_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 0
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 0
#endif
#if BS_TIM3_CH1_PIN != NULL
            BS_TIM3_CH1_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 1
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 1
#endif
#if BS_TIM3_CH2_PIN != NULL
            BS_TIM3_CH2_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 2
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 2
#endif
#if BS_TIM3_CH3_PIN != NULL
            BS_TIM3_CH3_PIN | NRF_DRV_PWM_PIN_INVERTED, // channel 3
#else
            NRF_DRV_PWM_PIN_NOT_USED,                   // channel 3
#endif
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = (nrf_pwm_clk_t)BS_TIM3_PRESCALER,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = m_pwm1_top,
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm2, &config2, NULL));

    m_pwm2_seq_values.channel_0 = 0x8000;
    m_pwm2_seq_values.channel_1 = 0x8000;
    m_pwm2_seq_values.channel_2 = 0x8000;
    m_pwm2_seq_values.channel_3 = 0x8000;

    (void)nrf_drv_pwm_simple_playback(&m_pwm2, &m_pwm2_seq, 1, NRF_DRV_PWM_FLAG_LOOP);
	g_pwm_init = true;
#endif
}

/**
 * @brief  PWN功能关闭
 * @note   NULL
 * @retval None
 */
void bsp_pwm_deinit(void)
{
    if (!g_pwm_init)
    {
        return;
    }
#if BS_TIM1_EN
	nrf_drv_pwm_uninit(&m_pwm0);
    g_pwm_init = false;
#endif
#if BS_TIM2_EN
	nrf_drv_pwm_uninit(&m_pwm1);
    g_pwm_init = false;
#endif
#if BS_TIM3_EN
	nrf_drv_pwm_uninit(&m_pwm2);
    g_pwm_init = false;
#endif
}

/**
 * @brief  设置PWM占空比
 * @note   NULL
 * @param  pwmx: PWM组号
 * @param  val: 0-100 PWM值
 * @retval None
 */
void bsp_pwm_set_pulse(bsp_pwm_t pwmx, uint16_t val)
{
#if BS_TIM1_EN || BS_TIM2_EN
    if (!g_pwm_init)
    {
        return;
    }
#endif
    if (pwmx == BSP_PWM_0)
    {
#if BS_TIM1_EN && BS_PWM0_EN
        m_pwm0_seq_values.channel_0 = val;
#endif
    }
    else if (pwmx == BSP_PWM_1)
    {
#if BS_TIM1_EN && BS_PWM1_EN
        m_pwm0_seq_values.channel_1 = val;
#endif
    }
    else if (pwmx == BSP_PWM_2)
    {
#if BS_TIM1_EN && BS_PWM2_EN
        m_pwm0_seq_values.channel_2 = val;
#endif
    }
    else if (pwmx == BSP_PWM_3)
    {
#if BS_TIM1_EN && BS_PWM3_EN
        m_pwm0_seq_values.channel_3 = val;
#endif
    }
    else if (pwmx == BSP_PWM_4)
    {
#if BS_TIM2_EN && BS_PWM4_EN
        m_pwm1_seq_values.channel_0 = val;
#endif
    }
    else if (pwmx == BSP_PWM_5)
    {
#if BS_TIM2_EN && BS_PWM5_EN
        m_pwm1_seq_values.channel_1 = val;
#endif
    }
    else if (pwmx == BSP_PWM_6)
    {
#if BS_TIM2_EN && BS_PWM6_EN
        m_pwm1_seq_values.channel_2 = val;
#endif
    }
    else if (pwmx == BSP_PWM_7)
    {
#if BS_TIM2_EN && BS_PWM7_EN
        m_pwm1_seq_values.channel_3 = val;
#endif
    }
    else if (pwmx == BSP_PWM_8)
    {
#if BS_TIM3_EN && BS_PWM8_EN
        m_pwm2_seq_values.channel_0 = val;
#endif
    }
    else if (pwmx == BSP_PWM_9)
    {
#if BS_TIM3_EN && BS_PWM9_EN
        m_pwm2_seq_values.channel_1 = val;
#endif
    }
    else if (pwmx == BSP_PWM_10)
    {
#if BS_TIM3_EN && BS_PWM10_EN
        m_pwm2_seq_values.channel_2 = val;
#endif
    }
    else if (pwmx == BSP_PWM_11)
    {
#if BS_TIM3_EN && BS_PWM11_EN
        m_pwm2_seq_values.channel_3 = val;
#endif
    }
}

/********************************************************************************
* @file    bsp_pwm.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-18
* @brief   NULL
********************************************************************************/

#ifndef __BSP_PWM_H
#define __BSP_PWM_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>

/* Public enum ---------------------------------------------------------------*/
typedef enum
{
    BSP_PWM_0 = 0,
    BSP_PWM_1,
    BSP_PWM_2,
    BSP_PWM_3,
    BSP_PWM_4,
    BSP_PWM_5,
    BSP_PWM_6,
    BSP_PWM_7,
    BSP_PWM_8,
    BSP_PWM_9,
    BSP_PWM_10,
    BSP_PWM_11
} bsp_pwm_t;

/* Public Function Prototypes ------------------------------------------------*/

void bsp_pwm_init(void);
void bsp_pwm_deinit(void);

void bsp_pwm_set_pulse(bsp_pwm_t pwmx, uint16_t val);

#endif

posted on 2022-08-13 11:00  xuejianqiang  阅读(115)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033