More Time Planning

Unfortunately, due to the Holidays and finding myself engrossed in a work project I haven’t had time to finish the timer design for the ARM system I’m working on. There are some core bits I can’t decide on in a way that is satisfactory to me so I’ve been kicking around different ideas. To start, if you have X hardware timers but want to support essentially infinite software timers what is the best way to do it? The common approach in a situation like this is to use the system tick timer (systick) and have it tick every Y milliseconds. When its associated interrupt is fired you check if any timers should have their callbacks / events handled and you go back to work. Unfortunately, this also means your timing system has potential to be off by nearly Y every timer since it may fire and reschedule itself right before the deadline you were trying to meet. For that reason I’ve been pondering a system where you utilize all the hardware timers available in a FIFO sort of design, keeping in mind the constraints of each. For example, on the NXP chip I mentioned in a previous post there are two 16 bit timers and two 32 bit timers. A data structure I had in mind for keeping track of all of them is:

typedef struct {
        uint32_t        *base_addr;
        uint32_t        cnt_max;
        uint8_t         in_use;
        void            *callback;
        void            *arg;
} timer_t;

timer_t system_timers[] = {
    { LPC_TM16B0, 0xFFFF, 0, NULL, NULL },
    { LPC_TM16B1, 0xFFFF, 0, NULL, NULL },
    { LPC_TM32B0, 0xFFFFFFFF, 0, NULL, NULL },
    { LPC_TM32B1, 0xFFFFFFFF, 0, NULL, NULL }
};

Under this setup when a timer is set it can walk the timer list and find the first timer that is both unused and has the largest precision that will successfully fit the requirements. Another benefit to this is that all four timers can be mapped to the same interrupt handler which can walk the list to figure out what fired and handle it appropriately. A modification would be made so there was some sort of identifier to properly do that, so I imagine it would be easier to just have a single interrupt handler mapped to each vector via a macro to fill in those characteristics.

My problem right now stems from how I want to handle the infinite timer issue. If timers are configured to fire in some number of microseconds, what happens if all the timers are in use and I try to set up one that should expire in the middle of them? Do I find one that would fire after my new one and replace it? That would accrue a timing penalty as I swapped the data out and reconfigured the hardware block. I would also need to add a field to track the expected time to fire and do a number of comparisions. Considering how sensitive the constraints in that situation are, I think a better approach would be a hybrid approach. Something like using 3 of them for timers as needed, then in overflow cases have the fourth timer dedicated to a systick type behavior. When timers become free they can grab from the waiting timer pool as available. I’ll have to put more thought into it and perhaps prototype it to see how it feels.