highest recommended periodic interrupt frequency

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

highest recommended periodic interrupt frequency

768 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by jonotree on Fri Oct 10 07:10:00 MST 2014
Hi there,

I'm trying to write a bit-bashing based spi routine (the spi peripheral on my lpc is taken already), and am planning to use a periodic timer-based interrupt to toggle a variable which will represent my spi clock signal.

I'm aware of the issue of having an interrupt frequency which is too high, such that the processor is always in an interrupt so it has virtually no time to run the actual program.

Are there any guidelines or good rules of thumb when defining a sensible limit for interrupt frequency in relation to actual system clock speed?

My system clock speed is 120 MHz (found by checking 'PeripheralClock' variable in system_LPC177x_8x.c) and I would like an interrupt frequency of 5 MHz.

With my timer presacaled to give this interrupt frequency, the program get stuck due to the issue described above. I know I should basically lower the interrupt frequency a lot, but I'm curious as to whether there is a way to get a ballpark type figure if you know your system clock frequency. Or if there are any helpful metrics you can use to get an idea?

Thanks in advanced
Jonathan  

Labels (1)
0 Kudos
Reply
5 Replies

748 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Thu Oct 30 14:20:49 MST 2014

Quote: jonotree
I know I can just do things in the ISR but am also wanting to keep the isr size to a minumum.



I recommend avoiding loops in ISRs; apart from that, a large ISR is not really a problem; just avoid loops, and avoid calling functions outside the ISR, then in general, your ISR will stay pretty quick. Normally your ISR will only be invoked if it needs to do something, so it's the most efficient way of processing data. Processing data in the main-loop (aka. Task-Time) is really a bad idea and consumes a lot of power.
If you can, try writing your code, so it only uses interrupt service routines to handle the jobs, then your main-loop can be as simple as this:
while(1){ asm volatile("wfi"); }
... or a variant, such as while(1){ __asm("wfi"); } - this may depend on your compiler.

The "wfi" instruction waits for an interrupt. It makes the processor go to sleep and use as little power as possible.
It'll take a few clock cycles for the CPU to wake up, so if a couple of clock cycles can be wasted, try using the above.
It's possible to make an application solely run on timers and DMA and shut down the CPU completely (that is: Without using interrupts).


Quote:
Also, apologies for my ignorance but how do I know that it takes 12 cycles to enter/leave an isr?



Joseph Yiu's document: A Beginner's Guide on Interrupt Latency

Like TheFallGuy, I also recommend Joseph Yiu's books in the [color=#090]Definitive Guide to the Cortex-M*[/color] series


Quote:
And would I be right in thinking that I wouldnt be able to work out a 'worst case' number of clock cycles from a given bit of c code, because just from the c itself, you can't really tell how the compilers putting it together?



Exactly, and if you're using an interrupt, which may also vary in execution time and frequency, then it's pretty difficult.
-But you can still estimate.


Quote:
...and/but therefore to work out how many clock cycles it would take, I could look at the disassembly? (something I haven't really done before but seems like I should try and learn about).



If you need to make sure it stays within a certain number of clock cycles, I highly recommend learning assembly language.
-It is not that difficult. -Many people stay away from assembly language because it sounds too "spooky". Well, it's just another programming language. I like writing code in assembly language, due to that I'm in complete control of what's going on, and I can be pretty sure about the execution speed.
I've even made a piece of code, which I knew exactly at which instruction an interrupt would occur.
(It ran non-stop for more than 6 months; then I just turned it off; the interrupt would occur approximately 31500 times per second, and was precise always - well, it still is).
Though C is a wonderful language for making portable code, you can outrun C easily when using assembly language. And if you're porting between different ARM chips, you can write portable assembly language as well (yes, I'm running Cortex-M0 code on a Cortex-A7).
0 Kudos
Reply

748 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Mon Oct 27 10:35:39 MST 2014

Quote:
Also, apologies for my ignorance but how do I know that it takes 12 cycles to enter/leave an isr? or probably better, could you point me to the document/chapter - ive tried looking in the user manual briefly just now with no luck.



You need to look in the ARM documentation for the core that you are using this sort of information. NXP don't re-publish ARMs core documentation (it runs to thousands of pages!). However, a more manageable way it to get yourself a good book. Joseph Yiu's Definitve Guide books are very good.

