硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3469|回复: 13
收起左侧

[DMA] 请教下,历程V7-010_DMAMUX的定时器触+BDMA控制任意IO做PWM和脉冲数控制(V1.1)

[复制链接]

609

主题

3047

回帖

4894

积分

至尊会员

积分
4894
发表于 2019-6-27 14:51:56 | 显示全部楼层 |阅读模式
  请教下,历程V7-010_DMAMUX的定时器触+BDMA控制任意IO做PWM和脉冲数控制(V1.1)

  /*##-4- 启动LPTIM2的PWM模式,但使用输出引脚,仅用于DMAMUX的触发 ##############*/
    /* LPTIM2的时钟主频是100MHz,这里配置触发是100MHz / (10000 - 1 + 1) = 10KHz */
    HAL_LPTIM_PWM_Start(&LptimHandle, 10000-1, 5000 - 1);

如果我想在不改变 目前设置的频率情况下,值改变占空比应该就可以改变亮度,如果我吧

5000 改成 10000 是不是就是 100% 的占空比,1000就是 10% 的占空比 ???

回复

使用道具 举报

23

主题

1403

回帖

1472

积分

至尊会员

积分
1472
发表于 2019-6-27 17:51:47 | 显示全部楼层
不是哦,我记得那个占空比是反着的,你看下API源码确认下,比如你设置10%,实际应该是1 - 10% 也就是90%
代码不规范,亲人两行泪!
回复

使用道具 举报

609

主题

3047

回帖

4894

积分

至尊会员

积分
4894
 楼主| 发表于 2019-6-27 20:00:56 | 显示全部楼层
missfox 发表于 2019-6-27 17:51
不是哦,我记得那个占空比是反着的,你看下API源码确认下,比如你设置10%,实际应该是1 - 10% 也就是90%

刚刚试过了,貌似使用这个方法 进行控制 lcd 背光时, 在 调节亮度时, 正常来说,在调节亮度时,
左边为最低(也就是亮度最低), 调节到右边时最高(亮度最亮),

但是实际 效果,有时最最左边最亮,有时又是最右边最亮, 貌似没有节操啊, 有没有什么方法可以解决啊 ??
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2019-6-28 08:47:09 | 显示全部楼层
hpdell 发表于 2019-6-27 20:00
刚刚试过了,貌似使用这个方法 进行控制 lcd 背光时, 在 调节亮度时, 正常来说,在调节亮度时,
左边为最低 ...

你搞错了,这个例子里面LPTIM的PWM仅仅是用来触发DMAMUX的,修改他的占空比是没有效果的。

你应该用LPTIM章节的PWM例子。
回复

使用道具 举报

609

主题

3047

回帖

4894

积分

至尊会员

积分
4894
 楼主| 发表于 2019-6-28 11:44:48 | 显示全部楼层
本帖最后由 hpdell 于 2019-6-28 11:48 编辑
eric2013 发表于 2019-6-28 08:47
你搞错了,这个例子里面LPTIM的PWM仅仅是用来触发DMAMUX的,修改他的占空比是没有效果的。

你应该用LP ...

原来如此啊,感觉还是使用 模拟 来控制 pwm 亮度比较方面,也没有 io 口限制,目前效果也还不错
回复

使用道具 举报

36

主题

1445

回帖

1553

积分

至尊会员

积分
1553
发表于 2019-6-28 12:34:22 | 显示全部楼层
hpdell 发表于 2019-6-28 11:44
原来如此啊,感觉还是使用 模拟 来控制 pwm 亮度比较方面,也没有 io 口限制,目前效果也还不错

模拟产生PWM太占用cpu,硬件PWM配置好就不用管了多好
回复

使用道具 举报

609

主题

3047

回帖

4894

积分

至尊会员

积分
4894
 楼主| 发表于 2019-6-28 16:41:30 | 显示全部楼层
