Interrupt handling


#1

I have been experimenting with adding support for interrupts to uLisp, and I would be interested in any suggestions.

The idea is that your uLisp program will be able to respond to events such as button presses without having to wait in a loop testing the input.

The proposed format is:

(attach-interrupt interrupt function mode )

This will attach a function to an interrupt; the function is evaluated when the interrupt occurs. Note that the interrupt parameter should be the interrupt number, not the Arduino pin number.

The function should be a function of one argument; it will be called with the number of interrupts that have occurred since the last evaluation of the interrupt handling function; this will normally be 1, but may be more if the interrupt handling function took longer than the rate of interrupts. There may be a latency of a few milliseconds, because of garbage collection, before the interrupt gets handled, but it shouldn’t be possible to miss an interrupt.

The mode argument specifies which edge the interrupt is triggered on, like the Arduino function.


#2

I think this is a very interesting feature. I find it also interesting to add a periodic software-interrupt, something linke the arduino timer libraries.
Another interesting feature would be servo support, because this is not possible without ulisp support (one wire is another one).

Regards,
Kaef


#3

I suppose this feature never got in or am I missing something? I saw it referenced in a beta release on the homepage as well …


#4

Hi David ,

Great !
This would be a great feature.
Also periodic interrupts could be useful , like executing small chunks of lisp code
after defined times.

Regards Ronny


#5

No, I decided against implementing it at the time. I’ll reconsider it if there’s enough interest.


#6

Aha!

I found the topic in the search field of the website, where it was in beta. Because that was a while ago I was wondering why I didn’t find it …
http://www.ulisp.com/show?1MWO

I was going to try out a rotary encoder which made me look for the feature.

Best regards / Peter


#7

In that case - please reconsider please! :)
Constant checking in loop, on AVR with only 32s timer, is no fun at all…


#8

Thanks for the encouragement! There’s now a beta version of the latest version of AVR uLisp with interrupt handling. Download it here:

ulisp-avr-interrupts on GitHub

For information about how to use it see:

Using interrupts

I welcome your comments, and feedback about whether this should become a standard part of uLisp.


#9

Cloned, uploaded, tested (on Uno) - and have to say - oh wow! That changes everything! At least for me :)
I tested all modes and both pins available on Uno, with named and anonymous functions - worked as expected. I used sligtly modified tog version:

(defun tog (n)
  (digitalwrite 13 (not (digitalread 13)))
  (print (cons n (millis))))

(Well ok, sometimes it didn’t react or reacted twice or so, but I’m pretty happy to blame my tired breadboard and unreliable buttons.)

In terms of comments (just small details):

  1. Now attach-interrupt returns nil. Can it return something evaluating to t on success and nil on failure? At least if it’s possible for attach to fail.
  2. It looks like attach-interrupt is using copy of a function. When I redefine function, I then have to attach it again. Was it by design? Would it be possible to have current version of a function used, or looking it up every time is too slow or something?
  3. On Uno it ate few bytes, so WORKSPACE has to be reduced. By 1 cell :) to 314-SDSIZE, to avoid low memory warning during compilation.

Thank you very much!!


#10

Glad it worked for you, and thanks for the comments.

It looks like attach-interrupt is using copy of a function. When I redefine function, I then have to attach it again. Was it by design? Would it be possible to have current version of a function used, or looking it up every time is too slow or something?

Good point. It would do what you want if attach-interrupt took the name of the function, rather than the function itself; for example:

(attach-interrupt 0 'tog)

You could then redefine tog and the interrupt would call the latest version.

Now attach-interrupt returns nil . Can it return something evaluating to t on success and nil on failure? At least if it’s possible for attach to fail.

It could return the symbol you’ve attached on success, eg tog, and nil on failure.

On Uno it ate few bytes, so WORKSPACE has to be reduced. By 1 cell :) to 314-SDSIZE , to avoid low memory warning during compilation.

That low-memory warning is totally arbitrary (75% of RAM), but I suppose it’s nice to avoid having a warning, so yes, it will need to be reduced by 1.


#11

It would do what you want if attach-interrupt took the name of the function, rather than the function itself; for example:

(attach-interrupt 0 'tog)

Oh, yes, that way we can have both those functionalities! I like that :)

It could return the symbol you’ve attached on success, eg tog , and nil on failure.

Perhaps interruption would be better, since you can attach anonymous functions too.

I was just thinking about more reliable test, so I thought about connecting two Uno boards to each others interruption pins… slowly it’s growing to this crazy idea of automated game with Unos firing interruptions on each other to …yeah I didn’t figured out rest of it yet, but if you’re wondering if interruption support is worth the time - yep! Even for pure fun it gives :)


#12

One more thing - it’s possible now to pass anything as a function to attach (quoted symbol, number etc). And when you do, it kind of kills interruptions. On first interruption, you get error message '1' is an illegal function, and when you later attach function as you should - it isn’t fired up on interruptions at all.


#13

Something strange is happening to memory when I mix attach-interrupt and save/load-image. My image is:

(defun run nil (pinmode 2 2) (pinmode 13 t) (attach-interrupt 0 tog 3))

(defun tog (n)
  (digitalwrite 13 (not (digitalread 13)))
  (print (cons n (millis))))

When I load it - everything is OK. I loaded 63 pairs and I have 254 free. Now when I execute (run), fire up some interruptions and do (save-image) I get info that 63 pairs were stored (OK), but then I end up with only 19 free.


#14

Thanks - I’ll check that.


#15

Something strange is happening to memory when I mix attach-interrupt and save/load-image .

Yes, I should have anticipated that. I think interrupts will have to be cleared when you do a load-image (because the functions you’re calling on each interrupt may have moved in the new image).


#16

Are there any plans or interest in porting interrupt handling over to uLisp-arm?

Thanks!


#17

I put those plans on hold because I couldn’t decide how best to do it, and there seemed to be limited interest in it. What sort of applications do you have in mind?


#18

My immediate interest was for handling touch events on a screen, as I wanted to turn on and off interrupts as I read from an array of touch coordinates. It’s not too difficult for me to do it all in C for now. I just wanted to make sure this wasn’t also an option for ARM controllers. I’m much happier working in Lisp languages in a live environment whenever possible.

Eventually I’d also like to do some basic scheduling, so interacting with the periodic interrupt timer, clock interrupt or what have you would be nice.

Thanks, this has been a pleasure so far.


#19

are there any plans to revive interrupt support for uLisp? this is something i use a lot in Arduino for my music projects. ie i will attach an interrupt to a pin, and use that as my clock / gate input for stepping an algorithm via an external synthesizer module or modular sequencer. these use gates / triggers etc instead of MIDI via serial.


#20

I had a prototype implementation working on one platform, where you could define a Lisp function as an interrupt-service routine, but I wasn’t satisfied with it for two reasons:

  1. I couldn’t see how it could be implemented in a consistent way on all platforms.
  2. Although interrupts were responded to immediately (within a few clock cycles), there was an unavoidable latency before running the Lisp interrupt-service routine.

An alternative would be: a flag set immediately by an interrupt, and you can then use polling in the Lisp program to see if the flag has been set. Would this be an acceptable alternative?