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.

CCS/MSP432P401R: Sync PWM1 (TimerA0) and PWM2 (TimerA1)

Part Number: MSP432P401R


Tool/software: Code Composer Studio

Hello guys,

I'm doing a test program to better understand the microprocessor.

I'm using Sample - "uart_pc_echo" and "timer_a_pwm_mode" (driverlib). I am generating a PWM signal through TimerA0 and another PWM1 through dp TimerA1. The Uart communication configures the PERIOD and DUTY CYCLE of each PWM separately. When the program receives this information, it activates the PWMs, but they are not synchronized. I need this synchroniz because in the future I need to give an OFFset between these two signals.

I appreciate any help.

Thank you.

Follow the code:

/* DriverLib Includes */
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>

#define __SYSTEM_CLOCK 48000000 

//![Simple Timer_A Config]
/* Timer_A PWM Configuration Parameter */
Timer_A_PWMConfig pwmConfig =
{
TIMER_A_CLOCKSOURCE_SMCLK,
TIMER_A_CLOCKSOURCE_DIVIDER_2,
9650,
TIMER_A_CAPTURECOMPARE_REGISTER_1,
TIMER_A_OUTPUTMODE_RESET_SET,
965
};

//![Simple Timer_A Config]
/* Timer_A PWM Configuration Parameter */
Timer_A_PWMConfig pwmConfig1 =
{
TIMER_A_CLOCKSOURCE_SMCLK,
TIMER_A_CLOCKSOURCE_DIVIDER_2,
19300,
TIMER_A_CAPTURECOMPARE_REGISTER_1,
TIMER_A_OUTPUTMODE_RESET_SET,
1930
};


/* Statics */
const Timer_A_ContinuousModeConfig continuousModeConfig =
{
TIMER_A_CLOCKSOURCE_ACLK, // ACLK Clock Source
TIMER_A_CLOCKSOURCE_DIVIDER_1, // ACLK/1 = 32.768khz
TIMER_A_TAIE_INTERRUPT_ENABLE, // Enable Overflow ISR
TIMER_A_DO_CLEAR // Clear Counter
};


//![Simple UART Config]
/* UART Configuration Parameter. These are the configuration parameters to
* make the eUSCI A UART module to operate with a 9600 baud rate. These
* values were calculated using the online calculator that TI provides
* at:
*software-dl.ti.com/.../index.html
*/
const eUSCI_UART_Config uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
312, // BRDIV = 13
8, // UCxBRF = 0
0, // UCxBRS = 37
EUSCI_A_UART_NO_PARITY, // No Parity
EUSCI_A_UART_LSB_FIRST, // LSB First
EUSCI_A_UART_ONE_STOP_BIT, // One stop bit
EUSCI_A_UART_MODE, // UART mode
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION // Oversampling
};
//![Simple UART Config]

//Declaração de Operadores Globais
char matriz1[7] = {0, 0, 0, 0, 0, 0, 0};
int Start = 0;
int Cont = 0;
int atualizapwm1 = false;
int atualizapwm2 = false;
int ContimerA0 = 0;
int ContimerA1 = 0;
int atraso = 0;

int main(void)
{
/* Halting WDT */
MAP_WDT_A_holdTimer();

/* Selecting P1.2 and P1.3 in UART mode */
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);

//![Simple Timer_A Example]
/* Setting MCLK to REFO at 128Khz for LF mode
* Setting SMCLK to 128Khz */
MAP_CS_setReferenceOscillatorFrequency(CS_REFO_128KHZ);
MAP_CS_initClockSignal(CS_MCLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
MAP_CS_initClockSignal(CS_SMCLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
MAP_PCM_setPowerState(PCM_AM_LF_VCORE0);

/* Configuring GPIO2.4 as peripheral output for PWM and P1.1 for button
* interrupt */
MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN4,
GPIO_PRIMARY_MODULE_FUNCTION);
MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P7, GPIO_PIN7,
GPIO_PRIMARY_MODULE_FUNCTION);
MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1);
MAP_GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);