本帖最后由 hpdell 于 2019-6-28 16:42 编辑
sanit 发表于 2019-6-28 12:34
模拟产生PWM太占用cpu,硬件PWM配置好就不用管了多好

不会呀,我目前使用的是 1ms 系统本身的定时器中断,pwm 最大数值设置为 10ms,
/*
使用定时器 + io 口模拟 pwm 功能控制 LCD 屏亮度
*/
uint16_t s_ucBright = 7;                                        /* 背光亮度参数默认值,最大值为 10 ,默认值为7
                                     需要与 emWin_BrightApp.c 里面 ID_SLIDER_0 这个 ID 定义的控件保持一致
                                  */

#define GPIO_RCC_PWM   __HAL_RCC_GPIOB_CLK_ENABLE()
#define GPIO_PORT_PWM         GPIOB
#define GPIO_PIN_PWM   GPIO_PIN_5

//高 16 位用于控制 GPIO 的输出低电平,而低 16 位用于输出高电平工作,所以我们这里设置
#define PWM_ON          GPIO_PORT_PWM->BSRR = (uint32_t)GPIO_PIN_PWM                           /* 输出 1 */
#define PWM_OFF          GPIO_PORT_PWM->BSRR = (uint32_t)GPIO_PIN_PWM << 16        /* 输出 0 */

/*
*********************************************************************************************************
*        函 数 名: PWM_InitHard
*        功能说明: 初始化 PWM IO 硬件
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void PWM_InitHard(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        /* 打开GPIO BEEP 的时钟 */
        GPIO_RCC_PWM;

        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStructure.Pull = GPIO_NOPULL;  //GPIO_PULLUP;
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;  //GPIO_SPEED_FREQ_VERY_HIGH;        
        GPIO_InitStructure.Pin = GPIO_PIN_PWM;
        HAL_GPIO_Init(GPIO_PORT_PWM, &GPIO_InitStructure);        
}



HAL_StatusTypeDef LCD_BackLightInit(void)
{
        PWM_InitHard();

        return HAL_OK;
}


uint16_t LCD_GetBackLight(void)
{
        return s_ucBright;
}


void LCD_SetBackLight(uint16_t _bright)
{
        s_ucBright = _bright;
}

/*
在中断定时器里面被调用,每1ms调用一次
具体的在bsp.c 里面的 bsp_RunPer1ms 这个函数里面被调用
*/
void PWM_Timer1ms(void)
{
        static uint8_t _value=0;

        _value++;
        if(_value <= s_ucBright)
        {
                PWM_ON;
        }
        else
        {
                PWM_OFF;
        }
        
        if(_value > 10)
        {
                _value = 0;
        }
}


模拟的就这么多代码了,目前效果非常不错,硬件 pwm 的io 口做为其他功能使用了,目前使用方法感觉还是非常不错的

反正控制 lcd 背光亮度也不需要那么精确
回复

使用道具 举报

23

主题

1403

回帖

1472

积分

至尊会员

积分
1472
发表于 2019-6-29 00:53:21 | 显示全部楼层
hpdell 发表于 2019-6-28 16:41
不会呀,我目前使用的是 1ms 系统本身的定时器中断,pwm 最大数值设置为 10ms,
/*
使用定时器 + io 口 ...

原来你是搞这个功能啊
代码不规范,亲人两行泪!
回复

使用道具 举报

609

主题

3047

回帖

4894

积分

至尊会员

积分
4894
 楼主| 发表于 2019-6-29 08:27:42 | 显示全部楼层
missfox 发表于 2019-6-29 00:53
原来你是搞这个功能啊

回复

使用道具 举报

2

主题

87

回帖

93

积分

初级会员

积分
93
发表于 2022-1-20 11:59:33 | 显示全部楼层
请教一下,我用 PB9,把缓冲区改为,还是有脉冲。只有停了HAL_LPTIM_PWM_Stop(&LptimHandle); 脉冲才停 .

/**********************************************************************************************************
*
*        模块名称 : 定时器触发DMA
*        文件名称 : bsp_tim_dma.c
*        版    本 : V1.0
*        说    明 : DMAMUX的定时器触+DMA控制任意IO做PWM和脉冲数控制
*
*        修改记录 :
*                版本号   日期        作者      说明
*                V1.0    2018-12-12  Eric2013  正式发布
*
*        Copyright (C), 2018-2030, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/
#include "bsp.h"






LPTIM_HandleTypeDef  LptimHandle = {0};


/* 方便Cache类的API操作,做32字节对齐 */
__attribute__((section (".RAM_D3"))) uint16_t usPWM_NUM=0;


