Hi, another crazy wish:
Anybody possibly has an idea how to get the bit number from the predefined bitmask?
STM32F4xx.h has very nicely predefined all bitmasks for the peripheral bits, e. g. for the interrupt status flags in the TIM_SR registers:
#define TIM_SR_UIF ((uint16_t)0x0001) /*!<Update interrupt Flag */ #define TIM_SR_CC1IF ((uint16_t)0x0002) /*!<Capture/Compare 1 interrupt Flag */ #define TIM_SR_CC2IF ((uint16_t)0x0004) /*!<Capture/Compare 2 interrupt Flag */ #define TIM_SR_CC3IF ((uint16_t)0x0008) /*!<Capture/Compare 3 interrupt Flag */ #define TIM_SR_CC4IF ((uint16_t)0x0010) /*!<Capture/Compare 4 interrupt Flag */ #define TIM_SR_COMIF ((uint16_t)0x0020) /*!<COM interrupt Flag */ #define TIM_SR_TIF ((uint16_t)0x0040) /*!<Trigger interrupt Flag */ #define TIM_SR_BIF ((uint16_t)0x0080) /*!<Break interrupt Flag */ #define TIM_SR_CC1OF ((uint16_t)0x0200) /*!<Capture/Compare 1 Overcapture Flag */ #define TIM_SR_CC2OF ((uint16_t)0x0400) /*!<Capture/Compare 2 Overcapture Flag */ #define TIM_SR_CC3OF ((uint16_t)0x0800) /*!<Capture/Compare 3 Overcapture Flag */ #define TIM_SR_CC4OF ((uint16_t)0x1000) /*!<Capture/Compare 4 Overcapture Flag */
In the "Timer Update Interrupt" I need to clear the UIF flag in the TIM_SR register. I would prefer to do this atomic.
For this I defined the following macro:
#define BB_OFFSET 0x02000000 #define BB_SRAMMASK 0xF0000000 #define CLEAR_BIT_BB(VarAddr, BitNumber) \ (*(__IO uint32_t *) ( (VarAddr & BB_SRAMMASK) | BB_OFFSET | ((VarAddr & (BB_OFFSET-1)) << 5) | ((BitNumber) << 2)) = 0)
Now I can nicely use the command
#define BITNR_UIF 0 CLEAR_BIT_BB(TIM8->SR, BITNR_UIF);
This generally is very nice - just I am disturbed that I have to define this BITNR_UIF. It would be very nice to get the BitNumber from the STM32F4xx.h mask definition somehow automatically by some macro. Converting BitNumber to BitMask is easy with the 1<<BitNumber operator, but other direction seems to be impossible. Anybody has some hint? (Or Keil could consider to implement a precompiler instruction log2, so that BitNumber=Log2(BitMask)???
Now I made my own "log2"-macro:
#define BITNR(x) (x&0x1?0:x&0x2?1:x&0x4?2:x&0x8?3: \ x&0x10?4:x&0x20?5:x&0x40?6:x&0x80?7: \ x&0x100?8:x&0x200?9:x&0x400?10:x&0x800?11: \ x&0x1000?12:x&0x2000?13:x&0x4000?14:x&0x8000?15: \ x&0x10000?16:x&0x20000?17:x&0x40000?18:x&0x80000?19: \ x&0x100000?20:x&0x200000?21:x&0x400000?22:x&0x800000?23: \ x&0x1000000?24:x&0x2000000?25:x&0x4000000?26:x&0x8000000?27: \ x&0x10000000?28:x&0x20000000?29:x&0x40000000?30:x&0x80000000?31:32) #define CLEAR_BIT_BB( Var, BitMask) \ (*(__IO uint32_t *) ( ( ((uint32_t)&(Var)) & BB_SRAMMASK) | BB_OFFSET | (( ((uint32_t)&(Var)) & (BB_OFFSET-1)) << 5) | (BITNR(BitMask) << 2)) = 0) #define SET_BIT_BB( Var, BitMask) \ (*(__IO uint32_t *) ( ( ((uint32_t)&(Var)) & BB_SRAMMASK) | BB_OFFSET | (( ((uint32_t)&(Var)) & (BB_OFFSET-1)) << 5) | (BITNR(BitMask) << 2)) = 1) #define READ_BIT_BB(Var, BitMask) \ (*(__IO uint32_t *) ( ( ((uint32_t)&(Var)) & BB_SRAMMASK) | BB_OFFSET | (( ((uint32_t)&(Var)) & (BB_OFFSET-1)) << 5) | (BITNR(BitMask) << 2)) )
With this it works nicely, I can write such things like:
CLEAR_BIT_BB(ADC1->SR,ADC_SR_JEOC);
using the BitMASK definition for ADC_SR_JEOC.
If anybody knows some simpler replacement for this long macro BITNR defined above, I anyway would be very grateful.
By the way, I seem to remember that my version of the CLEAR_BIT_BB() macro would do address calculation at run time with the RealView compiler. Can you verify that with your setup? IAR compiler, on the other hand, would calculate the address at compile time.
Yes, of course my version calculates all the addresses at compile time (otherwise I would not use it - I need it to save time and to keep atomic :) ).
Can you post your version of CLEAR_BIT_BB?
#define REG32(addr) (*(uint32_t volatile*)(addr)) #define PERIPH_BASE 0x40000000 #define REGBIT(reg,bit) REG32(PERIPH_BASE+0x2000000+((uint32_t)&(reg)-PERIPH_BASE)*32+(bit)*4) ... /* usage example */ REGBIT(RCC_AHBENR, 3) = 1; REGBIT(RCC_AHBENR, 3) = 0;
What I meant is when all numbers are known at compile time, the compiler should be able to just use the resulting address. I was very surprised to see that the RealView compiler would not do that. It appears that it will not use the result of (uint32_t)&(reg) for compile time calculations. Odd, isn't it?
Are you sure - this sounds strange - maybe in optimisation level zero?
(I always use optimization level 1 - USB lib of ST e. g. does not work in optimisation level zero).
I checked my macro thoroughly, and the compiler produces exactly 2 assembler commands: An LDR to load the address in a register (which is omitted if some nearby base address is already available). An STR to save the 0 or 1 to this register.
So very optimum - I did not find any troubles.
The advantage of my solution is, that you can work with the bitmask values which are defined in the STM32F4xx.h directly - you do not need to define your own BitNr values.