Total Noob needs a small push - interrupt pulse length counter displayed on Uart.

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

Total Noob needs a small push - interrupt pulse length counter displayed on Uart.

477 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Wenzu on Sun Dec 19 06:11:55 MST 2010
Hi, Season's greetings to all.

I'm coming from PIC 18F and 24F background, also Arduino.
I am used to code in Basic, using varius IDE's. Familiar and also comfortable with C.

I have just purchased an LPCExpresso 1343 board because I am forseeing that my next projects need all horsepower that this part can provide. I have tried the provided examples in Develop. All work fine.

However, it is my impression that the way to work with what happens during interrupt vectors is not shown in these examples.

What I'm trying to do as a first step is to measure a PWM coming from a signal generator's square wave output ( limited to 3.3Volts output ) into Port2.1, and at first, switching the LED ( Port0.7) in sync with this.
Then I've added the Uart to let me know my connections are OK. Whatever I type is echoed back. This works fine.
Then I tried adding a Timer to count the High pulse, and also derive the period of the incoming PWM, and this is where I failed miserably. ( I have removed the offending and non working code.. out of shyness

[SIZE=2][COLOR=#7f0055]

[B][SIZE=2][COLOR=#7f0055]#include
[/COLOR][/SIZE][/B][/COLOR][/SIZE][LEFT][SIZE=2][COLOR=#2a00ff][SIZE=2][COLOR=#2a00ff]"LPC13xx.h"[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#3f7f5f][SIZE=2][COLOR=#3f7f5f]/* LPC13xx Peripheral Registers */[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#3f7f5f]
[LEFT][/COLOR][/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]#include[/LEFT]
[/LEFT]
[/COLOR][/SIZE][/COLOR][/SIZE][/B][LEFT][SIZE=2][COLOR=#2a00ff][SIZE=2][COLOR=#2a00ff]"gpio.h"[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#2a00ff]
[LEFT][/COLOR][/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]#include[/LEFT]
[/LEFT]
[/COLOR][/SIZE][/COLOR][/SIZE][/B][LEFT][SIZE=2][COLOR=#2a00ff][SIZE=2][COLOR=#2a00ff]"uart.h"[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#2a00ff]
[LEFT][/COLOR][/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]#include[/LEFT]
[/LEFT]
[/COLOR][/SIZE][/COLOR][/SIZE][/B][LEFT][SIZE=2][COLOR=#2a00ff][SIZE=2][COLOR=#2a00ff]"config.h"[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#2a00ff]
[/COLOR][/SIZE]
[LEFT][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]extern[/LEFT]
[/LEFT]
[/COLOR][/SIZE][/COLOR][/SIZE][/B][LEFT][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]volatile[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2][COLOR=#005032][SIZE=2][COLOR=#005032]uint32_t[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] UARTCount;[/SIZE]
[LEFT][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]extern[/LEFT]
[/LEFT]
[/COLOR][/SIZE][/COLOR][/SIZE][/B][LEFT][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]volatile[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2][COLOR=#005032][SIZE=2][COLOR=#005032]uint8_t[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] UARTBuffer[BUFSIZE];[/SIZE]
 
[LEFT][SIZE=2][COLOR=#3f7f5f][SIZE=2][COLOR=#3f7f5f]/*****************************************************************************[/COLOR][/SIZE]
[SIZE=2][COLOR=#3f7f5f]** Main Function main()[/COLOR][/SIZE]
[SIZE=2][COLOR=#3f7f5f]******************************************************************************/[/COLOR][/SIZE]
[/COLOR][/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]int[/LEFT]
[/LEFT]
[/COLOR][/SIZE][/COLOR][/SIZE][/B][LEFT][SIZE=2][B]main[/B] ([/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]void[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2])[/SIZE]
[LEFT][SIZE=2]{[/SIZE][/LEFT]
 
[LEFT][SIZE=2]UARTInit(115200);[/SIZE]
[SIZE=2]GPIOInit();[/SIZE]
[SIZE=2]GPIOSetDir( PORT2, 1, 0 );[/SIZE]
[SIZE=2]GPIOSetInterrupt( PORT2, 1, 0, 1, 1 );[/SIZE][/LEFT]
 
[LEFT][SIZE=2]GPIOIntEnable( PORT2, 1 );[/SIZE][/LEFT]
 
[LEFT][SIZE=2]GPIOSetDir( LED_PORT, LED_BIT, 1 );[/SIZE]
[SIZE=2]GPIOSetValue( LED_PORT, LED_BIT, LED_OFF );[/SIZE][/LEFT]
 
[LEFT][SIZE=2][U]UARTSend([/U][/SIZE][U][SIZE=2][COLOR=#2a00ff][SIZE=2][COLOR=#2a00ff]"Pulse Length Counter"[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2], 20);[/SIZE][/U][/LEFT]
 
[LEFT][SIZE=2] [/SIZE]
[B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]while[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2] (1)[/SIZE]
[SIZE=2]{[/SIZE]
[B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]if[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2] ( UARTCount != 0 ) [/SIZE][SIZE=2][COLOR=#3f7f5f][SIZE=2][COLOR=#3f7f5f]// whatever I type in Hyper terminal is echoed back.[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#3f7f5f]
[/COLOR][/SIZE][SIZE=2]{[/SIZE]
[SIZE=2]LPC_UART->[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]IER[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = IER_THRE | IER_RLS; [/SIZE][SIZE=2][COLOR=#3f7f5f][SIZE=2][COLOR=#3f7f5f]/* Disable RBR */[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#3f7f5f]
[/COLOR][/SIZE][SIZE=2]UARTSend( ([/LEFT]
[/LEFT]
[/SIZE][LEFT][SIZE=2][COLOR=#005032][SIZE=2][COLOR=#005032]uint8_t[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] *)UARTBuffer, UARTCount );[/SIZE]
[LEFT][SIZE=2]UARTCount = 0;[/SIZE]
[SIZE=2]LPC_UART->[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]IER[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = IER_THRE | IER_RLS | IER_RBR; [/SIZE][SIZE=2][COLOR=#3f7f5f][SIZE=2][COLOR=#3f7f5f]/* Re-enable RBR */[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#3f7f5f]
[/COLOR][/SIZE][SIZE=2]}[/SIZE]
[SIZE=2]}[/SIZE]
[SIZE=2]}[/SIZE][/LEFT]
 
[LEFT][SIZE=2][COLOR=#3f7f5f][SIZE=2][COLOR=#3f7f5f]/*********************************************************************************[/COLOR][/SIZE]
[SIZE=2][COLOR=#3f7f5f]** End Of File[/COLOR][/SIZE]
[SIZE=2][COLOR=#3f7f5f]*********************************************************************************/[/COLOR][/SIZE][/LEFT]
[/COLOR][/SIZE]


What I would like, is for some pointers to the right direction, in what I would like to achieve as a first step as mentioned above.

Thanks !!
[/LEFT]
0 Kudos
11 Replies

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Wenzu on Wed Dec 22 15:28:33 MST 2010
Eeek....OK... Zero ,thanks for the heads up on the different name on PIO1_0

:)

Many Thanks !!
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Wed Dec 22 15:20:42 MST 2010
Reset Value in IOCON_JTAG_TMS_PIO1_0 register is TMS (JTAG). If you don't use JTAG (LPCXpresso uses SWD) you can set it's function to CT32B1_CAP0.

//set CT32B1_CAP0
LPC_IOCON->JTAG_TMS_PIO1_0 &= 0x00;
LPC_IOCON->JTAG_TMS_PIO1_0 |= ((0x01<<3)| 0x03);//CT32B1_CAP0, pull-down
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Wenzu on Wed Dec 22 15:00:34 MST 2010
Thanks for your support till now.

My aim, as part one of my learning curve, is to be able to read all capture timers on the LPC1343.

Zero, the external UART display from a TTL-USB works fast with your <no semihosting> code, using many instances of printf.
(Turbo Thanks for it !! .. still need to understand what magic it does !!)
( Need to read the CodeRed printf Wiki a couple of times ...)

CT16B0, CT16B1, CT32B0..... work fine now and give me reasonable results.
Still need to learn how to tune the prescalers. They're at 70 now, and result in mS is the closest I could get it.

But when I come to write the code for CT32B1 capture timer, Code Red <develop> throws me an error due to Port P1_0 not available, most probably because of JTAG ???

What can I do to be able to access it ??

Thanks for all your help !!
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Mon Dec 20 02:12:20 MST 2010
A printf() will always be semihosted, unless you retarget it.

Zero's post gives you the basis of how to retarget, but I we also have an FAQ on this...

http://support.code-red-tech.com/CodeRedWiki/UartPrintf

Note that if you are using LPCXpresso for Linux, Zero's code will not work. See the following FAQ for more information...

http://support.code-red-tech.com/CodeRedWiki/redlib_v2_notes

Regards,
CodeRedSupport
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Mon Dec 20 01:51:13 MST 2010
To use printf with your working UART (no semihosting) you just need to add
#include <stdio.h>
 
// Function __write() ->printf
int __write (int iFileHandle, uint8_t *pcBuffer, uint8_t iLength)
{
 UARTSend(pcBuffer,iLength);
 return iLength;
}


If you set CR_INTEGER_PRINTF your code will just increase a few kilobytes.
See LPCXpressoGettingStarted.pdf in your LPCXpresso folder.

To avoid problems in your ISR it's always a good idea to set a flag in the ISR and do everything else within your while loop:

volatile unsigned char flag_low=0;
volatile unsigned char flag_high=0;
 
ISR...
{
 ...
 timer_down = LPC_TMR16B1->CR0;
 flag_low=1;
...
 timer_up = LPC_TMR16B1->CR0;
 flag_high=1;
...
}
 
while(1)
{
 ...
 if (flag_low & flag_high)
 {
  flag_low =0;
  flag_high =0;
  ...calculate and 
  printf()
 } 
 ...
}


Next step: Use a timer to printf every second -> see SysTick Timer in User Manual / Examples.
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Wenzu on Mon Dec 20 01:39:24 MST 2010
Hi Thanks for your reply.
However I am not using semihosting.... I am using a USB-Uart(TTL) adapter on the TXD/RXD pins on LPCExpresso.
Does your post above still count ??

Can you kindly point me to the right direction to be able to output my variable "timer_count" over uart as in my attempt at printf below ??

I have enabled "stdio.h" but to no avail.

Thanks for your support.
I feel this is going to be a nice ride :)
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Mon Dec 20 01:05:47 MST 2010
Using printf's with interrupts - and in particular within interrupt handlers is not recommended. This is because the semihosting operation that the printf triggers between the target and the PC running the debugger causes the CPU to be halted whilst the string to be displayed is transferred up to the host (and potentially halted multiple times). This will prevent any "real-time" behaviour of the rest of you code.

More information at:

http://support.code-red-tech.com/CodeRedWiki/UsingPrintf

Regards,
CodeRedSupport
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Wenzu on Sun Dec 19 19:25:10 MST 2010
Hi Zero,

Thanks for the tip on init. It now works.. sort of...

#include "LPC13xx.h"            /* LPC13xx Peripheral Registers */
#include "gpio.h"
#include "uart.h"
#include "config.h"
#include "stdio.h"

#define  EN_CT16B1 (1<<8)
volatile unsigned int timer_up;     //timer high
volatile unsigned int timer_down;   //timer low
volatile unsigned int timer_count;  //timer difference

extern volatile uint32_t UARTCount;
extern volatile uint8_t UARTBuffer[BUFSIZE];

   void timer_config(void)
         {
       LPC_SYSCON->SYSAHBCLKCTRL |= (EN_CT16B1);    //enable clock CT16B1
       //init i/o CT16B1_CAP0
       LPC_IOCON->PIO1_8 = (1<<0) | (1<<4);         //CT16B1_CAP0 & pullup
       LPC_TMR16B1->CTCR = 0;                       //use timer mode
       LPC_TMR16B1->CCR  = 7;                       //capture rising & falling edge, enable interrupt
       LPC_TMR16B1->TCR  = 1;                       //start timer
       NVIC_EnableIRQ(TIMER_16_1_IRQn);
         }

    void TIMER16_1_IRQHandler(void)
          {
           LPC_TMR16B1->TC = 0;  //reset counter
           if(LPC_GPIO1->DATA & (1<<8) )
           {
            timer_down = LPC_TMR16B1->CR0;
            UARTSend("H",1);
            GPIOSetValue( 0, 7, 1 );            //LED_ON;
           }
           else
           {
            timer_up = LPC_TMR16B1->CR0;
            UARTSend("L",1);
            GPIOSetValue( 0, 7, 0 );             //LED_OFF;

          timer_count = (timer_up - timer_down);

           printf ("Timer16B1 Count : %d\n", timer_count);

           }
           LPC_TMR16B1->IR |= (1<<4); //reset interrupt
          }


int main (void)
{

    UARTInit(115200);
    GPIOInit();
    //GPIOSetDir( PORT2, 1, 0 );
    //GPIOSetInterrupt( PORT2, 1, 0, 1, 1 );    // original 'extint' example - input pin
    //GPIOIntEnable( PORT2, 1 );

    //GPIOSetDir( PORT1, 8, 0 );                // Not needed to Setup Port1_8 as input.. done in TimerConfig.
    //GPIOSetInterrupt( PORT1, 8, 0, 1, 1 );
    //GPIOIntEnable( PORT1, 8 );

    GPIOSetDir( 0, 7, 1 );                 // set LPCExpresso LED as echo of input pulse stream
    GPIOSetValue( 0, 7, 0 );

    timer_config();


    UARTSend("Pulse Length Counter", 20);

  while (1)
    {

      if ( UARTCount != 0 ) // 'whatever I type in Hyper terminal is echoed back.'
      {
        LPC_UART->IER = IER_THRE | IER_RLS;            /* Disable RBR */
        UARTSend( (uint8_t *)UARTBuffer, UARTCount );
        UARTCount = 0;
        LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR;    /* Re-enable RBR */
      }


    }
}

I get an L or H on each transition of the input stream. The echo from Uart is still OK.

I am now having trouble with the Printf statement ( within the Timer16 ISR ) , when trying to output the difference between timer counts.
To be very honest, I've been researching how printf works, and what the %d.. etc mean. ( never used it before )

Last push, and I'll be fending for myself for a while.



Thanks so much for getting me up to grips with my first steps !!
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Sun Dec 19 16:49:37 MST 2010
1.Remove

Quote:
GPIOSetDir( PORT1, 8, 0 ); // setting P1_8 as input
GPIOSetInterrupt( PORT1, 8, 0, 1, 1 );
GPIOIntEnable( PORT1, 8 );



Using Capture Input and also GPIO Interrupt with the same Pin isn't working.

2. Set a breakpoint in the ISR to control if this ISR is served (& triggered).
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Wenzu on Sun Dec 19 16:19:47 MST 2010
Hi Zero,

Thankyou for posting a sample code.
I notice that you chose to use the InputCapture hardware module present on Port1_8. There are 2 inputs that can be used with Timer 16, and 2 with Timer 32, as I'm getting more familiar with the 1343UserManual.

I have tried to work around the code you posted, but could not get a GP output to echo the input pulse stream from my signal generator. I have a scope and am monitoring both input (p1,8) and output(p0,7 (LED)) .

here's the code I'm trying:

#include "LPC13xx.h"            /* LPC13xx Peripheral Registers */
#include "gpio.h"
#include "uart.h"
#include "config.h"

#define  EN_CT16B1 (1<<8)
volatile unsigned int timer_up;   //timer high
volatile unsigned int timer_down;  //timer low

extern volatile uint32_t UARTCount;
extern volatile uint8_t UARTBuffer[BUFSIZE];

    void TIMER16_1_IRQHandler(void)
          {
           LPC_TMR16B1->TC = 0;  //reset counter
           if(LPC_GPIO1->DATA & (1<<8) )
           {
            timer_down = LPC_TMR16B1->CR0;
            UARTSend("High",4);
            GPIOSetValue( 0, 7, 1 );
            //LED_ON;
           }
           else
           {
            timer_up = LPC_TMR16B1->CR0;
            UARTSend("Low",3);
            GPIOSetValue( 0, 7, 0 );
            //LED_OFF;
           }
           LPC_TMR16B1->IR |= (1<<4); //reset interrupt
          }


int main (void)
{

    UARTInit(115200);
    GPIOInit();

    GPIOSetDir( PORT1, 8, 0 );        // setting P1_8 as input
    GPIOSetInterrupt( PORT1, 8, 0, 1, 1 );
    GPIOIntEnable( PORT1, 8 );

    GPIOSetDir( 0, 7, 1 );   // Setting the LED port as output ( to echo input )
    GPIOSetValue( 0, 7, 0 );



    //void timer_config(void)
    //{
     LPC_SYSCON->SYSAHBCLKCTRL |= (EN_CT16B1);    //enable clock CT16B1
     //init i/o CT16B1_CAP0
     LPC_IOCON->PIO1_8 = (1<<0) | (1<<4);         //CT16B1_CAP0 & pullup
     LPC_TMR16B1->CTCR = 0;                       //use timer mode
     LPC_TMR16B1->CCR  = 7;                       //capture rising & falling edge, enable interrupt
     LPC_TMR16B1->TCR  = 1;                       //start timer
     NVIC_EnableIRQ(TIMER_16_1_IRQn);
    //}

    //timer_config();
    UARTSend("Pulse Length Counter", 20);

  while (1)
    {

      if ( UARTCount != 0 ) // 'whatever I type in Hyper terminal is echoed back.'
      {
        LPC_UART->IER = IER_THRE | IER_RLS;            /* Disable RBR */
        UARTSend( (uint8_t *)UARTBuffer, UARTCount );
        UARTCount = 0;
        LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR;    /* Re-enable RBR */
      }
    }
}




In my original tests.. I was trying to use GPIO interrupts, so as not to use the Capture function and leave that for high speed capturing.

I think I still need some more spoon feeding, if anyone can provide some enlightenment.
I am feeling exactly like when you travel to a new ( small, unknown and remote) airport for the first time, and do not know where to go for your luggage = ( completely lost ) ... ( unless you follow the passengers that were also on the same plane  ).

Thanks for your input.
0 Kudos

462 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Sun Dec 19 07:27:34 MST 2010
Step1: Config Timer as Capture input, enable IRQ
Step2: Read times in ISR
Step3: Ready

Sample:
#define  EN_CT16B1 (1<<8)
volatile unsigned int timer_up;   //timer high
volatile unsigned int timer_down;  //timer low
 
void TIMER16_1_IRQHandler(void)
{
 LPC_TMR16B1->TC = 0;  //reset counter
 if(LPC_GPIO1->DATA & (1<<8) )
 {
  timer_down = LPC_TMR16B1->CR0;
//  LED_ON;
 }
 else
 {
  timer_up = LPC_TMR16B1->CR0;
//  LED_OFF;
 }
 LPC_TMR16B1->IR |= (1<<4); //reset interrupt
}
 
void timer_config(void)
{
 LPC_SYSCON->SYSAHBCLKCTRL |= (EN_CT16B1);//enable clock CT16B1
 //init io CT16B1_CAP0
 LPC_IOCON->PIO1_8 = (1<<0) | (1<<4); //CT16B1_CAP0 & pullup
 LPC_TMR16B1->CTCR = 0;      //use timer mode
 LPC_TMR16B1->CCR  = 7;       //capture rising & falling edge, enable interrupt 
 LPC_TMR16B1->TCR  = 1;       //start timer
 NVIC_EnableIRQ(TIMER_16_1_IRQn);
}
0 Kudos