在线时间2226 小时
UID3253523
注册时间2016-3-21
NXP金币3266
该用户从未签到
超级版主
 
- 积分
- 25213
- 最后登录
- 2025-8-18
|
问题简介:
客户使用RT1020开发项目,需要RT1020按此顺序(300kHz,333kHz,375kHz,400kHz)生成频率变化的PWM,为了实现此目标,客户选择使用FlexIO模块,并且利用PIT生成10Hz的中断来更改输出的PWM频率,所以客户使用evkmimxrt1020_flexio_pwm工程进行验证,却在示波器观察到PWM的频率是在两个频率(333kHz和400kHz或300kHz和375kHz)之间切换,而并非预想中的四个。
当PIT的频率降低到1Hz时,虽然会观察到四个频率会依此出现,但偶尔也会跳过333 kHz。
在测试过程中,示波器上显示的频率改变的时间始终遵循着PIT周期。
具体代码如下:- const int Periods[4] = {300000, 333333, 375000, 400000};
- const int DutyCycle[4] = {50, 50, 50, 50};
- int pwmDitheringIdx = 0;
- void PWMModule_InitPWM()
- {
- // Init mux pin
- IOMUXC_SetPinMux(IOMUXC_PIN_PAD, 0U);
- IOMUXC_SetPinConfig(IOMUXC_PIN_PAD, 0x10B0u);
-
- // Init flexio
- CLOCK_SetMux(kCLOCK_Flexio1Mux, 3); // Select USB1 PLL CLK
- CLOCK_SetDiv(kCLOCK_Flexio1PreDiv, 1);
- CLOCK_SetDiv(kCLOCK_Flexio1Div, 1);
-
- flexio_config_t fxioUserConfig;
- FLEXIO_GetDefaultConfig(&fxioUserConfig);
- fxioUserConfig.enableFastAccess = true;
- FLEXIO_Init(PWM_FLEXIO, &fxioUserConfig);
-
- flexio_timer_config_t fxioTimerConfig;
- fxioTimerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0U);
- fxioTimerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
- fxioTimerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
- fxioTimerConfig.pinConfig = kFLEXIO_PinConfigOutput;
- fxioTimerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
- fxioTimerConfig.pinSelect = PWM_PIN; /* Set pwm output */
- fxioTimerConfig.timerMode = kFLEXIO_TimerModeDisabled;
- fxioTimerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
- fxioTimerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
- fxioTimerConfig.timerDisable = kFLEXIO_TimerDisableNever;
- fxioTimerConfig.timerEnable = kFLEXIO_TimerEnabledAlways;
- fxioTimerConfig.timerReset = kFLEXIO_TimerResetNever;
- fxioTimerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
- fxioTimerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
- fxioTimerConfig.timerCompare = computeTimerCompare(frequency, dutyCycle);
- FLEXIO_SetTimerConfig(PWM_FLEXIO, 0, &fxioTimerConfig);
- // Init Timer
- PIT_SetTimerPeriod(PIT, kPIT_Chnl_1, (24000000 / DITHERING_FREQUENCY) - 1);
- PIT_EnableInterrupts(PIT, kPIT_Chnl_1, kPIT_TimerInterruptEnable);
- EnableIRQ(PIT_IRQn);
- }
- void PIT_IRQHandler(void)
- {
- // Stop pwm
- PWM_FLEXIO->TIMCTL[0] &= 0xFFFFFFFC;
- // Update the frequency of the flexio.
- PWM_FLEXIO->TIMCMP[0] = FLEXIO_TIMCMP_CMP(computeTimerCompare(Periods[pwmDitheringIdx], DutyCycle[pwmDitheringIdx]));
-
- // Start pwm
- PWM_FLEXIO->TIMCTL[0] |= FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitPWM);
-
- pwmDitheringIdx = (pwmDitheringIdx + 1) % NUMBER_OF_FREQUENCY;
-
- // Clear IRQ flags
- PIT_ClearStatusFlags(PIT, kPIT_Chnl_1, kPIT_TimerFlag);
- }
- int computeTimerCompare(unsigned int frequency, unsigned int dutyCycle)
- {
- //The clock of the FLEXIO Timer[0] is the PLL3 (USB1) clock divided by the predivisor+1 (4+1) and the divisor (7+1)
- //The number of timer count (sum) required to generate the desired period is Timer[0]_Clock/[Desired Frequency]
- unsigned int sum = ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / (1 + 1U) / (1 + 1U)) * 2 / frequency + 1) / 2; //...*2+1)/2 -> Round to nearest
-
- //In 8-bit PWM high mode, the lower 8-bits configure the high period of the output to (CMP[7:0] + 1) and
- //the upper 8-bits configure the low period of the output to (CMP[15:8] + 1).
- //low/high period is the number of timer count where to output is low/high.
- //PWM output is hardware inverted...
- unsigned int lowerValue = (sum * dutyCycle / 50 + 1) / 2;
- unsigned int upperValue = sum - lowerValue;
- return ((upperValue -1) << | (lowerValue - 1);
- }
复制代码
问题解决:
分析上述描述,可得PIT中断周期的长短可能是主要原因,而为了更好的观测波形变化规律,小编使用逻辑分析仪而不是示波器来观察PWM波,确实复现了客户所说的现象。
在经过多次测试和代码浏览后发现,此现象是跟PIT中断函数未及时清零中断符号位有关,CPU时钟频率相比于IP总线时钟要大得多,CPU可能会在清除中断标志之前就已运行完中断处理程序了,从而导致CPU一次又一次进入处理程序。
所以需要在进入PIT中断函数后,跟着调用PIT_ClearStatusFlags(PIT, kPIT_Chnl_1, kPIT_TimerFlag);来清零中断符号位或者在上述函数调用后,执行_DSB()以保证在退出中断函数之前,中断符号位已清零,具体实现代码可参考如下。
- /*
- * Copyright (c) 2013 - 2015, Freescale Semiconductor, Inc.
- * Copyright 2016-2017 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include "fsl_device_registers.h"
- #include "fsl_debug_console.h"
- #include "fsl_flexio.h"
- #include "board.h"
- #include "fsl_pit.h"
- #include "pin_mux.h"
- #include "clock_config.h"
- /*******************************************************************************
- * Definitions
- ******************************************************************************/
- #define DEMO_TIME_DELAY_FOR_DUTY_CYCLE_UPDATE (2000000U)
- #define DEMO_FLEXIO_BASEADDR FLEXIO1
- #define DEMO_FLEXIO_OUTPUTPIN (5U) /* Select FLEXIO1_FLEXIO05 as PWM output */
- #define DEMO_FLEXIO_TIMER_CH (0U) /* Flexio timer0 used */
- /* Select USB1 PLL (480 MHz) as flexio clock source */
- #define FLEXIO_CLOCK_SELECT (3U)
- /* Clock pre divider for flexio clock source */
- #define FLEXIO_CLOCK_PRE_DIVIDER (4U)
- /* Clock divider for flexio clock source */
- #define FLEXIO_CLOCK_DIVIDER (7U)
- #define DEMO_FLEXIO_CLOCK_FREQUENCY \
- (CLOCK_GetFreq(kCLOCK_Usb1PllClk) / (FLEXIO_CLOCK_PRE_DIVIDER + 1U) / (FLEXIO_CLOCK_DIVIDER + 1U))
- /* FLEXIO output PWM frequency */
- #define DEMO_FLEXIO_FREQUENCY (48000U)
- #define FLEXIO_MAX_FREQUENCY (DEMO_FLEXIO_CLOCK_FREQUENCY / 2U)
- #define FLEXIO_MIN_FREQUENCY (DEMO_FLEXIO_CLOCK_FREQUENCY / 256U)
- /* Get source clock for PIT driver */
- #define PIT_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_OscClk)
- /*******************************************************************************
- * Prototypes
- ******************************************************************************/
- /*!
- * @brief Configures the timer as a 8-bits PWM mode to generate the PWM waveform
- *
- * @param freq_Hz PWM frequency in hertz, range is [FLEXIO_MIN_FREQUENCY, FLEXIO_MAX_FREQUENCY]
- * @param duty Specified duty in unit of %, with a range of [1, 99]
- */
- static void flexio_pwm_init(uint32_t freq_Hz, uint32_t duty);
- /*!
- * @brief Enables the timer by setting TIMOD to 8-bits PWM and start generating the PWM
- */
- static void flexio_pwm_start(void);
- /*******************************************************************************
- * Variables
- *******************************************************************************/
- unsigned int idx = 0;
- uint32_t freq[4] = {50000,48000,300000,400000};
- /*******************************************************************************
- * Code
- ******************************************************************************/
- static void flexio_pwm_init(uint32_t freq_Hz, uint32_t duty)
- {
- assert((freq_Hz < FLEXIO_MAX_FREQUENCY) && (freq_Hz > FLEXIO_MIN_FREQUENCY));
- uint32_t lowerValue = 0; /* Number of clock cycles in high logic state in one period */
- uint32_t upperValue = 0; /* Number of clock cycles in low logic state in one period */
- uint32_t sum = 0; /* Number of clock cycles in one period */
- flexio_timer_config_t fxioTimerConfig;
- /* Check parameter */
- if ((duty > 99) || (duty == 0))
- {
- duty = 50;
- }
- /* Configure the timer DEMO_FLEXIO_TIMER_CH for generating PWM */
- fxioTimerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0U);
- fxioTimerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
- fxioTimerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
- fxioTimerConfig.pinConfig = kFLEXIO_PinConfigOutput;
- fxioTimerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
- fxioTimerConfig.pinSelect = DEMO_FLEXIO_OUTPUTPIN; /* Set pwm output */
- fxioTimerConfig.timerMode = kFLEXIO_TimerModeDisabled;
- fxioTimerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
- fxioTimerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
- fxioTimerConfig.timerDisable = kFLEXIO_TimerDisableNever;
- fxioTimerConfig.timerEnable = kFLEXIO_TimerEnabledAlways;
- fxioTimerConfig.timerReset = kFLEXIO_TimerResetNever;
- fxioTimerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
- fxioTimerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
- /* Calculate timer lower and upper values of TIMCMP */
- /* Calculate the nearest integer value for sum, using formula round(x) = (2 * floor(x) + 1) / 2 */
- /* sum = DEMO_FLEXIO_CLOCK_FREQUENCY / freq_H */
- sum = (DEMO_FLEXIO_CLOCK_FREQUENCY * 2 / freq_Hz + 1) / 2;
- PRINTF("\r\n freq_Hz is %d,sum is %d\r\n",freq_Hz,sum);
- /* Calculate the nearest integer value for lowerValue, the high period of the pwm output */
- /* lowerValue = sum * duty / 100 */
- lowerValue = (sum * duty / 50 + 1) / 2;
- /* Calculate upper value, the low period of the pwm output */
- upperValue = sum - lowerValue;
- fxioTimerConfig.timerCompare = ((upperValue - 1) << 8U) | (lowerValue - 1);
- PRINTF("\r\n fxioTimerConfig.timerCompare is %d\r\n",fxioTimerConfig.timerCompare);
- FLEXIO_SetTimerConfig(DEMO_FLEXIO_BASEADDR, DEMO_FLEXIO_TIMER_CH, &fxioTimerConfig);
- }
- static void flexio_pwm_start(void)
- {
- /* Set Timer mode to kFLEXIO_TimerModeDual8BitPWM to start timer */
- DEMO_FLEXIO_BASEADDR->TIMCTL[DEMO_FLEXIO_TIMER_CH] |= FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitPWM);
- }
- /*!
- * @brief Main function
- */
- int main(void)
- {
- uint32_t i;
- uint32_t duty = 100;
- flexio_config_t fxioUserConfig;
- /* Init board hardware */
- BOARD_ConfigMPU();
- BOARD_InitPins();
- BOARD_BootClockRUN();
- BOARD_InitDebugConsole();
- /* Clock setting for Flexio */
- CLOCK_SetMux(kCLOCK_Flexio1Mux, FLEXIO_CLOCK_SELECT);
- CLOCK_SetDiv(kCLOCK_Flexio1PreDiv, FLEXIO_CLOCK_PRE_DIVIDER);
- CLOCK_SetDiv(kCLOCK_Flexio1Div, FLEXIO_CLOCK_DIVIDER);
- /* Init flexio, use default configure
- * Disable doze and fast access mode
- * Enable in debug mode
- */
- FLEXIO_GetDefaultConfig(&fxioUserConfig);
- FLEXIO_Init(DEMO_FLEXIO_BASEADDR, &fxioUserConfig);
- // Init Timer
- CLOCK_SetMux(kCLOCK_PerclkMux, 1U); // Take the osc clock source 24MHz
- CLOCK_SetDiv(kCLOCK_PerclkDiv, 0U); // divide the clock by 1
- pit_config_t pitConfig;
- PIT_GetDefaultConfig(&pitConfig);
- PIT_Init(PIT, &pitConfig);
- PIT_SetTimerPeriod(PIT, kPIT_Chnl_1, USEC_TO_COUNT(1000000U, PIT_SOURCE_CLOCK));
- PIT_EnableInterrupts(PIT, kPIT_Chnl_1, kPIT_TimerInterruptEnable);
- EnableIRQ(PIT_IRQn);
- PIT_StartTimer(PIT, kPIT_Chnl_1);
- PRINTF("\r\nFLEXIO_PWM demo start.\r\n");
- flexio_pwm_init(freq[idx], 50);
- flexio_pwm_start();
- while (1)
- {
- // flexio_pwm_init(DEMO_FLEXIO_FREQUENCY, --duty);
- // flexio_pwm_start();
- // for (i = 0; i < DEMO_TIME_DELAY_FOR_DUTY_CYCLE_UPDATE; i++)
- // {
- // __NOP();
- // }
- // if (duty == 0)
- // {
- // duty = 100;
- // }
- }
- }
- void PIT_IRQHandler(void)
- {
- PIT_ClearStatusFlags(PIT, kPIT_Chnl_1, kPIT_TimerFlag);
- idx = (idx + 1) % 4;
- PRINTF("\r\n idx is %d\r\n",idx);
- flexio_pwm_init(freq[idx], 50);
- flexio_pwm_start();
- /* Added for, and affects, all PIT handlers. For CPU clock which is much larger than the IP bus clock,
- * CPU can run out of the interrupt handler before the interrupt flag being cleared, resulting in the
- * CPU's entering the handler again and again. Adding DSB can prevent the issue from happening.
- */
- //__DSB();
- }
复制代码
|
|