/* Configuring Timer_A to have a period of approximately 500ms and
* an initial duty cycle of 10% of that (3200 ticks) */
// MAP_Timer_A_generatePWM(TIMER_A0_BASE, &pwmConfig);
// MAP_Timer_A_generatePWM(TIMER_A1_BASE, &pwmConfig1);

//![Simple Timer_A Example]

/* Setting DCO to 48MHz */
FlashCtl_setWaitState( FLASH_BANK0, 2);
FlashCtl_setWaitState( FLASH_BANK1, 2);
PCM_setPowerState( PCM_AM_DCDC_VCORE1);
CS_setDCOCenteredFrequency( CS_DCO_FREQUENCY_48);
CS_setDCOFrequency(48000000);
CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, 1);
CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, 1);
CS_initClockSignal(CS_HSMCLK, CS_DCOCLK_SELECT, 1);

/* Configuring Continuous Mode */
MAP_Timer_A_configureContinuousMode(TIMER_A3_BASE, &continuousModeConfig);

//![Simple UART Example]
/* Configuring UART Module */
MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);

/* Enable UART module */
MAP_UART_enableModule(EUSCI_A0_BASE);

/* Enable interrupts */
MAP_Interrupt_enableInterrupt(INT_TA3_N);

/* Enabling interrupts */
MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
MAP_Interrupt_enableInterrupt(INT_EUSCIA0); 
MAP_Interrupt_enableInterrupt(INT_PORT1);


// MAP_Interrupt_enableSleepOnIsrExit(); 
MAP_Interrupt_enableMaster();
//![Simple UART Example]

/* Starting the Timer_A3 in continuous mode */
MAP_Timer_A_startCounter(TIMER_A3_BASE, TIMER_A_CONTINUOUS_MODE);

MAP_Timer_A_generatePWM(TIMER_A0_BASE, &pwmConfig);
MAP_Timer_A_generatePWM(TIMER_A0_BASE, &pwmConfig1);


while(true) //Rotina principal
{

}
}

void PORT1_IRQHandler(void)
{
uint32_t status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, status);
uint32_t txdatatemp = 0xff;
MAP_UART_transmitData(EUSCI_A0_BASE, txdatatemp);

}

/* EUSCI A0 UART ISR - Echoes data back to PC host */
void EUSCIA0_IRQHandler(void) 
{
uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE); 
uint32_t TXdata = 0x00; 

TXdata = MAP_UART_receiveData(EUSCI_A0_BASE); 

MAP_UART_clearInterruptFlag(EUSCI_A0_BASE, status); 
if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) 
{ //Se verdadeiro
if(TXdata == 0xAA)
{
Cont = 1;
}
else
{
if (TXdata == 0x55)
{
atualizapwm1 = true;
Cont = 0;
}
else
{
if(TXdata == 0x5A)
{
atualizapwm2 = true;
Cont = 0;
}
else
{
if (Cont == 1)
{
matriz1 [1] = TXdata;
MAP_UART_transmitData(EUSCI_A0_BASE, TXdata);
Cont = 2;
}
else
{
if (Cont == 2)
{
matriz1 [2] = TXdata;
MAP_UART_transmitData(EUSCI_A0_BASE, TXdata);
}
}
}
}
}
}
}