ALIGN_32BYTES(__attribute__((section (".RAM_D3"))) uint32_t IO_Toggle[16]) =
                                                      {
                                                          0x00000200U,
                                                          0x02000000U,
                                                          0x00000200U,
                                                          0x02000000U,
                                                          0x00000200U,
                                                          0x02000000U,
                                                          0x00000200U,
                                                          0x02000000U,
                                                                                                                  0x00000200U,
                                                          0x02000000U,
                                                          0x00000200U,
                                                          0x02000000U,
                                                          0x00000200U,
                                                          0x02000000U,
                                                          0x00000200U,
                                                          0x02000000U,
                                                      };






/*
*********************************************************************************************************
*        函 数 名: LPTIM_Config
*        功能说明: 配置LPTIM,用于触发DMAMUX的请求发生器
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
static void LPTIM_Config(void)
{
    RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;




    /*##-1- 配置LPTIM2使用PCLK时钟 ##################################################*/
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM2;
    PeriphClkInitStruct.Lptim2ClockSelection = RCC_LPTIM2CLKSOURCE_D3PCLK1;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);




    /*##-2- 使能LPTIM2时钟并配置 ####################################################*/
    __HAL_RCC_LPTIM2_CLK_ENABLE();


    LptimHandle.Instance                           = LPTIM2;
    LptimHandle.Init.CounterSource                 = LPTIM_COUNTERSOURCE_INTERNAL;
    LptimHandle.Init.UpdateMode                    = LPTIM_UPDATE_ENDOFPERIOD;
    LptimHandle.Init.OutputPolarity                = LPTIM_OUTPUTPOLARITY_HIGH;
    LptimHandle.Init.Clock.Source                  = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
    LptimHandle.Init.Clock.Prescaler               = LPTIM_PRESCALER_DIV1;
    LptimHandle.Init.UltraLowPowerClock.Polarity   = LPTIM_CLOCKPOLARITY_RISING;
    LptimHandle.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
    LptimHandle.Init.Trigger.Source                = LPTIM_TRIGSOURCE_SOFTWARE;
    LptimHandle.Init.Trigger.ActiveEdge            = LPTIM_ACTIVEEDGE_RISING;
    LptimHandle.Init.Trigger.SampleTime            = LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION;


    /*##-3- 初始化LPTIM2 ##########################################################*/
    if(HAL_LPTIM_Init(&LptimHandle) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);
    }


    /*##-4- 启动LPTIM2的PWM模式,但使用输出引脚,仅用于DMAMUX的触发 ##############*/
    /* LPTIM2的时钟主频是100MHz,这里配置触发是100MHz / (10000 - 1 + 1) = 10KHz */
    //if (HAL_LPTIM_PWM_Start(&LptimHandle, 10000-1, 5000 - 1) != HAL_OK)
        if (HAL_LPTIM_PWM_Start(&LptimHandle, 5000-1, 2500 - 1) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);
    }
}


