Lisp Badge note support


Might it be possible to support the note function on the Lisp Badge’s piezzo buzzer (pin 4/PB4), while keeping the keyboard functional?


I’ll need to refresh my memory about the circuit, but if I remember correctly I don’t think it’s possible without changing tracks on the PCB.


Try this: replace the section of code between

// Note


// Sleep


const int scale[] PROGMEM = {4186,4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902};

void playnote (int pin, int note, int octave) {
  int prescaler = 8 - octave - note/12;
  if (prescaler<0 || prescaler>8) error(NOTE, PSTR("octave out of range"), number(prescaler));
  tone(pin, pgm_read_word(&scale[note%12])>>prescaler);

void nonote (int pin) {

The piezo speaker is on pin 4. Here’s a test program that plays a scale:

(defun sca () 
   (lambda (n) (note 4 n 4) (delay 500))
   '(0 2 4 5 7 9 11 12)) 

For some reason it doesn’t seem to work when you have a USB-to-serial board plugged in.

Regards, David


2 posts were split to a new topic: Big text mode


That works, thanks. One thing I noticed is that when using the keyboard to enter a program, I always have to complete a note-playing block with (note), otherwise the keyboard stops accepting input until after a reset. I wonder if ESC could call (note) somehow.


Strange… I’ll investigate.


Ah yes, I see what you mean now. I’m not sure why - on other platforms you can continue using the REPL loop while notes are playing.

You could try changing the line in ProcessKey() to:

if (c == 27) { setflag(ESCAPE); noTone(4); return; }    // Escape key

This is just a workaround, not a good permanent solution!


The ESC key press still doesn’t seem to get through, unfortunately.

I had been playing around with overloading ISR(TIMER2_OVF_vect) to also toggle the buzzer pin, in the same way that Tone.cpp’s ISR does, but while still accepting keyboard input. I made some progress, and I can get a tone playing while still being able to use the keyboard, but I can’t vary the pitch.

I narrowed down that it is these calls in Tone that lock the keyboard:

TCCR2A = 0;
bitWrite(TCCR2A, WGM21, 1);

I guess that mode directly conflicts with how InitKybd wants to set up that register (TCCR2A = 0<<WGM20; // Normal mode). I’m not sure if those two states can be reconciled somehow, so that I can vary the pitch and still use the keyboard.


The WGM bits together determine the mode the counter runs in, so they’re not independent. Changing either of them means choosing a different mode. The tone function is setting it so that the counter resets on a specified value - a value determined by the frequency to be played, I believe. (It’s been a while since I looked at this in detail.) The keyboard init routine wants it to simply count to the top, presumably to generate an interrupt when the counter wraps around. In the mode note wants, it won’t ever wrap around. That’s probably why the keyboard dies.

You can’t reconcile those different modes, but there are two solutions I can think of: Either use a different timer for the keyboard interrupt (looks like there’s four of them on the chip) or change the interrupt being used - each timer has three possible interrupts. I don’t know enough to say which is more reasonable, though…


Great explanation, thanks @odin . I changed LispBadge.ino to use timer 1 for keyboard scanning, while still calling stock tone as @johnsondavies had suggested. Now I can play a note asynchronously and the keyboard is still responsive. (I didn’t try changing the interrupt being used.) The only thing I notice now is the tone isn’t as clear; it has “beats” in it. I’m not sure if that’s caused by internal interference due to enabling an additional timer, or if the mode I’m using isn’t the best possible one (I didn’t give the 16-bit Timer/Counter1 section of the data sheet a close reading). I pushed the change to sourcehut in case others are interested:


@johnsondavies explained why the tone wasn’t as clear, because the keyboard scanning interrupt service routine was sometimes delaying the tone generation interrupt service routine.

The extra buzzing is easier to notice at higher frequencies, like (note 4 0 8). Even with keyboard scanning totally disabled, there is still some buzzing, but I think that’s due to imprecisions inherent in the timer, not something that can be addressed in software.

I discovered I can allow the tone ISR to nest within the keyboard ISR by changing ISR(TIMER1_OVF_vect) to ISR(TIMER1_OVF_vect, ISR_NOBLOCK). The result is the keyboard can still be used while a note is playing, and the note quality is as good as when keyboard scanning is disabled. I pushed the change to sourcehut. I’m satisfied with this as a complete solution to note support on the Lisp Badge.

Thank you for all the help.