This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Part Number: MSP432P401R
I'm trying to use relatively high frequency PWM on the MSP432 Timer A. The PWM frequency is ~100kHz, and it's updated at a 20kHz rate, using the Systick interrupt.
It almost works, but the issue is that there is an occasional glitch in the duty cycle, probably when the duty cycle is updated. This is fatal for my application, so I was wondering if there's a glitchless way to update the PWM duty cycle? Or if that's not the issue what might be the root cause and solution?
I note that the MSP432 doesn't seem to have the double-buffered compare register structure that is typically used to avoid this problem, so I'm hoping that there is some workaround other than switching to a different device. Thanks!
The glitch:
The code: (Sorry, I'm an analog/power hardware guy, so probably not too elegant!)
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
#include <ti/devices/msp432p4xx/inc/msp.h>
/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
static volatile uint32_t aclk, mclk, smclk, hsmclk, bclk;
#define CPU_F ((double)48000000)
#define TIMER_A0_MODULE 0X4000
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
#define MaxPWMCount 460
#define refTick 1.0/60.0/((float)MaxPWMCount)/(1.0/48.0e6)
#define MaxPWMCountdiv2 MaxPWMCount/2
/* Timer_A PWM Configuration Parameter */
Timer_A_PWMConfig pwmConfig =
{
TIMER_A_CLOCKSOURCE_SMCLK,
TIMER_A_CLOCKSOURCE_DIVIDER_1,
MaxPWMCount,
TIMER_A_CAPTURECOMPARE_REGISTER_1,
TIMER_A_OUTPUTMODE_RESET_SET,
32
};
unsigned short sinTable[MaxPWMCount];
int sysTickCounter;
int sinIndex;
int loopCount;
float reference;
int main(void)
{
volatile unsigned int i;
MAP_WDT_A_holdTimer();
MAP_FPU_enableModule();
MAP_FPU_enableLazyStacking();
int i2;
//Set up the table of sin values to be used as a reference to the control system.
for(i2=0;i2<MaxPWMCount;i2++)
{
//sinTable[i2] = 800.0f/2.0f*(sin(((float)i2)/((float)MaxPWMCount)*2.0f*3.14159265f));
sinTable[i2] = (((float)MaxPWMCount)-20.0f)/2.0f*(sin(((float)i2)/((float)MaxPWMCount)*2.0f*3.14159265f)+1.0f)+10.0f;
}
/* Set the core voltage level to VCORE1 for max clock speed and performance */
MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);
/* Set 2 flash wait states for Flash bank 0 and 1*/
MAP_FlashCtl_setWaitState(FLASH_BANK0, 2);
MAP_FlashCtl_setWaitState(FLASH_BANK1, 2);
/* Initialize Clock System */
//Digitally Controlled Oscillator set to 48MHz
MAP_CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_48);
MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
MAP_CS_initClockSignal(CS_HSMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
MAP_CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
//-------------------------------------------------------------------------
/* Configuring GPIO2.4 as peripheral output for PWM and NOT P6.7 for button
* interrupt but pin 5 for debug output*/
MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN4,
GPIO_PRIMARY_MODULE_FUNCTION);
MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN5);
/* Configuring Timer_A */
MAP_Timer_A_generatePWM(TIMER_A0_BASE, &pwmConfig);
/* Enabling interrupts and starting the watchdog timer */\
MAP_Interrupt_enableMaster();
//*****************************SYSTICK SETUP********************************************
/* Configuring SysTick to trigger at 100kHz (48MHz clock freq) */
MAP_SysTick_enableModule();
MAP_SysTick_setPeriod((int)refTick*5);
MAP_SysTick_enableInterrupt();
P5->SEL0 |= BIT4;
P5->SEL1 |= BIT5;
P5->SEL0 |= BIT5;
P5->DIR &= ~BIT5;
P5->DIR &= ~BIT4;
// Enable global interrupt
__enable_irq();
while (1)
{
__no_operation();
}
}
void SysTick_Handler(void)
{
int loop;
sinIndex++;
if(sinIndex==MaxPWMCount) sinIndex = 0;
reference = sinTable[sinIndex];
TIMER_A0->CCR[1] = reference;
MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN5);
}
Hi,
We will look into it and get back to you ASAP. Please bear with us.
Thanks,
PM
Any update on this, or ETA for an update? The glitch is indeed due to updating the duty cycle.
Thanks,
JD
A workaround idea:
Have the same PWM signal go to an input pin. Turn on the interrupt for that pin on the rising edge. In the interrupt handler there, you write the new pulse width, then disable that interrupt again. You turn on the interrupt for that pin only when you want to change the Pulse Width.
I have seen the glitch on a different kind of chip before. It happens when the pulse width count is past the new pulse width you are writing. So the counter never equals the target number and the PWM just sails on past that number. By having the interrupt on the rising edge out of the PWM signal and changing the PWM then, the pulse counter doesn't have the chance to be anything but ZERO while you're writing the new value.
**Attention** This is a public forum