Repetitive Interrupt Timer Library

11 Mar 2011

Hi,

FYI, I've just published a library wrapping the LPC's RIT (Repetitive Timer Interrupt).

See

Import programRIT_Demo

RIT (Repetitive Interrupt Timer) Demo.

Any comments are welcome!

11 Mar 2011

Hi Wim,

Nice to see you getting into the spirit of sharing your libraries! :) If you want, I have a RIT library (currently unpublished) however, mines different from your. Your's does a single callback whereas mine is just the same as Mbed's Ticker library (allowing as many as you want each with it's own time value). I didn't publish it because, well, 99.9% of the time you'd use a Ticker anyway. My "Ricker" (odd name, it's a Ticker but using the RIT) only really has one obscure use case and that's if you need to alter interrupt priorities. All Mbed Tickers use Timer3 so their callbacks all run under a single irq, Timer3. So if you want a "Ticker" but with a different IRQ priority you have to use another timer (or the RIT). So I used the RIT. Obscure use case (and potentially dangerous as it's easy to write some bizarre race condition bugs!) but I've used it a couple of times.

Let me know if you want the code to look through or use.

11 Mar 2011

can the RIT do intervals less than 1us?

11 Mar 2011

Hi Igor,

My RIT library is actually limited to 1ms resalution, no where near sub-microsecond, but that's deliberate as I just don't have cases where I need timers like that (and if I did I would use an Mbed Ticker).

As for "sub-us", here's how I setup the RICOMPVAL to give me a 1ms IRQ:-

    switch ((LPC_SC->PCLKSEL1 >> 26) & 0x3) {
        case 0: LPC_RIT->RICOMPVAL = (SystemCoreClock / 4 / 1000); break; /* CCLK / 4 */
        case 1: LPC_RIT->RICOMPVAL = (SystemCoreClock / 1 / 1000); break; /* CCLK / 1 */
        case 2: LPC_RIT->RICOMPVAL = (SystemCoreClock / 2 / 1000); break; /* CCLK / 2 */
        case 3: LPC_RIT->RICOMPVAL = (SystemCoreClock / 8 / 1000); break; /* CCLK / 8 */
    }

The main issue is how much can you really get done in such a short period of time available between "ticks"?

Do you have a use case or example of what you are trying to do or measure?

11 Mar 2011

For those who are interested you can find the Ricker library below. Note, it's not "public" so you can only find it from the link below.

Import libraryRicker

A Ricker is a simple Ticker but using the RIT rather than Timer3

11 Mar 2011

Actually, my problem has more to do with wait_us(). At some point I was tying to interface an N64 controller to the mbed. The communication protocol uses a one-wire interface where each bit is 4us long. A '1' is 1us low and 3us high.

The problem I had with wait_us() is that even with a 1us resolution, it was not stable enough when it came to wait times less than 3 or 4 us. I resorted to using a NOP for loop for the delays in order to make it work. I just didn't see that as the most elegant solution. See more about the protocol here.

11 Mar 2011

Hi Andy,

Andy K wrote:

Let me know if you want the code to look through or use.

I assume the code you mentioned is in the link some posting further? I sure like to take a look at it (see if I forgot anything)!

The reason I did not implement a List of attached function isr's is quite simple, my C++ is to rusty (and thus do i need sample code to look at ;-)

11 Mar 2011

Hi Wim

It's the "Ricker" library above :)

11 Mar 2011

Andy K wrote:

Hi Wim

It's the "Ricker" library above :)

Quite some useful code I like! The list of function isr's is one think I'm pleased to see a good sample of.

11 Mar 2011

Igor,

I haven't seen the wait_api code but reading between the lines on some of Simon's posts I gather that for such short time delays the overhead of the library will probably become a factor, hence the problem you are seeing. Have to say I haven't used one-wire with an Mbed (yet) but in the past with AVRs and older 8051 type systems I have resorted to for() waits just like you did.

But, considering the Timer3 clock is running at 1MHz you could try this:-

    uint32_t mydelay = LPC_TIM3->TC + 4;
    while (LPC_TIM3->TC < mydelay);

However, in order to use that above you must at least once somewhere used a wait(x) or a Ticker etc to force the Mbed library to init TIM3. Once at least one wait() has been used (perhaps at program startup before you hit the while(1) loop) then TIM3 TC register starts clocking.

[Edit: Btw, you may have also suffered if you used a DigitalOut with such tight timing requirements. I have this library of macros that are alot faster than DigitalOut.]

11 Mar 2011

