LPC1768 PWM measurement - PWMAverage.h library - how to use different pins other than 29 + 30 that are shown in the example?

Hello, im newbie with mbed and i would like get some advice with customizing following library PWMAverage.h which i found in here:

https://os.mbed.com/cookbook/Accurately-measuring-duty-cycle#implementation

this library is used to measure dutycycle of incoming PWM signal on pins 29 and 30 on LPC1768 board.

I copy pasted the example code “PWMAverage_test - main.cpp” into my offline Mbed studio, compiled it and uploaded it into the LPC1768 board, send PWM signal and got the same result that i measured with osciloscope, so everything is nice in this part.

However, I ran into a problem with my application where im testing drivers of other NXP boards, where LPC1768 is used as verifying device that is recieving signals from the tested board (not important for this matter tho, i think). Im already using pin 30 during SPI bus tests that are provided from microsoft and i dont really want to interfere much with their implementation of those tests → therefore pin 30 is not available for me (I tried connecting both at the same time and SPI tests stopped working, even when i ran the tests separately - so i excluded the possibility of using the pin 30).

(I suppose that a workaround could be a simple HW relay switching between PWM and SPI wires used in those tests, but i would love to solve this with just software change with no additional HW components)

**So, I wanted to ask, how can i accomplish same behaviour of the example using different pins of the LPC1768 board (or if it can be accomplished at all). ** I tried modifying the code

PWMAverage pa(p29,p30);
to
PWMAverage pa(p15,p16);

= to different pin numbers and physically connect then to pwm signal input and got no results (i guess it has something to do with Timer 2 judging from " In this example we are using Timer 2 and therefore pins 30 and 29 ." sentence in the article.).

Can anyone please help me, what to change (my guess in the library .cpp file) so i can use different pins for this?

Thank you very much.
(Sorry for long post, i hope i described the problem enough, never used programming forum before :D)

1 Like

Unfortunately that library completely ignores the pins you pass it in the constructor and uses hard coded pins.

The actual pins are set in PWMAverage.cpp PWMAverage.cpp

Physical pins 15 and 16 are connected to IO pins 0_23 and 0_24 (port 0, pin 23/24), these are Timer 3 capture pins 0 and 1 and so are the timer 3 equivalent of the pins currently used. From memory timer 3 may be used by the mbed system so reconfiguring that timer that could break things.
It looks like Timer 0 and 1’s capture inputs aren’t available on this board.

To try this change you’d need to change all the references in the library from LPC_TIM2 to LPC_TIM3 and then change PWMAverage::configure() to power the correct part of the chip (line 111) set the appropriate pin mux modes for the IO pins used (115/116), set the timer input source (120) double check the timer mode options (128, 132).

You would need to refer to the LPC 1768 user manual for the exact values needed for these settings.

To be honest it would probably be a lot easier to move the SPI bus to different pins.

1 Like

Hello AndyA,

