L'Hexapod: Registers, stack usage and timing

Previously published

This article was previously published on lhexapod.com as part of my journey of discovery into robotics and embedded assembly programming. A full index of these articles can be found here.

So far the servo controller development has been reasonably straight forward; once various design issues were considered and once I’d got my head around building the hardware and learning AVR assembly language. However I expect that my assembly code has many novice mistakes and that it’s probably not especially idiomatic. I haven’t been writing in the language long enough and I haven’t read enough of other people’s code for it to be otherwise.

Adding more functionality to the servo controller and extending the ‘second’ thread of execution, the serial protocol code has started to expose weaknesses in the design. The timer code uses lots of registers; it was the easy way to make the code a bit more readable. Rather than simply reusing the same registers I have named the various registers with reasonably accurate names and hoped to give the code a little more meaning. Unfortunately the register set is limited and the more I use in the timer code the more complex it makes the transition between the serial code and the interrupting timer code. Every register that is used in both threads of execution needs to be pushed onto the stack when the interrupt occurs. This uses precious SRAM for our stack as we need to reserve space for the largest stack that we can use and we then can’t use that space to support additional servos. It also takes time at the start of the interrupt handler and that time is something that is more important to us that the space used by the stack.

The idea of using the same prologue and epilogue code for the timer interrupt no matter which state we were in; setup or pulse switch off, is good from a ‘simple design’ point of view and it’s a good way to make sure that we don’t forget to adjust the code in one place whilst adjusting it in another but it means that the setup code, which uses lots of registers, inflicts its stack requirements on the pulse switch off code which uses fewer registers. The more work that the pulse switch off code does before it gets to the point where the pulses are switched off the greater the minimum pulse length we support will be.

Whilst stubbing out some of the new serial code and adjusting the stack operations to protect the shared registers I not only managed to reduce the number of servos that the ATTiny2313 can support from 18 down to 15 due to stack space requirements but I also managed to take longer than the minimum pulse length of 6 ticks. This caused a very obvious failure as, during the interrupt handling for one pulse, the timer was reset to a duration of 6 yet the timer was already at a point beyond 6 and so the timer ran for the whole 16-bit duration before going off…

I expect my redesign will separate the stack handling for the setup and switch off interrupts and attempt to reduce the number of registers that the setup phase uses. We’ll see. I think the code for this project has just moved beyond ’toy example’ status…