Systick Inaccuracy

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

Systick Inaccuracy

424 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by nelmak on Fri Apr 13 07:51:32 MST 2012
Hello,

I am having problems with getting accurate readings using the Systick timer. I am trying to measure the time intervals between pulses. These pulses have the same geometry from a function generator.

My Systick is ticking at every 1ms.

Below is the simple code i am using,

        adcval = ADCRead(0);

        if ((oldadcval > 200) && (adcval < 200))
        {
            printf("%d ms\n", msTicks);
            msTicks = 0;
        }

        oldadcval = adcval;

When I run a 2.5Hz pulse into AD0, it gives me a reading of 310ms or approximately 3.2Hz. Which is wrong. How would i be able to get an accurate reading? Would using a timer increase the accuracy?

Thanks
0 Kudos
8 Replies

397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by nelmak on Fri Apr 13 10:08:43 MST 2012
Thanks Rob65 for your clear and concise explanation.

It makes much more sense to me now. I have some experience in embedded programming but it was with TI's piccolo and I was guided in one of my classes.(Still an undergraduate student)

I was just trying to figure out the syntax because it is a little unusual compared to the Piccolo. I am already knee deep in the user manual and just trying to find my way around the LPCXpresso. I will take your advice to heart.
0 Kudos

397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Fri Apr 13 09:33:31 MST 2012

Quote: nelmak
LPC_IOCON->PIO_2 = (1<<1) | (2<<3);
is
LPC_IOCON->PIO_2 = 010 | 10000?



BTW: That's of course wrong. That's decimal and not binary.

Everything except decimal has to be marked :eek:
LPC_IOCON->PIO_2 = 0b10 | 0b10000 //set bit 1 and 4 
0 Kudos

397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Fri Apr 13 09:09:35 MST 2012
The syntax is actually just (plain) C.

Quote: nelmak

I am guessing that
LPC_IOCON->PIO_2 = (1<<1) | (2<<3);
is
LPC_IOCON->PIO_2 = 010 | 10000?


Good guess - but if you know you languages this is not that hard a guess ;)
And then of course 010 | 10000 results in 10010

If you look in the lpc11xx.h you will see that there is a #define that defines LPC_IOCON as a pointer to a structure and PIO_2 is just a member of that structure. So LPC_IOCON->PIO_2 = value is just writing the value to the member in the structure (a register on the lpc1114). If you look in the lpc1114 user manual you'll notice there is a block called IOCON and inside that block there is a register named PIO_2 (the actual name used in the user manual might be a bit different, I don't have the manuals or actual code at hand right now).

Also note how LPC_IOCON is defined as being "volatile"  which means that the compiler may never optimize any assignments or reads away.

See how the user manual states that sometimes sets of multiple bits are being used to specify a certain function. The PIO pins can be routed to different signals in the lpc1114, one pin could be either a ADC input, a GPIO pin, an I2C clock or .... Each pin has 4 different dedicated functions that it can be attached to. So there it makes sense to specify something like 2<<1 if bits 2 and 1 of a register specify the function.

This is fairly common to a lot of microcontrollers (with each micro having it's own registers and pin types of course).
You want to have a copy of the user manual at hand - but not a paper copy, just a PDF file on your PC. Now take some of the simple examples and try to figure out what the register assignments do and if this makes sense to you.

I know some programmers who are excellent in programming large style database applications. They now all the ins and outs of network protocols, use function pointers like it's part of there native language and they write SQL statements that don't say anything to me.
Still, if I show them a program that blinks an LED on my LPCXpresso module they don't understand a single word of it :D - hardware engineers with hardly any programming experience have an advantage here!
So don't get confused or frustrated. Even experienced programmers may benefit form the simple examples like blinky. Just start out with some of the examples and start experimenting.

And please note: using the capture input of a timer is an advanced function of the timer. You might want to start with a simple example that just uses the timer as a free running or a periodic timer. Be prepared to read the chapter about the timers in the user manual and re-read the parts about functions being used when trying to understand what the examples do.

And start to experiment with the debugger (placing breakpoints, watches and single stepping) through the simpler examples. I have 30+ years of hands-on in hardware design and embedded systems programming but I still like to start with those simple examples before diving into the more complex applications.

But to get to your original topic: the systick is as accurate as your main clock; the clock is derived from the CPU clock frequency and this is mostly the 12 MHz crystal on the LPCXpresso module. But the CPU clock may also be derived from an internal RC oscillator and that one is not as accurate as the crystal.
If you use the examples, they use the CMSIS library. CMSIS contains an system_lpc11xx.c file (if I remember the name correctly) where the CPU clock is selected.

But before diving into this ...
You might be using a different LPCXpresso module - if you have any specific questions about what happens, please include details like the LPCXpresso tools version used, the type of microcontroller and which program you used.
I suggest to start with the examples in the c:\nxp\lpcxpresso\examples folder (use the examples provided with the tools, not the ones that are on the NXP website) and the latest version of the LPCXpresso IDE.

You might be a good 'victim'  for testing out a "Programming microcontrollers for Dummies (using LPCXpresso)" :rolleyes:

Regards,[INDENT]Rob
[/INDENT]
0 Kudos

397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by nelmak on Fri Apr 13 08:59:37 MST 2012
1 shifted left by 1
1 = 10

2 shifted left by 3
10 = 10000

correct me if im wrong?

I was wondering if that statement sets bits [1] and bits [4] with the least significant bit starting at 0.
0 Kudos

397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Fri Apr 13 08:41:00 MST 2012

Quote: nelmak
There is no guide on the syntax for setting bits on the pins.

I am guessing that
LPC_IOCON->PIO_2 = (1<<1) | (2<<3);
is
LPC_IOCON->PIO_2 = 010 | 10000?



You need a guide for shifting bits?
0 Kudos

397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by nelmak on Fri Apr 13 08:18:50 MST 2012

Quote: Zero
Is there a special reason why you don't use capture function as described several times in this forum like #4 of  http://knowledgebase.nxp.com/showthread.php?t=2815 :confused:



In your example in #4, it starts the timer on the rising edge of the signal into PIO_2?

I am unsure about how you are initializing? There is no guide on the syntax for setting bits on the pins.

I am guessing that
LPC_IOCON->PIO_2 = (1<<1) | (2<<3);
is
LPC_IOCON->PIO_2 = 010 | 10000?
0 Kudos

397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by nelmak on Fri Apr 13 08:08:42 MST 2012
Sorry, I am new to microcontroller programming and was going off the example projects. I will take a look at it.

Thanks
0 Kudos

397 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Fri Apr 13 08:01:03 MST 2012

Quote: nelmak
I am trying to measure the time intervals between pulses.



Is there a special reason why you don't use capture function as described several times in this forum like #4 of  http://knowledgebase.nxp.com/showthread.php?t=2815 :confused:
0 Kudos