Search code examples
cembeddedpwmlpcnxp-microcontroller

How to setup PWM output on an LPC11CXX series microcontroller without any timer resets


Background: I have this LPC11C24 microcontroller that I'm working on that uses a single 32 bit timer to read PWM input on one pin and control PWM outputs on 2 other pins. Being that input and output are on the same timer, I do not do any resets of the timer register (TC). For output in particular, I'm trying to set it up so that the match register will continuously increment with either the time when the signal should be HIGH or a signal is LOW respectfully.

Example: If I have a period of 10000 ticks and my duty cycle is 50%, every time I get an interrupt, I want to add 5000 to MR0 to prepare for the next interrupt.

Initialization:

IOCON_R_PIO1_1_bit.FUNC = 0;
IOCON_R_PIO1_1_bit.MODE = 0;  
GPIO1DIR_bit.P1_1 = 1;

LPC_TMR32B1->MCR |= (1<<0); /* Interrupt when MR0 matches TC */
LPC_TMR32B1->MR0 = 0; /* zero the match value */

ISR:

/* If interrupt was from MR0 */
if(LPC_TMR32B1->IR & (1<<0))
{
    /* Clear the interrrupt */
    LPC_TMR32B1->IR = (1<<0);

    if(GPIO1DATA_bit.P1_1 == 1)
    {
       LPC_TMR32B1->MR0 = LPC_TMR32B1->TC;
       LPC_TMR32B1->MR0 += OutputChan0MatchPeriodFalling;
       GPIO1DATA_bit.P1_1 = 0;
    }
    else if(GPIO1DATA_bit.P1_1 == 0)
    {
       LPC_TMR32B1->MR0 = LPC_TMR32B1->TC;
       LPC_TMR32B1->MR0 += OutputChan0MatchPeriodRising;
       GPIO1DATA_bit.P1_1 = 1;
    } 
}

When I probe this pin I get no output whatsoever, so I'm not sure what I'm doing wrong. Another problem I'm having is that I am not getting interrupts except for when I provide a new duty cycle from some external code (which basically just sets MR0 = TC). I think it's because TC is getting ahead of MR0 but I'm not sure how to prevent that. Thank you so much! Please let me know if I can provide any additional information.


Solution

  • I figured it out. There were 2 things going wrong here.

    The I/O configuration was incorrect. After reading the documentation, I found out that the function needs to be set to 1 for GPIO. 0 is a reserved function.

     IOCON_R_PIO1_1_bit.FUNC = 1;
    

    The second thing going wrong here was that I needed to pause the timer to process the ISR.

    /* If interrupt was from MR0 */
    if(LPC_TMR32B1->IR & (1<<0))
    {
        /* Pause timer */
        LPC_TMR32B1->TCR = 0; 
    
        /* Clear interrupt */
        LPC_TMR32B1->IR = (1<<0);
    
        if(GPIO1DATA_bit.P1_1 == 1)
        {
           LPC_TMR32B1->MR0 = LPC_TMR32B1->TC + OutputChan0MatchPeriodFalling;
           GPIO1DATA_bit.P1_1 = 0;
        }
        else if(GPIO1DATA_bit.P1_1 == 0)
        {
           LPC_TMR32B1->MR0 = LPC_TMR32B1->TC + OutputChan0MatchPeriodRising;
           GPIO1DATA_bit.P1_1 = 1;
        } 
    
        /* Restart timer */
        LPC_TMR32B1->TCR = 1; 
    }