/*
*********************************************************************************************************
*        函 数 名: bsp_InitTimBDMA
*        功能说明: 配置DMAMUX的定时器触+DMA控制任意IO做PWM和脉冲数控制
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitTimBDMA(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    DMA_HandleTypeDef DMA_Handle = {0};
    HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams ={0};




     /*##-1- 配置PB9用于PWM输出######################################*/
    __HAL_RCC_GPIOB_CLK_ENABLE();


    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);




    /*##-2- 配置DMA ##################################################*/
    __HAL_RCC_BDMA_CLK_ENABLE();


    DMA_Handle.Instance                 = BDMA_Channel0;           /* 使用的BDMA通道0 */
    DMA_Handle.Init.Request             = BDMA_REQUEST_GENERATOR0; /* 请求类型采用的DMAMUX请求发生器通道0 */
    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 传输方向是从存储器到外设 */
    DMA_Handle.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外设地址自增禁止 */
    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;         /* 存储器地址自增使能 */
    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;     /* 外设数据传输位宽选择字,即32bit */
    DMA_Handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存储器数据传输位宽选择字,即32bit */
    DMA_Handle.Init.Mode                = DMA_CIRCULAR;            /* 循环模式 */
    DMA_Handle.Init.Priority            = DMA_PRIORITY_LOW;        /* 优先级低 */
    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    /* BDMA不支持FIFO */
    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* BDMA不支持FIFO阀值设置 */
    DMA_Handle.Init.MemBurst            = DMA_MBURST_SINGLE;       /* BDMA不支持存储器突发 */
    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;       /* BDMA不支持外设突发 */


    HAL_DMA_Init(&DMA_Handle);


    /* 开启BDMA Channel0的中断 */
    HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);


    /*##-3- 配置DMAMUX #########################################################*/
    dmamux_ReqGenParams.SignalID  = HAL_DMAMUX2_REQ_GEN_LPTIM2_OUT;         /* 请求触发器选择LPTIM2_OUT */
    dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING_FALLING;      /* LPTIM2输出的上升沿和下降沿均可触发  */
    dmamux_ReqGenParams.RequestNumber = 1;                                  /* 触发后,传输进行1次DMA传输 */


    HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handle, &dmamux_ReqGenParams); /* 配置DMAMUX */


    HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handle);                      /* 使能DMAMUX请求发生器 */


    /*##-4- 启动DMA传输 ################################################*/
    HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)IO_Toggle, (uint32_t)&GPIOB->BSRR, 16);


    /*
       默认情况下,用户通过注册回调函数DMA_Handle.XferHalfCpltCallback,然后函数HAL_DMA_Init会开启半传输完成中断,
       由于这里没有使用HAL库默认的中断管理函数HAL_DMA_IRQHandler,直接手动开启。
    */
    BDMA_Channel0->CCR |= BDMA_CCR_HTIE;
        BDMA_Channel0->CCR |= BDMA_CCR_TCIE;


    LPTIM_Config(); /* 配置LPTIM触发DMAMUX */
}