thank you for you answer, Im trying the way u described first with using Timer 3. (because the SPI tests that are running on the desk are from microsoft (SPI WinRT Clock Frequency Verification Tests (mbed LPC1768 Required) | Microsoft Learn) and are even more hardcoded to pin 30 than this this simple test im trying to implement. I tried to extract the information from datasheet of the board

https://www.nxp.com/docs/en/user-guide/UM10360.pdf

and change the library as you described, but im still not successful with it.
I changed:

  • every LPC_TIM2 → LPC_TIM3

  • LPC_SC->PCONP |= (1<<22); → LPC_SC->PCONP |= (1<<23);
    (page 65/851 in datasheet)

  • LPC_PINCON->PINSEL0 |= (0x3<<8); → LPC_PINCON->PINSEL1 |= (0x3<<14);
    LPC_PINCON->PINSEL0 |= (0x3<<10); → LPC_PINCON->PINSEL1 |= (0x3<<16);
    (page 118/851)

  • LPC_SC->PCLKSEL1 |= (0x1<<12); → LPC_SC->PCLKSEL1 |= (0x1<<14);
    (page 59/851)

Did I forget something or made a mistake somewhere? I still dont get any measurements.

My current code in PWMAverage.cpp (i kept the original code in comments for comparison):

#include “PWMAverage.h”
#define PWMA_PCLK 96000000

PWMAverage * PWMAverage::instance;

void PWMAverage::_tisr()
{
//printf(“.”);
//int cr0 = LPC_TIM2->CR0;
//int cr1 = LPC_TIM2->CR1;
int cr0 = LPC_TIM3->CR0;
int cr1 = LPC_TIM3->CR1;

//LPC_TIM2->IR = 0x3F;   //111111
LPC_TIM3->IR = 0x3F;

//LPC_TIM2->TCR = 3;
//LPC_TIM2->TCR = 1;
LPC_TIM3->TCR = 3;
LPC_TIM3->TCR = 1;

//LPC_NVIC->ICPR0 |= (1<<3)

if(!instance->starting)
{
instance->total += cr1 + 82;
instance->totalup += cr0 + 82;
instance->count_++;
}
else instance->starting = false;
}

PWMAverage::PWMAverage(PinName cap0, PinName cap1)
{
prescaler_point = 0x0;
configure();
stop();

timeMult = (1/PWMA_PCLK)*(prescaler_point+1);
timeDiv = PWMA_PCLK/(prescaler_point+1);
instance = this;

}
void PWMAverage::reset()
{
count_ = 0;
total = 0;
totalup = 0;
//LPC_TIM2->TCR = 2;
//LPC_TIM2->TCR = 0;
LPC_TIM3->TCR = 2;
LPC_TIM3->TCR = 0;
}

void PWMAverage::start()
{
//reset();
starting = true;
enable(true);
//NVIC_EnableIRQ(TIMER2_IRQn);
NVIC_EnableIRQ(TIMER3_IRQn);
}

void PWMAverage::stop()
{
enable(false);
//NVIC_DisableIRQ(TIMER2_IRQn);
NVIC_DisableIRQ(TIMER3_IRQn);
}

float PWMAverage::read()
{
if(period() != 0) return float(avg_up()/period());
else return 0;
}

double PWMAverage::avg_up()
{
if(count_!= 0) return (double(totalup)/timeDiv)/double(count_);
else return 0;

}

float PWMAverage::avg_UP()
{
if(count_!= 0) return float((double(totalup)/timeDiv)/double(count_));
else return 0;
}

double PWMAverage::avg_down()
{
if(count_!= 0) return (double(total-totalup)/timeDiv)/double(count_);
else return 0;
}

double PWMAverage::period()
{
if(count_!= 0) return (double(total)/timeDiv)/double(count_);
else return 0;
}

int PWMAverage::count()
{
return count_;
}

void PWMAverage::enable(bool yn)
{
//LPC_TIM2->TCR = yn;
LPC_TIM3->TCR = yn;
}

void PWMAverage::configure()
{
//Power Periferal
//LPC_SC->PCONP |= (1<<22);
LPC_SC->PCONP |= (1<<23); //str 65/851 PCTIM

//Setup Pins
//LPC_PINCON->PINSEL0 |= (0x3<<8);
//LPC_PINCON->PINSEL0 |= (0x3<<10);
LPC_PINCON->PINSEL1 |= (0x3<<16);
LPC_PINCON->PINSEL1 |= (0x3<<14);

//Setup clock source
//LPC_SC->PCLKSEL1 |= (0x1<<12);
LPC_SC->PCLKSEL1 |= (0x1<<14);

//Setup PC 
//LPC_TIM2->PR = prescaler_point;
LPC_TIM3->PR = prescaler_point;

//Setup CAP0 - Store on fall
//LPC_TIM2->CCR |= 0x2; 
LPC_TIM3->CCR |= 0x2; 

//Setup CAP1 - Store on rise, interrupt
//LPC_TIM2->CCR |= 0x5<<3;
LPC_TIM3->CCR |= 0x5<<3;

//Setup IRQs
//NVIC_DisableIRQ(TIMER2_IRQn);
//NVIC_SetVector(TIMER2_IRQn, (uint32_t)&_tisr);
//NVIC_EnableIRQ(TIMER2_IRQn);
NVIC_DisableIRQ(TIMER3_IRQn);
NVIC_SetVector(TIMER3_IRQn, (uint32_t)&_tisr);
NVIC_EnableIRQ(TIMER3_IRQn);

}

Thank you for any useful comments :slight_smile:

I can’t see anything obvious :frowning:

Did you connect the pins up the correct way around? The order is switched.
The old pinout was p29 (cap2.1) and p30 (cap2.0)
The new pinout is p15 (cap3.0) and p16 (cap3.1)

So the signal on p30 should now be on p15 and the signal on p29 should be on p16.

Hello,

As Andy says, Timer3 is used by the system for the US_TICKER_TIMER. Maybe Timer3 shall be replaced with Timer2 in the /targets/TARGET_NXP/TARGET_LPC176X/us_ticker.c file (when using Mbed OS 2), if Timer2 was replaced with Timer3 in the PWMAverage.cpp library file, in order not to use the same timer (Timer3) for both the US_TICKER_TIMER and for the PWMAverage. That can be accomplished via mbed_app.json configuration file:

{
    "target_overrides": {
        "*": {
            "target.us-ticker-timer": 2
        }
    }
}