0 Kudos
Reply

748 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by jonotree on Mon Oct 27 09:03:03 MST 2014
Thanks for your replies, and sorry for the lack of response (i've been away).

The code suggestion isn't too dissimilar to what I have now, its especially handy to use a circular buffer. I've settled on just lowering the clock frequency a lot because its not too important in this application.
I know I can just do things in the ISR but am also wanting to keep the isr size to a minumum.

Also, apologies for my ignorance but how do I know that it takes 12 cycles to enter/leave an isr? or probably better, could you point me to the document/chapter - ive tried looking in the user manual briefly just now with no luck.

And would I be right in thinking that I wouldnt be able to work out a 'worst case' number of clock cycles from a given bit of c code, because just from the c itself, you can't really tell how the compilers putting it together?

...and/but therefore to work out how many clock cycles it would take, I could look at the disassembly? (something I haven't really done before but seems like I should try and learn about) .
0 Kudos
Reply

748 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Sat Oct 11 11:44:16 MST 2014
Listen to rocketawg; you should really use the chip-select pin and share the SPI with multiple devices if you can.

But if you must implement this as an interrupt, I have a suggestion; it's nothing special, though...

In your interrupt service routine, you can send+receive a complete byte (or any bit-length you wish) while toggling the clock.
When you've done sending your chunk of bytes, leave the ISR.
-You can do this on the SPI master, because the SPI master is the one that controls the clock.

The SPI protocol allows you to have strange timings on your clock signal, as long as you don't exceed the maximum clock rate for your attached device(s) of course.

Use any timer you wish, including the systick.

Some (untested) pseudo-code for a dirt-cheap discount FIFO:

static volatile uint16_t sRhead = 0;
static volatile uint16_t sRtail = 0;
static volatile uint16_t sThead = 0;
static volatile uint16_t sTtail = 0;
static volatile uint8_t sRbuf[256]; /* the received data */
static volatile uint8_t sTbuf[256]; /* the data to transmit */

void isr(void)
{
    int32_t tbits;
    int32_t rbits;
    int32_t b;
    int32_t i;

    /* remember to clear interrupt pending bit. */

    for(i = 0; i < 4; i++)
    {
        tbits = sTbuf[sTtail];
        sTtail = (sTtail + 1) & 255;
        for(b =0; b < 8; b++)
        {
            SPI_CLK_LO;
            rbits = (rbits << 1) | (SPI_CLK_MISO);
            SPI_CLK_MOSI = (tbits >> 7) & 1;
            SPI_CLK_HI;
            tbits = tbits << 1;
        }
        sRbuf[sRhead] = rbits;
        if(rTail != rHead) /* only save data if receive buffer isn't full, otherwise drop the received data */
        {
            sRhead = (sRhead + 1) & 255;
        }
    }
}

void mySendSPI(uint8_t aByte)
{
    while(((sThead - sTtail) & 255) <= 1) /* we must always have 1 empty slot, since the buffer is empty if head == tail */
    {
        asm volatile("wfi"); /* go low-power while waiting */
    }
    sTbuf[sThead] = aByte;
    sThead = (sThead + 1) & 255;
}



-It may contain a bunch of bugs and typos, but it should give you an idea of what I mean.
Thus you should be able to save some CPU time by sending small bursts of data each time the interrupt fires.
0 Kudos
Reply

748 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by rocketdawg on Sat Oct 11 11:02:30 MST 2014

Quote: jonotree
Hi there,
My system clock speed is 120 MHz (found by checking 'PeripheralClock' variable in system_LPC177x_8x.c) and I would like an interrupt frequency of 5 MHz.
Jonathan



you can do this yourself.  We know that there are 12 cycles to enter an ISR, and another 12 to exit.  Then you need to write the isr to determine how many cycles will be needed to perform the work inside the ISR.

Then you need to find the worst case (longest interval of time) of this SPI activity and then do all the math to get a maximum CPU usage used by this code.

Another way to look at it is to figure out how many clock cycles are available in an interval @ 5 MHz.

SPI is designed so that multiple slaves can be controlled by one master.  My question is, why not share?  I am sure you are not using 100% of the SPI bandwidth.
0 Kudos
Reply