/*
*********************************************************************************************************
*        函 数 名: BDMA_Channel0_IRQHandler
*        功能说明: BDMA通道0
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void BDMA_Channel0_IRQHandler(void)
{
    /* 传输完成中断 */
    if((BDMA->ISR & BDMA_FLAG_TC0) != RESET)
    {
        BDMA->IFCR = BDMA_FLAG_TC0;


        /*
           1、传输完成开始使用DMA缓冲区的前半部分,此时可以动态修改后半部分数据
              比如缓冲区大小是IO_Toggle[0] 到 IO_Toggle[7]
              那么此时可以修改IO_Toggle[4] 到 IO_Toggle[7]
           2、变量所在的SRAM区已经通过MPU配置为WT模式,更新变量IO_Toggle会立即写入。
           3、不配置MPU的话,也可以通过Cahce的函数SCB_CleanDCache_by_Addr做Clean操作。
        */
                if(usPWM_NUM==2500){
                    //HAL_DMAEx_DisableMuxRequestGenerator();
                        HAL_LPTIM_PWM_Stop(&LptimHandle);
                IO_Toggle[ 8]= 0x02000000U;
                IO_Toggle[ 9]= 0x02000000U;
                IO_Toggle[10]= 0x02000000U;
                IO_Toggle[11]= 0x02000000U;
                IO_Toggle[12]= 0x02000000U;
                IO_Toggle[13]= 0x02000000U;
                IO_Toggle[14]= 0x02000000U;
                IO_Toggle[15]= 0x02000000U;


                        usPWM_NUM=0;
         //HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)IO_Toggle, (uint32_t)&GPIOB->BSRR, 16);
                        //HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);
                        //HAL_NVIC_DisableIRQ(BDMA_Channel0_IRQn);
                }
                usPWM_NUM++;




    }


    /* 半传输完成中断 */
    if((BDMA->ISR & BDMA_FLAG_HT0) != RESET)
    {
        BDMA->IFCR = BDMA_FLAG_HT0;


        /*
           1、半传输完成开始使用DMA缓冲区的后半部分,此时可以动态修改前半部分数据
              比如缓冲区大小是IO_Toggle[0] 到 IO_Toggle[7]
              那么此时可以修改IO_Toggle[0] 到 IO_Toggle[3]
           2、变量所在的SRAM区已经通过MPU配置为WT模式,更新变量IO_Toggle会立即写入。
           3、不配置MPU的话,也可以通过Cahce的函数SCB_CleanDCache_by_Addr做Clean操作。
        */
                if(usPWM_NUM==2500){
                IO_Toggle[0]= 0x02000000U;
                IO_Toggle[1]= 0x02000000U;
                IO_Toggle[2]= 0x02000000U;
                IO_Toggle[3]= 0x02000000U;
                IO_Toggle[4]= 0x02000000U;
                IO_Toggle[5]= 0x02000000U;
                IO_Toggle[6]= 0x02000000U;
                IO_Toggle[7]= 0x02000000U;
                }
    }


    /* 传输错误中断 */
    if((BDMA->ISR & BDMA_FLAG_TE0) != RESET)
    {
        BDMA->IFCR = BDMA_FLAG_TE0;
    }
}


/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/



回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2022-1-21 10:58:39 | 显示全部楼层
EastWind 发表于 2022-1-20 11:59
请教一下,我用 PB9,把缓冲区改为,还是有脉冲。只有停了HAL_LPTIM_PWM_Stop(&LptimHandle); 脉冲才停 .

...

注意Cache操作。
回复

使用道具 举报

2

主题

87

回帖

93

积分

初级会员

积分
93
发表于 2022-1-21 14:10:16 | 显示全部楼层
谢谢,确实是CACHE的问题。
SCB_CleanDCache_by_Addr((uint32_t*)&IO_Toggle[8],8);
                IO_Toggle[ 8]= 0x02000000U;
                IO_Toggle[ 9]= 0x02000000U;
                IO_Toggle[10]= 0x02000000U;
                IO_Toggle[11]= 0x02000000U;
                IO_Toggle[12]= 0x02000000U;
                IO_Toggle[13]= 0x02000000U;
                IO_Toggle[14]= 0x02000000U;
                IO_Toggle[15]= 0x02000000U;
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2022-1-22 10:44:05 | 显示全部楼层
EastWind 发表于 2022-1-21 14:10
谢谢,确实是CACHE的问题。
SCB_CleanDCache_by_Addr((uint32_t*)&IO_Toggle[8],8);
                IO_Toggle[ 8]= 0 ...

好的,后面还有什么问题再交流。
回复

使用道具 举报

3

主题

90

回帖

99

积分

初级会员

积分
99
发表于 2022-4-25 15:33:57 | 显示全部楼层
hpdell 发表于 2019-6-28 16:41
不会呀,我目前使用的是 1ms 系统本身的定时器中断,pwm 最大数值设置为 10ms,
/*
使用定时器 + io 口 ...

0~10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-28 13:45 , Processed in 0.417730 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表