LPC1769 Capture Timer

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC1769 Capture Timer

2,549 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Tue Feb 28 21:07:07 MST 2012
In my project, I am trying to send a music file to a VS1053b when it's data request pin (DREQ) goes high. As I got the idea originally from a tutorial on Sparkfun, I am using the same method to catch this event, which is to attach it to CAP0.0. When it didn't work, I tried pulling the pin high/low manually and still could not get it to work. I am using CMSIS 1.3 and the LPC17xx CMSIS Driver Library and have copied over the relevant code:

[LEFT][COLOR=#005032][COLOR=#005032]TIM_TIMERCFG_Type [/COLOR][/COLOR]TIM_ConfigStruct;
[COLOR=#005032][COLOR=#005032]TIM_CAPTURECFG_Type[/COLOR][/COLOR] TIM_CaptureConfigStruct;[/LEFT]
 
[LEFT]LPC_PINCON->[COLOR=#0000c0][COLOR=#0000c0]PINSEL3[/COLOR][/COLOR] |= (0x20300015); [/LEFT]
 
[LEFT]TIM_ConfigStruct.[COLOR=#0000c0][COLOR=#0000c0]PrescaleOption[/COLOR][/COLOR] = [I][COLOR=#0000c0][COLOR=#0000c0]TIM_PRESCALE_TICKVAL[/COLOR][/COLOR][/I];
TIM_ConfigStruct.[COLOR=#0000c0][COLOR=#0000c0]PrescaleValue[/COLOR][/COLOR] = 125;[/LEFT]
 
[LEFT]TIM_CaptureConfigStruct.[COLOR=#0000c0][COLOR=#0000c0]CaptureChannel[/COLOR][/COLOR] = 0;
TIM_CaptureConfigStruct.[COLOR=#0000c0][COLOR=#0000c0]RisingEdge[/COLOR][/COLOR] = [I][COLOR=#0000c0][COLOR=#0000c0]ENABLE[/COLOR][/COLOR][/I];
TIM_CaptureConfigStruct.[COLOR=#0000c0][COLOR=#0000c0]FallingEdge[/COLOR][/COLOR] = [I][COLOR=#0000c0][COLOR=#0000c0]DISABLE[/COLOR][/COLOR][/I];
TIM_CaptureConfigStruct.[COLOR=#0000c0][COLOR=#0000c0]IntOnCaption[/COLOR][/COLOR] = [I][COLOR=#0000c0][COLOR=#0000c0]ENABLE[/COLOR][/COLOR][/I];[/LEFT]
 
[LEFT]TIM_Init(LPC_TIM0, [I][COLOR=#0000c0][COLOR=#0000c0]TIM_TIMER_MODE[/COLOR][/COLOR][/I], &TIM_ConfigStruct);
TIM_ConfigCapture(LPC_TIM0, &TIM_CaptureConfigStruct);[/LEFT]
 
[LEFT]NVIC_SetPriority([I][COLOR=#0000c0][COLOR=#0000c0]TIMER0_IRQn[/COLOR][/COLOR][/I], ((0x01<<3)|0x01));
NVIC_EnableIRQ([I][COLOR=#0000c0][COLOR=#0000c0]TIMER0_IRQn[/COLOR][/COLOR][/I]);[/LEFT]
 
[LEFT]TIM_ResetCounter(LPC_TIM0); 
TIM_Cmd(LPC_TIM0, [I][COLOR=#0000c0][COLOR=#0000c0]ENABLE[/COLOR][/COLOR][/I]);[/LEFT]
 
[LEFT]...[/LEFT]
 
[LEFT][B][COLOR=#7f0055][COLOR=#7f0055]void [/COLOR][/COLOR][/B][B]TIMER0_IRQHandler[/B]([B][COLOR=#7f0055][COLOR=#7f0055]void[/COLOR][/COLOR][/B]) {
 [B][COLOR=#7f0055][COLOR=#7f0055]if[/COLOR][/COLOR][/B] (TIM_GetIntCaptureStatus(LPC_TIM0, 0) == [I][COLOR=#0000c0][COLOR=#0000c0]SET[/COLOR][/COLOR][/I]) {
   [B][COLOR=#7f0055][COLOR=#7f0055]while[/COLOR][/COLOR][/B](LPC_GPIO1->[COLOR=#0000c0][COLOR=#0000c0]FIOPIN[/COLOR][/COLOR] & (1<<26)){
     SDtoCoProcessor();
   }
 }
 TIM_ClearIntCapturePending(LPC_TIM0, 0);
 [B][COLOR=#7f0055][COLOR=#7f0055]return[/COLOR][/COLOR][/B];
}[/LEFT]


[LEFT]When I stick a breakpoint on the handler function it never hits it even when I manually toggle the capture pin. As a last ditch I can try to simply connect DREQ to any old GPIO setup as an external interrupt but this should work either way. Any help is appreciated here especially as I am already late on getting this project done.[/LEFT]
0 Kudos
22 Replies

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Tue Mar 06 09:48:20 MST 2012
I did some more testing last night and P1.26 never goes high in the register as a GPIO input as well. I even set it up as an output and my meter only moved from 0v0 to 0v3 on the change. I don't know what is going on with my chip but that is possibly why the capture timer does not work.

I would like to at least get the GPIO interrupt working for P2.12 but failing that I am currently just checking FIOPIN on every cycle so I can at least move forward with my project. Alternatively, since I only need to interrupt on rising edge, I may setup P2.12 as EINT2.
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Sun Mar 04 21:53:20 MST 2012
I'm apparently looking at 2 problems:

1) P2.13 seems to never go high in the register; input or output, even on hardware reset. Switching over to P2.12 lets me see it in the register. I have no idea why P2.13 doesn't work but I guess I can work around it.
2) It seems to not take the enable GPIO interrupt settings. After I've set the appropriate bits, IO2IntEnF/R both remain 0x0. I tried IO0IntEnf/R as well with the same results. This is the bigger problem obviously.

I have no idea why the GPIO interrupt settings won't take but getting them to work should get me out of my hole. Alternatively, switching back to capture timer would also work if I wasn't having problems there as well.
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Sun Mar 04 14:46:34 MST 2012
Last trial:

#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif

#include <cr_section_macros.h>
#include <NXP/crp.h>

__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

//LED
#define LED     (1 << 22)
#define LED_ON     LPC_GPIO0->FIOSET=LED
#define LED_OFF    LPC_GPIO0->FIOCLR=LED
#define LED_TOG    LPC_GPIO0->FIOPIN^=LED

//TEST
#define TEST     (1 << 28)
#define TEST_ON  LPC_GPIO0->FIOSET=TEST
#define TEST_OFF LPC_GPIO0->FIOCLR=TEST
#define TEST_TOG LPC_GPIO0->FIOPIN^=TEST


void EINT3_IRQHandler(void) // Note: EINT3 channel is shared with GPIO interrupts
{
 if(LPC_GPIOINT->IO2IntStatR &(1<<13))//read only rising edge status
 {
  LPC_GPIOINT->IO2IntClr =(1<<13); //reset interrupt
  LED_ON;
 }
 if(LPC_GPIOINT->IO2IntStatF &(1<<13))//read only falling edge status
 {
  LPC_GPIOINT->IO2IntClr =(1<<13); //reset interrupt
  LED_OFF;
 }
}

int main(void)
{
 LPC_GPIO0->FIODIR |= (LED | TEST);        //LED, TEST output
//GPIO interrupt
 LPC_GPIOINT->IO2IntEnF|=(1<<13); //enable falling edge
 LPC_GPIOINT->IO2IntEnR|=(1<<13); //enable rising edge
 NVIC_EnableIRQ(EINT3_IRQn);      //enable GPIO interrupt, Note: EINT3 channel is shared with GPIO interrupts
 volatile static int i = 0 ;
 while(1)
 {
  i++;                            //inc counter
  if(i>5000000)                    //delay
  {
   TEST_TOG;                    //toggle TEST output P0.28 = J6-26
   i=0;                            //reset counter
  }                                //end delay
 }
 return 0 ;
}
I've added a slow switching (~1 second) output P0.28 (J6-26). If connected with P2.13 (J6-27) GPIO Interrupt is switching LED2.

If that's not working and scoping J6-26 shows valid falling and rising edges your hardware is faulty

Of course you could try to change GPIO interrupt pin to another port0/2 pin
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Sun Mar 04 14:00:19 MST 2012
I copied your .axf  file into one of my sample projects then uploaded it by right-clicking on it and selecting "Build Utilities>Program Flash..." with the default settings. I then jumpered J6-27 (P2.13) to J6-1 (GND) and did not see any difference (LED2 remained on). Should I be contacting support at this point?
0 Kudos

1,642 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Sat Mar 03 23:18:13 MST 2012
This is the zipped axf of GPIO interrupt as described above.

LPCXpresso LED is showing there grounding of P2.13 (J6-27).

If that's not working your hardware is faulty :eek:
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Sat Mar 03 22:15:09 MST 2012
Argh! I created 2 new "NXP LPC1700 C Projects", one for each scenario using the code provided, and neither worked. I'm at my wits' end. Checking LPC_GPIO2->FIOPIN still registers 0x00001fff regardless of how the pin is tied when I'm doing the GPIO interrupt method as well.
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Fri Mar 02 08:15:26 MST 2012

Quote: NineBall
When I am manually toggling it for testing I simply jumper the input pin straight to ground or 3V3 and confirmed with my meter.



That's too difficult for me :rolleyes:

Since it's a pull-up I just use an Alligator Clip Test Lead  to ground it. To make it more colorful I scope input and output meanwhile :)
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Fri Mar 02 07:59:17 MST 2012
When I checked it yesterday, everything was in it's default position (pull-up enabled in normal mode). When I am manually toggling it for testing I simply jumper the input pin straight to ground or 3V3 and confirmed with my meter. Should I be using a different mode?
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Fri Mar 02 07:32:44 MST 2012
PINMODE :rolleyes:
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Fri Mar 02 07:25:27 MST 2012
I wish :(

Like I said, I checked the PINSEL registers and everything checks out. I didn't manually set it and I'm not at home so I can't check it, but PCONP should already be configured for PCTIM0 and PCGPIO.

You do bring up a good point though. I'll create a new project that does just this first and then move the changes into my main project. In case it matters, I'm still using LPCXpresso IDE 3.6 with CMSIS 1.3 and the matching NXP driver library instead of the newest of everything.
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Thu Mar 01 23:17:25 MST 2012
You're kidding :)

Both samples has been tested here and are working in a new LPCXpresso CMSIS project. Did you check PINSEL and PCONP settings?
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Thu Mar 01 20:48:07 MST 2012
So...neither way worked. After having switched to the GPIO mode, I stuck a breakpoint on my main loop and 0x2009c054 (LPC_GPIO2->FIOPIN) always reads 0x00001FFE regardless of whether I have P2.13 tied high or low. What on earth could be causing this? Checking the registers just to confirm, it is definately setup as a GPIO input pin.
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Thu Mar 01 12:36:29 MST 2012

Quote: NineBall
I did mention that at the end of my first post. I would either have to set it up as an external interrupt or use a timer and check it often.



Yes, was reading this already A lot of samples I've seen don't use an interrupt to read DREQ. But anyway, that's not my problem :rolleyes:

This is an easy sample how to use capture interrupt:
//LED
#define LED     (1 << 22)
#define LED_ON     LPC_GPIO0->FIOSET=LED
#define LED_OFF    LPC_GPIO0->FIOCLR=LED
#define LED_TOG    LPC_GPIO0->FIOPIN^=LED

void TIMER0_IRQHandler(void)
{
 uint32_t reg_val;
 reg_val = LPC_TIM0->IR;
 if(reg_val & (1<<4))            //CR0 interrupt
 {
  if(LPC_GPIO1->FIOPIN & (1<<26))//high?
  {
   LED_ON;
  }
  else
  {
   LED_OFF;
  }
  LPC_TIM0->IR = (1<<4);        //reset interrupt
 }
}

int main(void)
{
 LPC_GPIO0->FIODIR |= LED;        //LED output
 volatile static int i = 0 ;
//setup timer 0 capture
//Setup P1.26 as CAP0.0
 LPC_PINCON->PINSEL3 |= (3<<20);    //set capture 0.0
//Note: reset values of timer registers are 0, so setting them isn't necessary
 LPC_TIM0->CCR =((1<<0)|(1<<1)|(1<<2));        //capture rising & falling with interrupt
 LPC_TIM0->TCR = 1;                //start timer
 NVIC_EnableIRQ(TIMER0_IRQn);
 while(1)
 {
  i++ ;
 }
 return 0 ;
}
Of course the easier approach would be a simple interrupt. Unfortunately external interrupts can't be used to detect rising and falling edge.
So the solution is GPIO Interrupt with Port0 or Port2.

Sample below shows how elegant GPIO Interrupts work

//LED
#define LED     (1 << 22)
#define LED_ON     LPC_GPIO0->FIOSET=LED
#define LED_OFF    LPC_GPIO0->FIOCLR=LED
#define LED_TOG    LPC_GPIO0->FIOPIN^=LED

void EINT3_IRQHandler(void) // Note: EINT3 channel is shared with GPIO interrupts
{
 if(LPC_GPIOINT->IO2IntStatR &(1<<13))//read only rising edge status
 {
  LPC_GPIOINT->IO2IntClr =(1<<13); //reset interrupt
  LED_ON;
 }
 if(LPC_GPIOINT->IO2IntStatF &(1<<13))//read only falling edge status
 {
  LPC_GPIOINT->IO2IntClr =(1<<13); //reset interrupt
  LED_OFF;
 }
}

int main(void)
{
 LPC_GPIO0->FIODIR |= LED;        //LED output
//GPIO interrupt P2.13
 LPC_GPIOINT->IO2IntEnF|=(1<<13); //enable falling edge
 LPC_GPIOINT->IO2IntEnR|=(1<<13); //enable rising edge
 NVIC_EnableIRQ(EINT3_IRQn);      //enable GPIO interrupt, Note: EINT3 channel is shared with GPIO interrupts
 volatile static int i = 0 ;
 while(1)
 {
  i++ ;
 }
 return 0 ;
}
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Thu Mar 01 10:48:26 MST 2012

Quote: Zero
Isn't it enough just to read DREQ pin?



I did mention that at the end of my first post. I would either have to set it up as an external interrupt or use a timer and check it often. As I have it in TIMER0_IRQHandler, I basically do just keep checking until it goes low and then start again on the next rising edge. This project has been my first foray into embedded development however and has been a great learning experience. Even if I switched over to one of the above options over using a capture timer, I would still like to get it working.


Quote: gbm
What you really need to do is:
- set PINSEL register for capture function
- (optionally) set PINMODE to configure pullup/-down
- set timer prescaler
- set capture on the right edge function and enable capture interrupt
- start the timer (TCR = 1)
- enable timer interrupt in NVIC



Ultimately, the code I posted is doing what you say here but I am not hitting TIMER0_IRQHandler. I will try doing a manual version, stripped down as you suggest, when I get home tonight but what else could I be doing wrong that this isn't working?
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Thu Mar 01 06:51:43 MST 2012

Quote: NineBall
...As I got the idea originally from a tutorial on Sparkfun, I am using the same method to catch this event...



Isn't it enough just to read DREQ pin?
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gbm on Thu Mar 01 03:32:40 MST 2012
What you really need to do is:
- set PINSEL register for capture function
- (optionally) set PINMODE to configure pullup/-down
- set timer prescaler
- set capture on the right edge function and enable capture interrupt
- start the timer (TCR = 1)
- enable timer interrupt in NVIC

this may be done with 6 simple assignments to registers or with 5 assignments and NVIC CMSIS pseudocall, no ANDs, no ORs, no shifts, no typecasts.
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Wed Feb 29 20:55:27 MST 2012
I have gone through and transcoded what the driver library timer functions are actually doing. Hopefully this will help you guys to help me with my problem.

// TIM_Init(...) {
LPC_TIM0->CCR &= ~0x3;
LPC_TIM0->CCR |= 0;
LPC_TIM0->TC = 0;
LPC_TIM0->PC = 0;
LPC_TIM0->PR = 0;
LPC_TIM0->TCR |= (1<<1); // Hold counter reset
LPC_TIM0->TCR &= ~(1<<1); // Release counter reset
LPC_TIM0->PR = 124; // 200kHz @ Peripheral clock of 25MHz
LPC_TIM0->IR = 0xFFFFFFFF; // Reset all interrupts
// }
//
// TIM_CaptureConfig(...) {
LPC_TIM0->CCR &= ~((uint32_t)(7<<(0*3))); // Clear CCR
LPC_TIM0->CCR |= ((1<<(0*3))); // Enable capture on rising edge
LPC_TIM0->CCR |= ((1<<((n*3)+2))); // Enable interrupt on CR0 load
// } 
//
// TIM_ResetCounter(...) {
LPC_TIM0->TCR |= ((uint32_t)(1<<1)); // Hold counter reset
LPC_TIM0->TCR &= ~((uint32_t)(1<<1)); // Release counter reset
// }
//
// TIM_Cmd(...) {
LPC_TIM0->TCR |= ((uint32_t)(1<<0)); // Enable counter
// }


I'm thinking the CCR register sets in TIM_Init are supposed to be CTCR sets but as the defaults are correct for timer mode anyway, this shouldn't be causing a problem.
0 Kudos

1,643 Views
ramanamadishett
Contributor II

Have you figure out the issue?

I have trans coded the library, to check the rising and falling edge on the Capture input pin. As in ISR am checking the time captured for both rising and falling edge,

But in my code, am not able to enter in ISR.

Please see the link. Let me know if any suggestions

https://embdev.net/attachment/highlight/339451

0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by NineBall on Wed Feb 29 13:12:43 MST 2012
I actually spent a few months in the LPC17xx manual before I worked on any code while I designed the hardware schematic. I then took a hard look at CMSIS before starting with it and directly accessing registers through it in my code. I eventually found out about NXP's driver library and felt the most comfortable with it coming from an OO development background. I still look at each function call to make sure I like it before using it and then I step through each call manually in code to make sure I understand what is happening. I currently use it for SSP (SPI mode), PWM and match timer functionality with no problems. I'm more concerned about my own lack of knowledge than I am about the library.

As for the pin selection, this is an area I left to doing manually as I saw no benefit to the driver library there. I keep a spreadsheet of every PINSEL register and the various functions I am using for each pin then toggle the bits in calculator (programmer mode) and copy the hex value over for my initialization routine only (when every pin is reset to 00 - known). After that, I toggle the PINSEL as you describe:

LPC_PINCON->PINSELx &= ~(3<<n);
LPC_PINCON->PINSELx |= (f<<n);


Or-ing as needed when toggling multiple pins' functionality.

Having said that, does it look like I have missed anything or am doing anything wrong with the timer capture function other than my preference for the driver library?
0 Kudos

1,643 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gbm on Wed Feb 29 13:05:42 MST 2012
This is my way of doing chip initialization:

struct init_entry_ {
    volatile uint32_t *loc;
    uint32_t value;
};

void writeregs(const struct init_entry_ *p)
{
    for (; p->loc; p ++)
        *p->loc = p->value;
}

static const struct init_entry_ init0_table[] = {
        {&LPC_SC->PCONP, 0xA060965e},    // USB, DMA, SSP0, SSP1, TIMER2...
        {&LPC_SC->PCLKSEL1, 0x800},    // SSP0: /2
        {&LPC_PINCON->PINMODE1,    0x002a8000},    // adc inputs, DAC output
        {&LPC_PINCON->PINSEL1,    0x14254028},    // DAC, ad2, ad1, ad0, USB, MOSI0, MISO0
        {&LPC_PINCON->PINMODE2,    0x00030000},    // pulldown PSEN
        {&LPC_PINCON->PINMODE4,    0x03000000},    // extpwr pulldn
        // Port init
                                //10987654321098765432109876543210
        {&LPC_GPIO0->FIOPIN,    0b00010000000000010000000101000010},    // oe, mtr control, SD ss, hlat, Flash_ss
        {&LPC_GPIO0->FIODIR,    0b00010100011110010000010101000010},    // bits 28- BLU, 16 - HLAT, OE, RTSOUT
        {&LPC_PWM1->PR,        25000000ul / PWM_CLK - 1},

    // many more entries follow - actually the table has about 100 entries in a typical app
    {0, 0}    // end of table marker
};

int main (void)
{
    writeregs(init0_table);    // most of initialization
    // do the real stuff...

}

0 Kudos