#define TCB0_MODE(v) TCB0.CTRLB = ((TCB0.CTRLB & 0xf8) | (v))
you can even take it further since you have more than one of the same timer-
#define TCB_MODE(n,v) TCB##n##.CTRLB = ((TCB##n##.CTRLB & 0xf8) | (v))
now you have a generic for every timer b
TCB_MODE(0, 0)
TCB_MODE(1, 0)
(you would even get an error if n was an invalid number)
but it is endless when it comes to defines/macros, and you end up with another language to maintain where you use the manufacturers defines/macros, your own defines/macros, and ultimately the functions which will use a combination of both
not trying to throw wrenches into gears, but maybe consider just using functions to do the work
a simple example using the avr defines already provided, and turning the mode setting into a function-
//just to make sure using a valid timer number
//(there could already be something in the avr include for this, I don't know)
typedef enum { TCBn0, TCBn1, TCBn2, TCBn3 } TCBn_t;
//simple function
//if we want to know what some of these defines are- look in one file- iom4809.h
//this function and iom4809.h are all we need to see how this function works
TCBmode(TCBn_t n, TCB_CNTMODE_t mode){
TCB0[n].CTRLB = (TCB0[n].CTRLB & (TCB_CNTMODE_gm<<TCB_CNTMODE_gp)) | mode;
}
//usage- it looks like a function, and it is a function
TCBmode( TCBn0 ,TCB_CNTMODE_TIMEOUT_gc );
//compare to
TCB0_MODE_TIME_OUT_CHECK;
//or
SET_TCB0_MODE(TCB0_MODE_TIME_OUT_CHECK);
//or
TCB_MODE(0, TCB0_MODE_TIME_OUT_CHECK);
//or any other type of macro/define
//AND_IT_ENDS_UP_LOOKING_LIKE_THIS_EVERYWHERE_FOR_EVERYTHING & WHICH_IS_HARD_TO_READ & DECIPHER
I know every last byte wants to be squeezed out of a micro, but compilers are good at removing unused code, in-lining, etc., and in many cases the defines/macros are not worth the trouble when a function will do the job with little cost and where readability/reliability becomes much better (in my opinion).
I'll go crawl back into my hole in the ground.