Wim, glad you like it. Since you enjoyed that one try looking at FPointer, there's some fun in that one too :)

11 Mar 2011

I'll give that a try. I was thinking of rewriting the code to use interrupts. From what I remember though, InterruptIn couldn't quite cope with the demands either. Maybe the simplest solution is the best...

I kinda put that project on hold because I haven't had the time to figure out USB HID yet.

11 Mar 2011

Hi Igor,

Igor Martinovski wrote:

I'll give that a try. I was thinking of rewriting the code to use interrupts. From what I remember though, InterruptIn couldn't quite cope with the demands either. Maybe the simplest solution is the best...

I kinda put that project on hold because I haven't had the time to figure out USB HID yet.

The RIT Timer should be able to run all the way up to the CCLK at 96Mhz but I doubt the interrupt system can cope with that. As the RIT runs strait of the 96Mhz clock I just multiply the us and ms by 96 and 96000.

Btw what do you want with HID? I have done a device with it some 8-10 years ago so I might have some knowledge left to share ;-)

11 Mar 2011

The plan was for the mbed to read 4 n64 controllers and to interface them to the computer using usb hid. There is a usb mouse example for the mbed, but I am not familiar with usb and the code is not documented. I have to sit down with the hid manual and hammer it out someday.

12 Mar 2011

I wonder if you can do timed DMA reads from GPIO registers.

12 Mar 2011

Hi Igor

Hid is a lot of defining tables and responding to enumeration commands before you get to your own code.

I developed an application with a Cypress chip and we had to buy a transparent driver (it exposed kernel level to user level so what we put in also arrived exactly the same at the device) to get it starting and be able to debug the hid stuff.

Problem with hid is that a lot has to work before it gets flagged as enumerated. The manual is thck but if you know where to look it's not that hard.

12 Mar 2011

@IgorSk, not sure what you mean. But if you are thinking that have the DMA send a regular read of a GPIO register to a memory buffer then the problem is that the GPDMA will take sink to it's FIFO as soon as the src allows and push it out as soon as the dst will take it. So if you setup a configuration to say read in say a 32burst a burst is what you get, you can set a time for each DMA transfer.

You could setup a config and prime it and then enable it on a RIT interrupt but that would just get you a "burst" of size defined in the config. If that's 1 then just as well to read the register and store it without the GPDMA. But if you want a "snapshot" into a buffer then you can use the GPDMA. However, the time between "samples" of the port register is, well, "as fast as it can do it" which is a bit vauge. Suppose it can be calculated and tested.

I did think of something similar in one of those MP3 player things. It would have been great if I could set the GPDMA to send a buffer to the DAC but of course I wanted to send it at the 44.1kHz rate. That wasn't possible, the GPDMA would just have "banged" the DAC. Would have been a good way to play out the buffer.

13 Mar 2011

Just a follow-up. I just tried Andy's code snippet as a delay. It seems to produce the same results as the wait_us(). I guess the wait functions implemented more or less the same (if there was any doubt.)

13 Mar 2011

@Igor Skochinsky

Igor Skochinsky wrote:

I wonder if you can do timed DMA reads from GPIO registers.

When I originally started MODDMA it was just a port of the NXP GPDMA Driver Library to a C++ "Mbed style" library component. However, it's gained a few minor features and bug fixes (that are still in the driver lib despite feeding them back) over time. However, Win's constant nagging about the Sync and BSel registers (sorry Wim, your not really nagging!) coupled with my poor response of "the manual is a bit vague" got me thinking. I don't like only vague ideas.

So this afternoon I set to on adding some lucidity to my understanding of some of the regsiters the NXP Driver Library doesn't support configurations for.

Low and behold, this is the result. Enjoy. I can see this new feature making MODDMA a popular library from it's previously obscure position :)

Note, only Timers 0 through 3 (although using 3 is a bad idea as we all know, Mbed libs use it) are supported for GPIO transfers. But that should be fine.

@Wim, I can now see how to remove the "latency" my other example of burst grabbing multiple ADC channels to a memory buffer. I'll probably add new transfer modes to MODDMA to support the same style of functionalty as timed sequence transfers of GPIO that the new functionaly has. Watch this space.

14 Mar 2011

Nice!

14 Mar 2011

Hi Andy

Keep on eliminating these vague ideas with excellent code!

14 Mar 2011
14 Mar 2011

Andy K wrote:

Double buffered DAC output.

That makes sound playback a lot easier!

Btw (and off-topic), found nice hardware for audio playback and I expect to do a project on it it. See http://www.sparkfun.com/products/9534