Help wanted with timer register management

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Help wanted with timer register management

1,749 Views
dwhite
Contributor I
CPU: MC9S12XDT256
Codewarrior 4.5
I often need to change the configuration of the timer control register in my ISRs for things like PWM generation or pulse width measurement. Anyone who has done this knows that these shared registers are a real pain.
 
I'm trying to write wrapper functions that protect the registers and allow for channels to be easily reassigned with a single channel assignment macro.
Example:
#define PULSE_WIDTH_MEASUREMENT_CHANNEL 3
#define PWM_GEN_CHANNEL 4
 
I want something like this in my ISRs:
if(IS_IC_CHANNEL_RISING(PULSE_WIDTH_MEASUREMENT_CHANNEL))
  Config_IC(PULSE_WIDTH_MEASUREMENT_CHANNEL, IC_ON_FALLING_ONLY);
else
  Config_IC(PULSE_WIDTH_MEASUREMENT_CHANNEL, IC_ON_RISING_ONLY);
 
or
if(IS_OC_CHANNEL_RISING(PWM_GEN_CHANNEL))
  Config_OC(PWM_GEN_CHANNEL, OC_CLR);
else
  Config_OC(PWM_GEN_CHANNEL, OC_SET);
 
The functions would have to disable interrupts, read the register(s), modify and then re-enable interrupts.
 
Does anyone have any examples of good wrapper functions or macros that can help with the management of these registers?
Labels (1)
0 Kudos
2 Replies

362 Views
kef
Specialist I
Yes, those EDGxA, EDGxB, OLx and OMx bits are the pain.
Also it's obvious that function(), that would set specific timer channel to specific compare/capture mode, such function would be also ineffective, because it would unavoidably include series of shifts left or right, ands and ors. In practice timer channel we are setting up is known and constant, it could be some const define. So my choose is a set of macros.
 
Code:
#define CAPTOFF       0#define CAPTRISING   1#define CAPTFALLING 2#define CAPTANY        3#define SetCaptureMode(channel, mode)              \               (&TCTL3)[1-(channel >> 2)]  =       \                    (&TCTL3)[1-(channel >> 2)]     \                    &  ~(3 << ((channel & 3)*2)) ; \               (&TCTL3)[1-(channel >> 2)]  =       \                    (&TCTL3)[1-(channel >> 2)]     \                    |  (mode  << ((channel & 3)*2))

 
Usage example:
Code:
#define mychannel 4
   SetCaptureMode(mychannel, CAPTANY);

 
This should compile to two instructions, bclr and bset. Bclr should set capture off for given channel, and bset should set new capture mode. Of course you should not use this macro with variable channel and/or variable capture mode. Small and effective code is guaranteed only using compile time constants.
 
How to check if specific channel is set to specific capture mode, without shifts and big code:
Code:
#define IsCaptureMode(channel, mode)               \           ( ( (&TCTL3)[1-(channel >> 2)]          \                    &  (3 << ((channel & 3)*2)) )  \             == (mode << ((channel & 3)*2)) )

 
Example:
Code:
   if(IsCaptureMode(mychannel, CAPTRISING))   {      ...   } 

 
In my SetCaptureMode macro, I'm changing capture mode in two steps. First I'm setting capture to off, then switching to target capture mode. Such two steps are OK for changing capture mode, but not good for changing compare mode. Compare mode, most often has to be changed without intermediate state like pin disconnected from output compare. So macro for SetCompareMode is bit different and compiles to little bigger code:
Code:
#define COMPOFF  0#define COMPTOGGLE  1#define COMPCLEAR  2#define COMPSET  3#define SetCompareMode(channel, mode)              \               (&TCTL1)[1-(channel >> 2)]  =       \                    (&TCTL1)[1-(channel >> 2)]     \                    &  ~(3 << ((channel & 3)*2))   \                    |  (mode  << ((channel & 3)*2))

 
Didn't try above with CodeWarrior, but I hope it will work as expected.


Message Edited by kef on 2008-12-18 11:06 AM
0 Kudos

362 Views
dwhite
Contributor I
Thanks, kef!
This is exactly the kind of elegant solution I was hoping for. In every situation, we know the channel and edge type at compile time so this solution works perfectly. I have tested this and also added a second version with SEI and CLI to protect my nested interrupt instances.  I also added an "IsCompareMode" which is exactly the same except pointing to TCTL1 instead of TCTL3.
0 Kudos