SVP-324 servo & buzzer control

Hello Everybody!
Recently I purchased SVP-324 robot controller and now I am playing with my new toy. The first thing what I tried to do is to modify svp-demo-program to add servo control. I added a new entry to the menu and wrote a function, associated with this entry (added string

static const char menu_servo_test[] PROGMEM = “Servo 0”;

and added corresponded items into main_menu_functions[] and *main_menu_options[]). Then I copied the content of main() function from svp-one-servo project to my function, associated with “Servo 0” menu entry. I made the only one modification to this code. Inside while(1) {…} loop I added the following button check

        if (button_is_pressed(MIDDLE_BUTTON))
             break;

to go out the infinite loop when the middle button is pressed. It worked as expected until I pressed the middle button. I went back to the menu (as expected), but I lost sound and servo was jerking every time I pressed the top and bottom buttons.

I saw the warning, that servo and buzzer libraries conflict (use the same Timer 1). Well, I do not want to control servo motor AND play music simultaneously. I am quite happy to do something with the servo and then switch back to the buzzer and leave the servo alone. In the beginning of the code from svp-one-servo project there is function servos_init(…). This function does something to the Timer 1 and buzzer does not work after this modification. If there were similar function buzzer_init(…) I would just call it before exiting my servo-function to restore the state of Timer 1. Unfortunately, there is no such function.

Now, finally, my question. How can I undo what servos_init(…) function does to the Timer 1 so I can use buzzer again?

Konstantin

Hello.

My original plan when adding the servo library was to make a way to disable it so that the buzzer code would work again, but I think that slipped through the cracks. I’ll add such a function to the next release of the library, but in the interim I can give you a function that accomplishes this:

void initBuzzer()
{
  TIMSK1 = 0;  // disable all timer 1 interrupts
  TCCR1A = 0x23;  // OC1A disconnected, clear OC1B on comp match when upcounting & set when downcounting
  TCCR1B = 0x11;  // phase-correct PWM with TOP = OCR1A and timer prescaler of 1
  TCCR1C = 0x00;
  OCR1A = 10000;  // set TOP for freq = 1 kHz
  OCR1B = 0;  // set 0% duty cycle (buzzer is silent)
}

I haven’t tested this, but I copied it from the library source code, so I expect it to work. When you want to switch from using servo functions to the buzzer, call this function to reconfigure timer 1 from servo mode to buzzer mode. When you want to switch from using the buzzer to servos, use the following line of code to disable the the timer 1 interrupts used by the buzzer library before initializing for servo mode:

TIMSK1 = 0;

Also, you should include the line:

#include <avr/io.h>

at the top of your program. This header file defines all of the AVR specific registers like TIMSK1 and TCCR1A.

Does this make sense? If you have any problems or questions, please let me know.

- Ben

Thank you, Ben!
It works! I have another question about details of realization. Subroutine servos_init(…) sets several interrupt vectors. Well, not subroutine itself, but inside the file with this subroutine there are several ISR(…). I am not sure what is exactly happening when you put ISR(…) in your code. I could not find too much information about it. Just that this is a macro which sets interrupt vectors. Macro? Hmm-m-m, year … As I understand, real thing called macro does not produce a code, but rather a template for later code generation. The real code is generated when the macro is called by a programmer. Well, nobody calls ISR(…) it does something by itself BEFORE the main() starts. In Assembler I exactly know what to do: write a code of the interrupt handler and set a jump to this code at the appropriate address (interrupt vector). Probably, ISR(…) is doing something like this. But !

  1. Does ISR(…) set interrupt only once before main() starts or every time I call servos_init(…) ?

  2. If every time, than calling servos_init(…) will cause memory leackage. A new copy of the interrupt handler code is allocated in memory and interrupt vector is initialised by jump operator to this code. The old copy still occupies the program memory, but the pointer on this piece of code is lost. Very unlikely. If interrupt handler is initialized only once, than how can I change the interrupt handler subroutine when program is running? For example, in assembler I have 2 subroutines interrupt handlers for the SAME interrupt. Initially, I set interrupt vector pointing on the 1st subroutine. If I want to swithch to another handler, I have to replace the interrupt vector and make it pointing on the 2nd subroutine. What about C?

Konstantin

The ISR macro is a directive to the compiler, not something processed at run time. The compiler places a jump to the flash location of the start of the ISR code block at the appropriate place in the interrupt jump table. Each interrupt vector has its own table entry, and when an interrupt happens, code execution jumps to that vector’s table location, which in turn jumps execution to the ISR. The ISR tag also causes certain instructions to be automatically added, such as disabling of interrupts while the ISR code is being executed. All the servo_init() function does is enable particular interrupts. The ISR code block is in your AVR’s flash whether these interrupts are enabled or not.

The only way you could have a memory leak is if you reenable interrupts inside an interrupt in a way that causes recursive interrupts. For example, imagine writing a timer overflow interrupt handler that takes longer to execute than the timer overflow period. If you reenable interrupts inside your ISR, execution will repeated jump back to the beginning of the ISR, and each time the value of the registers used by the ISR will be pushed onto the stack. Since execution doesn’t reach the end of the ISR, these values aren’t popped off the stack and your stack will eventually overflow. You have to try really hard to write bad code for something like this to happen, though.

- Ben

avr-gcc does not support anything close to what you are talking about. There is no dynamic allocation of flash memory. All the code you write is burned in to the flash memory of the AVR when you program it and the flash memory doesn’t change while your program is running (unless you’re doing something fancy). The type of memory leak you are positing is not possible.

The only type of memory leak you should worry about is a RAM memory leak. Ben talked about how the stack might get too big if you had recursive interrupts. Also, the heap might get too big if you call malloc repeatedly without calling free. You won’t have to worry about either of those problems in servos_init.

Are you saying that in assembly, you wrote code to modify your interrupt vector table in flash at run time? You could do the same thing in C, but it seems like a bad idea because erasing and writing to flash can take a few milliseconds and you might accidentally corrupt that part of your flash (e.g. if you have a bug or if you lose power). What you can do (in C or assembly) is have two functions and put an if statement in your ISR which chooses which function to call.

-David