From 60eba82797f095995ff0726b193673595e6373e5 Mon Sep 17 00:00:00 2001 From: "lichao.ren" Date: Thu, 18 May 2023 19:10:02 +0800 Subject: [PATCH] [Add] Add x1600 PWM DMA function --- drivers/drivers-x16xx/include/x16xx_hal_pwm.h | 25 +++- drivers/drivers-x16xx/src/x16xx_hal_pdma.c | 4 +- drivers/drivers-x16xx/src/x16xx_hal_pwm.c | 62 ++++++---- .../x16xx-halley6/Examples/pwm/CMakeLists.txt | 1 + projects/x16xx-halley6/Examples/pwm/Makefile | 1 + projects/x16xx-halley6/Examples/pwm/main.c | 112 ++++++++++++++---- 6 files changed, 155 insertions(+), 50 deletions(-) diff --git a/drivers/drivers-x16xx/include/x16xx_hal_pwm.h b/drivers/drivers-x16xx/include/x16xx_hal_pwm.h index aa903087..37212989 100644 --- a/drivers/drivers-x16xx/include/x16xx_hal_pwm.h +++ b/drivers/drivers-x16xx/include/x16xx_hal_pwm.h @@ -94,6 +94,8 @@ typedef struct __PWM_HandleTypeDef { uint32_t PWMColck; /*!< PWM时钟频率 */ __IO uint8_t Channels; /*!< 所有通道 */ HAL_LockTypeDef Lock; /*!< PWM Lock */ + DMA_HandleTypeDef *DMA_Handle; + DMA_InitChannelConfTypeDef *PWM_DMA_Config; } PWM_HandleTypeDef; /** * @} @@ -125,6 +127,7 @@ typedef struct __PWM_HandleTypeDef { */ #define __HAL_PWM_ENABLE_HW(__HANDLE__, __CHANNEL__) WRITE_REG((__HANDLE__)->Instance->PWMENS, 1 << __CHANNEL__) +#define __HAL_PWM_DMA_ENABLE_HW(__HANDLE__, __CHANNEL__) WRITE_REG((__HANDLE__)->Instance->PWMDRE, 1 << __CHANNEL__) /** @brief 禁用指定的PWM通道。 * @param __HANDLE__ 指定PWM句柄. * @param __CHANNEL__ 指定PWM通道. @@ -148,6 +151,7 @@ HAL_StatusTypeDef HAL_PWM_updateConfig(PWM_HandleTypeDef *hpwm, PWM_InitTypeDef HAL_StatusTypeDef HAL_PWM_DeInit(PWM_HandleTypeDef *hpwm); HAL_StatusTypeDef HAL_PWM_Enable(PWM_HandleTypeDef *hpwm); HAL_StatusTypeDef HAL_PWM_Disable(PWM_HandleTypeDef *hpwm); +void dump_pwm_reg(PWM_HandleTypeDef *hpwm); /** * @} */ @@ -284,7 +288,26 @@ HAL_StatusTypeDef HAL_PWM_Disable(PWM_HandleTypeDef *hpwm); WRITE_REG((__HANDLE__)->Instance->PWMWCn[__CHANNEL__], tmp); \ } while (0) -#define __HAL_PWM_SET_FIFO_THRESHOLD(__HANDLE__, __CHANNEL__) WRITE_REG((__HANDLE__)->Instance->PWMDRTNn(__CHANNEL__), 32); +#define __HAL_PWM_SET_FIFO_THROSHOLD(__HANDLE__, __CHANNEL__) WRITE_REG((__HANDLE__)->Instance->PWMDRTNn[__CHANNEL__], 32); + +#define __HAL_PWM_DMA_UNDER_IRQ_ENBLE(__HANDLE__, __CHANNEL__) \ + do { \ + int tmp = READ_REG((__HANDLE__)->Instance->PWMDFIE); \ + tmp |= 1 << __CHANNEL__; \ + WRITE_REG((__HANDLE__)->Instance->PWMDFIE, tmp); \ + } while (0) + +//#define __HAL_PWM_SET_FIFO_THROSHOLD(__HANDLE__, __CHANNEL__) WRITE_REG((__HANDLE__)->Instance->PWMDRTNn(__CHANNEL__), 32); + +#define __HAL_PWM_DMA_ASYNC_FIFO_FLUSH(__HANDLE__, __CHANNEL__) WRITE_REG((__HANDLE__)->Instance->PWMDAFF, 1 << __CHANNEL__); + +#define __HAL_PWM_DMA_FIFO_FLUSH(__HANDLE__, __CHANNEL__) WRITE_REG((__HANDLE__)->Instance->PWMDCFF, 1 << __CHANNEL__); +/** @brief PWM_DR 寄存器,指向PWM FIFO。 + * * @param __HANDLE__ 指定PWM句柄. + * * @retval 无 + * */ +#define PWM_FIFO(__HANDLE__,num) (&(__HANDLE__)->Instance->PWMDRn[num]) + /** * @} */ diff --git a/drivers/drivers-x16xx/src/x16xx_hal_pdma.c b/drivers/drivers-x16xx/src/x16xx_hal_pdma.c index ef39d785..52976ca9 100644 --- a/drivers/drivers-x16xx/src/x16xx_hal_pdma.c +++ b/drivers/drivers-x16xx/src/x16xx_hal_pdma.c @@ -258,7 +258,8 @@ static void HAL_PDMAD_IntHandler(int irq, void *data) if (dcs & DCSn_HLT) { prom_printk("dma halt!\n"); } - + if (hdma->InitChannelConf[ch]->descConfig->DescDMATransferType < DMA_RQ_PWM0 \ + || hdma->InitChannelConf[ch]->descConfig->DescDMATransferType > DMA_RQ_PWM7) HAL_DMA_Stop(hdma, ch); __HAL_UnLock(&hdma->Lock); @@ -589,7 +590,6 @@ HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, int32_t ch) /* 写入DCS寄存器 */ WRITE_REG(hdma->Instance->Channel.CHANNEL[ch].DCSn, reg_tmp); - // DMA_Dump_Reg(hdma); return HAL_OK; } diff --git a/drivers/drivers-x16xx/src/x16xx_hal_pwm.c b/drivers/drivers-x16xx/src/x16xx_hal_pwm.c index 972be51c..ad166acd 100644 --- a/drivers/drivers-x16xx/src/x16xx_hal_pwm.c +++ b/drivers/drivers-x16xx/src/x16xx_hal_pwm.c @@ -116,23 +116,6 @@ HAL_StatusTypeDef HAL_PWM_setOneChannel(PWM_HandleTypeDef *hpwm, uint8_t ch) uint32_t periodCount, dutyCount; // uint32_t freq = hpwm->Init[ch].freq; - /* 根据PWM时钟计算周期对应的寄存器count值 */ - periodCount = periodus * (PWMClock / US); - - /* 周期寄存器count值大于最大值需要进行分频,分频数2^perscale */ - while ((periodCount > PWM_DUTY_MAX_COUNT && perscale < 8)) { - periodCount >>= 1; - ++perscale; - } - - /* 最大分频2^7 */ - if (perscale == 8) { - prom_printk("pwm perscale bad value\n"); - return HAL_ERROR; - } - - /* 根据周期对应的count值计算占空比部分占的count值 */ - dutyCount = (periodCount * dutyus)/periodus; // prom_printk("dutyus = %d, periodus - dutyus = %d, periodus = %d\n", dutyus, periodus - dutyus, periodus); // prom_printk("dutyCount = %d, periodCount - dutyCount = %d, periodCount = %d\n", dutyCount, periodCount - dutyCount, periodCount); @@ -140,14 +123,40 @@ HAL_StatusTypeDef HAL_PWM_setOneChannel(PWM_HandleTypeDef *hpwm, uint8_t ch) // prom_printk("perscale = %d\n", perscale); __HAL_PWM_CLK_CONFIG(hpwm, ch, perscale); - __HAL_PWM_SET_IDLE_LEVEL(hpwm, ch, !!hpwm->Init[ch].idleLevel); + __HAL_PWM_SET_IDLE_LEVEL(hpwm, ch, !hpwm->Init[ch].idleLevel); __HAL_PWM_SET_INIT_LEVEL(hpwm, ch, !hpwm->Init[ch].idleLevel); __HAL_SET_PWM_UPDATE_MODE(hpwm, ch, hpwm->Init[ch].Mode); if (hpwm->Init[ch].Mode == commonMode) { - __HAL_PWM_WAVEFORM_HIGH(hpwm, ch, dutyCount); - __HAL_PWM_WAVEFORM_LOW(hpwm, ch, (periodCount - dutyCount)); + /* 根据PWM时钟计算周期对应的寄存器count值 */ + periodCount = periodus * (PWMClock / US); + + /* 周期寄存器count值大于最大值需要进行分频,分频数2^perscale */ + while ((periodCount > PWM_DUTY_MAX_COUNT && perscale < 8)) { + periodCount >>= 1; + ++perscale; + } + + /* 最大分频2^7 */ + if (perscale == 8) { + prom_printk("pwm perscale bad value\n"); + return HAL_ERROR; + } + + /* 根据周期对应的count值计算占空比部分占的count值 */ + dutyCount = (periodCount * dutyus)/periodus; + + __HAL_PWM_WAVEFORM_HIGH(hpwm, ch, dutyCount); + __HAL_PWM_WAVEFORM_LOW(hpwm, ch, (periodCount - dutyCount)); } + + if (hpwm->Init[ch].Mode == dmaMode) { + __HAL_PWM_DMA_UNDER_IRQ_ENBLE(hpwm, ch); + __HAL_PWM_SET_FIFO_THROSHOLD(hpwm, ch); + __HAL_PWM_DMA_ASYNC_FIFO_FLUSH(hpwm, ch); + __HAL_PWM_DMA_FIFO_FLUSH(hpwm, ch); + HAL_DMA_Start(hpwm->DMA_Handle, hpwm->PWM_DMA_Config->Channel); + } } return HAL_OK; @@ -173,11 +182,13 @@ HAL_StatusTypeDef HAL_PWM_setConfig(PWM_HandleTypeDef *hpwm, PWM_InitTypeDef *co __HAL_Lock(&hpwm->Lock); for (uint8_t ch = 0; ch < __HAL_PWM_MAX_CHANNEL; ch++) { if (config->Channels & (0x01U << ch)) { - hpwm->Init[ch].isEnable = ENABLE; + hpwm->Init[ch].isEnable = ENABLE; hpwm->Init[ch].Mode = config->Mode; - hpwm->Init[ch].periodus = config->periodus; - hpwm->Init[ch].freq = US / config->periodus; - hpwm->Init[ch].dutyus = config->dutyus; + if(config->Mode == commonMode){ + hpwm->Init[ch].periodus = config->periodus; + hpwm->Init[ch].freq = US / config->periodus; + hpwm->Init[ch].dutyus = config->dutyus; + } } } __HAL_UnLock(&hpwm->Lock); @@ -254,6 +265,9 @@ HAL_StatusTypeDef HAL_PWM_Enable(PWM_HandleTypeDef *hpwm) for (int ch = 0; ch < __HAL_PWM_MAX_CHANNEL; ch++) { if (hpwm->Channels & 0x01U << ch) { + if (hpwm->Init[ch].Mode == dmaMode){ + __HAL_PWM_DMA_ENABLE_HW(hpwm, ch); + } __HAL_PWM_ENABLE_HW(hpwm, ch); } } diff --git a/projects/x16xx-halley6/Examples/pwm/CMakeLists.txt b/projects/x16xx-halley6/Examples/pwm/CMakeLists.txt index 6a10b6d4..003ca2d3 100644 --- a/projects/x16xx-halley6/Examples/pwm/CMakeLists.txt +++ b/projects/x16xx-halley6/Examples/pwm/CMakeLists.txt @@ -49,6 +49,7 @@ set(sources_SRCS # Modified ${SDK_PATH}/drivers/drivers-x16xx/src/x16xx_hal.c ${SDK_PATH}/drivers/drivers-x16xx/src/x16xx_hal_def.c ${SDK_PATH}/drivers/drivers-x16xx/src/x16xx_hal_pwm.c + ${SDK_PATH}/drivers/drivers-x16xx/src/x16xx_hal_pdma.c ${SDK_PATH}/drivers/drivers-x16xx/src/x16xx_ll_cpm.c ${SDK_PATH}/drivers/drivers-x16xx/src/x16xx_ll_ost.c ${SDK_PATH}/lib/libc/minimal/ctype.c diff --git a/projects/x16xx-halley6/Examples/pwm/Makefile b/projects/x16xx-halley6/Examples/pwm/Makefile index ac70b931..0f847ccf 100644 --- a/projects/x16xx-halley6/Examples/pwm/Makefile +++ b/projects/x16xx-halley6/Examples/pwm/Makefile @@ -38,6 +38,7 @@ $(SDK_PATH)/lib/libc/minimal/vsprintf.c \ $(SDK_PATH)/lib/libc/minimal/string.c \ $(SDK_PATH)/lib/libc/minimal/ctype.c \ $(SDK_PATH)/lib/libc/minimal/div64.c \ +$(SDK_PATH)/drivers/drivers-x16xx/src/x16xx_hal_pdma.c \ $(SDK_PATH)/drivers/drivers-x16xx/src/x16xx_hal_pwm.c \ main.c diff --git a/projects/x16xx-halley6/Examples/pwm/main.c b/projects/x16xx-halley6/Examples/pwm/main.c index ea400b88..fc60d8ed 100644 --- a/projects/x16xx-halley6/Examples/pwm/main.c +++ b/projects/x16xx-halley6/Examples/pwm/main.c @@ -1,42 +1,117 @@ #include #include +#define PWM_DMA_MODE + #define PWMx PWM_Instance PWM_HandleTypeDef PWM_Handle; PWM_InitTypeDef PWM_Config; +__align(32) uint32_t TxBuffer[] = { + 0x00320032, +}; + +#define MPLL_CLOCK 1400000000 + +DMA_HandleTypeDef DMA_Handle; +DMA_InitChannelConfTypeDef PWM_DMA_Config; +__align(32) DMA_DescriptorDef PWM_Tx_desc; +DMA_InitDescConfTypeDef PWM_Tx_descConfig; +void dma_tx_cb(struct __DMA_HandleTypeDef *hdma) +{ + CleanDCache_by_Addr((uint32_t *)TxBuffer, sizeof(TxBuffer)); + CleanInvalidateDCache_by_Addr((uint32_t *)TxBuffer, sizeof(TxBuffer)); + //prom_printk("**-------------------dma tx end\n"); + return; +} -#define MPLL_CLOCK 1200000000 +LL_CPM_CGU_ConfigTypeDef CGU_Config_PWM_140000000 = { + PWMCDR_MPLL, 13, 0 +}; + +void Pwm_Dma_Mode_Config(void) +{ + PWM_Handle.Instance = PWMx; + PWM_Handle.PWMColck = MPLL_CLOCK / 14; // 100M频率 + PWM_Handle.DMA_Handle = &DMA_Handle; + PWM_Handle.PWM_DMA_Config = &PWM_DMA_Config; + + prom_printk("pwmClock = %d\n", PWM_Handle.PWMColck); + PWM_Config.Channels = CHANNEL_5; + PWM_Config.idleLevel = PWMIdleLow; + PWM_Config.Mode = dmaMode; + + PWM_DMA_Config.XferCpltCallback = dma_tx_cb; + PWM_DMA_Config.data = NULL; + PWM_DMA_Config.DescMode = DESCRIPTOR; + PWM_DMA_Config.desc = &PWM_Tx_desc; + PWM_DMA_Config.descConfig = &PWM_Tx_descConfig; + PWM_DMA_Config.desc_count = sizeof(PWM_Tx_desc) / sizeof(DMA_DescriptorDef); + + PWM_Tx_descConfig.Desc_Interrupt = DMA_INTERRUPT; + PWM_Tx_descConfig.Desc_Link = LINK_CYCLE; + PWM_Tx_descConfig.DescDMATransferType = DMA_RQ_PWM5; + + PWM_Tx_descConfig.DescSrcAddress = TxBuffer; + PWM_Tx_descConfig.DescSrcAddrIncrement = DISABLE; + PWM_Tx_descConfig.DescSrcPortWidth = DMA_PORT_32BIT; + + PWM_Tx_descConfig.DescDstAddress = (void *)PWM_FIFO(&PWM_Handle,5); + PWM_Tx_descConfig.DescDstAddrIncrement = DISABLE; + PWM_Tx_descConfig.DescDstPortWidth = DMA_PORT_32BIT; + + PWM_Tx_descConfig.DescTransferNumByte = 4; + PWM_Tx_descConfig.DataLength = 1; + + DMA_Handle.Instance = DMA_Instance; +} -LL_CPM_CGU_ConfigTypeDef CGU_Config_PWM_120000000 = { - 0, 11, 0 -}; // SCLK_A是APLL,1.2G 11+1=12分频,100M +void Pwm_Common_Mode_Config(void) +{ + PWM_Handle.Instance = PWMx; + PWM_Handle.PWMColck = MPLL_CLOCK / 14; // 100M频率 + prom_printk("pwmClock = %d\n", PWM_Handle.PWMColck); + PWM_Config.Channels = CHANNEL_5; + PWM_Config.periodus = 2; + PWM_Config.dutyus = 1; + PWM_Config.idleLevel = PWMIdleLow; + PWM_Config.Mode = commonMode; +} int main(void) { + CleanDCache_by_Addr((uint32_t *)TxBuffer, sizeof(TxBuffer)); + CleanInvalidateDCache_by_Addr((uint32_t *)TxBuffer, sizeof(TxBuffer)); + int i = 0; prom_printk("hello world %s, %d\n", __func__, __LINE__); SET_BIT(TCU_Instance->TESR, 0x1); - prom_printk("DISABLE: %d\n", DISABLE); /* enable pwm clock gate */ CPM_GATE_Enable(CPM_Instance, CPM_CLKID_PWM); - + CPM_GATE_Enable(CPM_Instance, CPM_CLKID_PDMA); /* clock generation unit, Divider for PWM clock Frequency */ - CPM_CGU_PWM_Start(CPM_Instance, &CGU_Config_PWM_120000000); + CPM_CGU_PWM_Start(CPM_Instance, &CGU_Config_PWM_140000000); HAL_InitTick(); /* PWM5 PB19 func 2*/ LL_GPIO_getPinLevel(GPIOB_Instance, 19); LL_GPIO_setPinMode(GPIOB_Instance, 19, GPIO_MODE_FUNCTION2); - PWM_Handle.Instance = PWMx; - PWM_Handle.PWMColck = SYSCLK_APLL / 12; // 100M频率 - prom_printk("pwmClock = %d\n", PWM_Handle.PWMColck); - PWM_Config.Channels = CHANNEL_5; - PWM_Config.periodus = 2; - PWM_Config.dutyus = 1; - PWM_Config.idleLevel = PWMIdleLow; +#ifdef PWM_DMA_MODE + /*初始化DMA描述符*/ + Pwm_Dma_Mode_Config(); + /*初始化DMA*/ + HAL_DMA_Init(PWM_Handle.DMA_Handle); + /*申请DMA通道*/ + int ch; + if (PWM_Handle.PWM_DMA_Config != NULL) { + ch = HAL_DMA_requestChannel(PWM_Handle.DMA_Handle, PWM_Handle.PWM_DMA_Config); + prom_printk("--------------------------->>> %s %d tx ch = %d\n", __func__, __LINE__,ch); + } +#else + Pwm_Common_Mode_Config(); +#endif /* 设置PWM配置 */ HAL_PWM_setConfig(&PWM_Handle, &PWM_Config); @@ -47,16 +122,7 @@ int main(void) /* 使能PWM */ HAL_PWM_Enable(&PWM_Handle); - HAL_Delay(5000); - PWM_Config.Channels = CHANNEL_4; - PWM_Config.periodus = 20; - PWM_Config.dutyus = 10; - PWM_Config.idleLevel = PWMIdleLow; - - HAL_PWM_updateConfig(&PWM_Handle, &PWM_Config); - while (1) { - HAL_Delay(1000); HAL_Delay(3000); } -- Gitee