//******************************************************************************
//
//This is the TIMERA interrupt vector service routine.
//
//******************************************************************************
void TA3_N_IRQHandler(void)
{
MAP_Timer_A_clearInterruptFlag(TIMER_A3_BASE);
MAP_UART_transmitData(EUSCI_A0_BASE, 0xff);
if(atualizapwm1 == true)
{
pwmConfig.timerPeriod = matriz1[1] * 0xf1;
pwmConfig.dutyCycle = matriz1[2] * (pwmConfig.timerPeriod/0x64);
MAP_Timer_A_generatePWM(TIMER_A0_BASE, &pwmConfig);
MAP_UART_transmitData(EUSCI_A0_BASE, 0x06);
atualizapwm1 = false;
}
else
{
if(atualizapwm2 == true)
{
pwmConfig1.timerPeriod = matriz1[1] * 0xf1;
pwmConfig1.dutyCycle = matriz1[2] * (pwmConfig1.timerPeriod/0x64);
MAP_Timer_A_generatePWM(TIMER_A1_BASE, &pwmConfig1);
MAP_UART_transmitData(EUSCI_A0_BASE, 0x05);
atualizapwm2 = false;
}
}
}

  • Will,

     If you are trying program the two PWM periods separately, then how do you expect to maintain an offset between the signals? Ultimately one PWM would sweep across the other and you would not maintain a phase relationship that way.

    Assuming you keep the periods the same, then I would recommend that you use the same timer and just adjust the duty cycle using different Compare registers from the same Timer- there are 7-(CCU0-6) per Timer. The multi-PWM example from TI Resource Explorer is "timer_a_updown_compare_multiple_pwm.c". This shows the independent setting of CCUs to control two PWMs. You can also see this described in the MSP432P4 Technical Reference Manual in section 19.2.3.5. The diagram below is from that section and shows how the CCUs are configured to generate multiple PWMs.  

    If you really need two Timers (for fully independent Period, for example), then you can still set each Timer's CCUx registers to set and reset the output at selected points in the count.  You can also get the two timers to start at (almost) the same time by setting the TACLR bit in each register in quick succession. This would of course still introduce a small offset since the counters would be reset a few cycles apart, but it might be workable in your application.

    For your case using TA0 and TA1, once you've configured your counters, use the following code snippet to reset both counters 

    TIMER_A0->CTL |= TIMER_A_CTL_CLR;
    TIMER_A1->CTL |= TIMER_A_CTL_CLR; 

    Let me know if this solution would work for you. 

    Regards,

      Bob L.

  • Bob,

    Thanks for the clarifications, I understood about the timing between 2 different timers, I will do the project adjustment and I will work on the same timer.

    About PWM generation (compare_multiple_pwm) I do not see how I can vary the Phase Shifted between the two PWM signals. You can explaning for me?

    Thank you.
  • In its code, CCR3 and CCR4 do not change the PWM. Only the Value of CCR1 and CCR2 are required to generate the same signal. Am I doing something wrong?

    Follow the complete code and result Image-1.

    /* DriverLib Includes */
    #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
    
    /* Application Defines */
    #define PERIOD    1000
    #define PWM1PHASE  100
    #define PWM1DUTYC  100
    #define PWM2OFFSET 250
    #define PWM2DUTYC  100
    
    /* Timer_A UpMode Configuration Parameter */
    Timer_A_UpModeConfig upConfig =
    {
            TIMER_A_CLOCKSOURCE_SMCLK,                    // SMCLK Clock Source
            TIMER_A_CLOCKSOURCE_DIVIDER_1,              // SMCLK/1 = 3MHz
            PERIOD,                                                                  // 5000 tick period
            TIMER_A_TAIE_INTERRUPT_DISABLE,               // Disable Timer interrupt
            TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE ,  // Enable CCR0 interrupt
            TIMER_A_DO_CLEAR                                            // Clear value
    };
    
    const Timer_A_CompareModeConfig compareConfig_PWM1LH = {
      TIMER_A_CAPTURECOMPARE_REGISTER_1,                                      // Use CCR1
      TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,                      // Disable CCR interrupt
      TIMER_A_OUTPUTMODE_TOGGLE_SET,                                              // Set
      PWM1PHASE                                                                                             // LH edge at this point in the cycle
    };
    
    const Timer_A_CompareModeConfig compareConfig_PWM1HL = {
      TIMER_A_CAPTURECOMPARE_REGISTER_2,                                     // Use CCR2
      TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,                     // Disable CCR interrupt
      TIMER_A_OUTPUTMODE_TOGGLE_RESET,                                        // Reset
      PWM1PHASE + PWM1DUTYC                                                                // HL edge at this point in the cycle
    };
    
    const Timer_A_CompareModeConfig compareConfig_PWM2LH = {
      TIMER_A_CAPTURECOMPARE_REGISTER_3,                                     // Use CCR3
      TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,                     // Disable CCR interrupt
      TIMER_A_OUTPUTMODE_TOGGLE_SET,                                             // Set
      PWM1PHASE + PWM2OFFSET                                                              // LH edge at this point in the cycle
    };
    
    const Timer_A_CompareModeConfig compareConfig_PWM2HL = {
      TIMER_A_CAPTURECOMPARE_REGISTER_4,                                    // Use CCR4
      TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,                    // Disable CCR interrupt
      TIMER_A_OUTPUTMODE_TOGGLE_RESET,                                       // Reset
      PWM1PHASE + PWM2OFFSET + PWM2DUTYC                                  // HL edge at this point in the cycle
    };
    
    
    int main(void)
    {
        /* Stop WDT  */
        MAP_WDT_A_holdTimer();
    
        /* Setting P7.7 and P7.6 and peripheral outputs for CCR */
        MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P7,
                GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
    
        /* Configuring Timer_A1 for UpDown Mode and starting counter */
        MAP_Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig);
        MAP_Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_UP_MODE);
    
    
        /* Initialize compare registers to generate PWM1,2 */
        MAP_Timer_A_initCompare(TIMER_A1_BASE, &compareConfig_PWM1LH);
        MAP_Timer_A_initCompare(TIMER_A1_BASE, &compareConfig_PWM1HL);
        MAP_Timer_A_initCompare(TIMER_A1_BASE, &compareConfig_PWM2LH);
        MAP_Timer_A_initCompare(TIMER_A1_BASE, &compareConfig_PWM2HL);
    
        /* Sleeping when not in use */
        while (1)
        {
            MAP_PCM_gotoLPM0();
        }
    }

    The result:

    I understand the risks of not having "dead time", anyway thank you for letting me know! In my application I do not have this problem. Actually I need activate the two PWMs together sometimes. These Signals are used to trigger from image capture cameras.These signals are used to trigger image capture cameras.

    I've tried using several methods to generate these lagged signals between them, but so far I have not been able to.

    Thanks for your help!

  • I apologize for the confusion here. I've taken another look at the register set for the Timer, and it from this I see that you can only control 1 edge with the phase shift approach I've given above.  Since CCR0 (the period register) is always involved on one edge or another, you can't generate the pulses the way you've shown here. You CAN generate opposite-phase pulses that are offset by 180degrees, but you can't provide an arbitrary offset. Section 19.2.3.5 of the Technical Reference manual (below) shows how the offset can be created in the updown count mode using two different compare registers. You can see how to set this up using the timer_a_updown_compare_multiple_pwm example in TI Resource explorer. This kind of approach WILL work with output drives for motors, etc, since you can guarantee that both outputs will not be high at the same time by setting the CCUx thresholds appropriately.

    PS- I will delete my previous post that had the incorrect code so as not to confuse others who might read it.

    Regards,

      Bob L. 

  • I thought and found a way in which I can make the PWM offset. But now I can not get a faster pulse. I am using 48Mhz in the CS_MCLK which is used by Timer32 which generates the interrupt. But I need to work on very high frequencies in the range of 10Mhz. And so far I've only been able to generate a 100kHz wave.

    If anyone can parse the code, I'm grateful!

    /* 
     * MSP432 UART - PC Echo with 48MHz BRCLK
     *
     * Description: This demo echoes back characters received via a PC serial port.
     * SMCLK/DCO is used as a clock source and the device is put in LPM0
     * The auto-clock enable feature is used by the eUSCI and SMCLK is turned off
     * when the UART is idle and turned on when a receive edge is detected.
     * Note that level shifter hardware is needed to shift between RS232 and MSP
     * voltage levels.
     *
     *                 MSP432P401
     *             -----------------
     *            |                 |
     *            |           P1.1  |<----Toggle Switch
     *            |           P2.6  |----> Output PWM1
     *       RST -|           P2.4  |----> Output PWM2
     *            |                 |
     *            |     P1.3/UCA0TXD|----> PC (echo)
     *            |     P1.2/UCA0RXD|<---- PC
     *            |                 |
     *
    */
    /* DriverLib Includes */
    #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
    
    /* Standard Includes */
    #include <stdint.h>
    #include <stdbool.h>
    
    #define TIMER_PERIOD 1
    
    //!*******************[Simple UART Config]*******************************
    /* UART Configuration Parameter. These are the configuration parameters to
     * make the eUSCI A UART module to operate with a 9600 baud rate. These
     * values were calculated using the online calculator that TI provides
     * at:
     *software-dl.ti.com/.../index.html
     */
    const eUSCI_UART_Config uartConfig =
    {
            EUSCI_A_UART_CLOCKSOURCE_SMCLK,                 // SMCLK Clock Source
            312,                                            // BRDIV = 13
            8,                                              // UCxBRF = 0
            0,                                              // UCxBRS = 37
            EUSCI_A_UART_NO_PARITY,                         // No Parity
            EUSCI_A_UART_LSB_FIRST,                         // LSB First
            EUSCI_A_UART_ONE_STOP_BIT,                      // One stop bit
            EUSCI_A_UART_MODE,                              // UART mode
            EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION   // Oversampling
    };
    //!*******************[Simple UART Config]*******************************
    
    //Declaração de Operadores Globais
            char matriz1[7] = {0, 0, 0, 0, 0, 0, 0};
            int Cont = 0;
    
            int pwm1[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
            int index_pwm1 = 0;
            int laststatusOUT1 = 0;
    
            int pwm2[10] = {0, 0, 0, 0, 0, 1, 0, 0, 0, 0};
            int index_pwm2 = 0;
            int laststatusOUT2 = 0;
    
            int test = 0;
    
    
    
    int main(void)
    {
        /* Halting WDT  */
        MAP_WDT_A_holdTimer();
    
        /* Configuring GPIO */
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);
    
        /* Selecting P1.2 and P1.3 in UART mode */
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
                GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
    
            //![Simple CS Config]
            /* Configuring pins for peripheral/crystal usage and LED for output */
            MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
                    GPIO_PIN3 | GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION);
            /* Just in case the user wants to use the getACLK, getMCLK, etc. functions,
             * let's set the clock frequency in the code.
             */
            CS_setExternalClockSourceFrequency(48000000,48000000);
            /* Starting HFXT in non-bypass mode without a timeout. Before we start
             * we have to change VCORE to 1 to support the 48MHz frequency */
            MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);
            MAP_FlashCtl_setWaitState(FLASH_BANK0, 2);
            MAP_FlashCtl_setWaitState(FLASH_BANK1, 2);
            CS_startHFXT(false);
    
            /* Initializing MCLK to HFXT (effectively 48MHz) */
            MAP_CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);
            //![Simple CS Config]
    
    
            /* Configuring Timer32 to 128000 (1s) of MCLK in periodic mode */
            MAP_Timer32_initModule(TIMER32_BASE, TIMER32_PRESCALER_1, TIMER32_32BIT,
                                       TIMER32_PERIODIC_MODE);
    
    
        /* Configuring GPIO2.4 as peripheral output for PWM  and P1.1 for button
         * interrupt */
        //Output
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN6);
        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6);
    
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN4);
        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN4);
        //Input
        MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1);
        MAP_GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);
    
        //![Simple UART Example]
        /* Configuring UART Module */
        MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);
    
        /* Enable UART module */
        MAP_UART_enableModule(EUSCI_A0_BASE);
    
        /* Enabling interrupts */
        MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
        MAP_Interrupt_enableInterrupt(INT_EUSCIA0);                                 //Permite a Inicialização da interrupção da comunicação UART
        MAP_Interrupt_enableInterrupt(INT_PORT1);
        MAP_Interrupt_enableMaster();   
    
        /* Enabling interrupts */
        MAP_Interrupt_enableInterrupt(INT_T32_INT1);
    
        MAP_Timer32_setCount(TIMER32_BASE,TIMER_PERIOD);
        MAP_Timer32_enableInterrupt(TIMER32_BASE);
        MAP_Timer32_startTimer(TIMER32_BASE, false);
    
        /* Starting the Timer_A1 */
        MAP_Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_UP_MODE);
    
        while(true)                                                             //Rotina principal
        {
            test = CS_getSMCLK();
        }
    }
    
    
    
    void PORT1_IRQHandler(void)                                                 //Interrupção de acionamento da Chave P1.1
    {
        uint32_t status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, status);
            CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, 2);
            test = CS_getSMCLK();
        MAP_UART_transmitData(EUSCI_A0_BASE, 0xff);
    }
    
    /* EUSCI A0 UART ISR - Echoes data back to PC host */
    void EUSCIA0_IRQHandler(void)                                               //Interrupção acionada quando recebe valor em "MAP_UART_receiveData(EUSCI_A0_BASE)"
    {
        uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE);    //Gera uma variável local chamada status que recebe 1 quando a interrupção foi chamana
        uint32_t TXdata = 0x00;                                                 //Gera uma variável local chamada TXdata que recebe 0
    
        TXdata = MAP_UART_receiveData(EUSCI_A0_BASE);                           //Coloca o dado recebido da comunicação UART pelo "MAP_UART_receiveData(EUSCI_A0_BASE)" em TXdata
    
        MAP_UART_clearInterruptFlag(EUSCI_A0_BASE, status);                     //Limpa o status flag da interrupção
        if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)                        //Se a variável local "status" e status flag (EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) = 1
        {                                                                       //Se verdadeiro
            if(TXdata == 0xAA)
            {
                Cont = 1;
            }
            else
            {
                if (TXdata == 0x55)
                {
                    MAP_UART_transmitData(EUSCI_A0_BASE, 0xff);
                    Cont = 0;
                }
                else
                {
                    if(TXdata == 0x5A)
                    {
                        MAP_UART_transmitData(EUSCI_A0_BASE, 0xaa);
                        Cont = 0;
                    }
                    else
                    {
                        if (Cont == 1)
                        {
                            matriz1 [1] = TXdata;
                            MAP_UART_transmitData(EUSCI_A0_BASE, TXdata);
                            Cont = 2;
                        }
                        else
                        {
                            if (Cont == 2)
                            {
                                matriz1 [2] = TXdata;
                                MAP_UART_transmitData(EUSCI_A0_BASE, TXdata);
                            }
                        }
                    }
                }
            }
        }
    }
    
    //******************************************************************************
    //
    //This is the TIMERA interrupt vector service routine.
    //
    //******************************************************************************
    
    void T32_INT1_IRQHandler(void)
    {
    
        int out1 = pwm1[index_pwm1++];
    
        int out2 = pwm2[index_pwm2++];
    
        if(out1)
        {
            if(out2)
            {
                if(laststatusOUT1)
                {
                    if(laststatusOUT2)
                    {
                    }
                    else
                    {
                        GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN4);
                        laststatusOUT2 = true;
                    }
                }
                else
                {
                    if(laststatusOUT2)
                    {
                        GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6);
                        laststatusOUT1 = true;
                    }
                    else
                    {
                        GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6 + GPIO_PIN4);
                        laststatusOUT1 = true;
                        laststatusOUT2 = true;
                    }
                }
            }
            else
            {
                if(laststatusOUT1)
                {
                    if(laststatusOUT2)
                    {
                        GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN4);
                        laststatusOUT2 = false;
                    }
                    else
                    {
                    }
                }
                else
                {
                    if(laststatusOUT2)
                    {
                        GPIO_toggleOutputOnPin(GPIO_PORT_P2, GPIO_PIN6 + GPIO_PIN4);
                        laststatusOUT1 = true;
                        laststatusOUT2 = false;
                    }
                    else
                    {
                        GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6);
                        laststatusOUT1 = true;
                    }
    
                }
            }
        }
        else
        {
            if(out2)
            {
                if(laststatusOUT1)
                {
                    if(laststatusOUT2)
                    {
                        GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6);
                        laststatusOUT1 = false;
                    }
                    else
                    {
                        GPIO_toggleOutputOnPin(GPIO_PORT_P2, GPIO_PIN6 + GPIO_PIN4);
                        laststatusOUT1 = false;
                        laststatusOUT2 = true;
                    }
                }
                else
                {
                    if(laststatusOUT2)
                    {
                    }
                    else
                    {
                        GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN4);
                        laststatusOUT2 = true;
                    }
                }
            }
            else
            {
                if(laststatusOUT1)
                {
                    if(laststatusOUT2)
                    {
                        GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6 + GPIO_PIN4);
                        laststatusOUT1 = false;
                        laststatusOUT2 = false;
                    }
                    else
                    {
                        GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6);
                        laststatusOUT1 = false;
                    }
                }
                else
                {
                    if(laststatusOUT2)
                    {
                        GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN4);
                        laststatusOUT2 = false;
                    }
                    else
                    {
                    }
                }
            }
        }
        if(index_pwm1 >= 10)
        {
            index_pwm1 = 0;
        }
        else
        {
        }
        if(index_pwm2 >= 10)
        {
            index_pwm2 = 0;
        }
        else
        {
        }
        MAP_Timer32_clearInterruptFlag(TIMER32_BASE);
    }

  • there is no mechanism to "sync" across multiple timers - the approach provided earlier aligns two timers sufficiently closely, but not synchronized.

    the easiest way to perfect align two pwm signals is to generate them off the same timer, on different channels.
  • Hi Danny,

    Yes you are right. This timing problem between two different Timers is solved with the code above. Now the problem is the PWM frequency.

    I can not switch PWM outputs with higher frequencies with this code that I am using.

    The Processor is already running at 48Mhz and I still can not, for example, generate an output with 100ns of period for example.

    Anyway thanks a lot for your comments.

  • I think you aren't listening to bob landers' suggestion carefully. using timer32 interrupts to generate pwm will NOT get you anywhere to 10Mhz output, simply because of the overhead + ISR execution time.

    what bob was saying is to use the timera's output compare feature. take a look at the datasheet and read his suggestions.

    BTW, if you are really in need of 10Mhz pwm, rethink and triple-think of your approach and think of a dedicated pwm chip.
  • Will,

     What you are seeing in the 100kHz limitation is just the inherent difficulty of trying to use a CPU + interrupts to do something that dedicated peripherals / hardware are meant to do.  In this case, you are using the CPU to do the TIMERA capture/compare modules function.  

    If you really must have PWM frequencies as high as 10MHz, then you might want to switch to TI's C2000 products, which have a more feature-rich PWM module targeted at the industrial space, at the expense of additional power compared to the MSP432.  One example product is the TMS320F2837xS, (see datasheet).  The 2 features of interest here are the higher CPU clock (up to 200MHz) and (more importantly), an enhanced PWM module that can create the variable-phase-offset that you want from a pair of PWM outputs. The device also has a high-resolution comparator on some of the channels for edge placement beyond the 5MHz / 20ns resolution of the clock itself.  This might be overkill for your project, but if you're intested, you can get the F2837xS LaunchPad and try it out.  Note that the C2000 has its own processor architecture and driverlib API set, but it's fairly easy to pick up for someone familiar with MSP432 driverlib.

    Regards,

     Bob L.

**Attention** This is a public forum