[En-Nut-Discussion] Do we need something like sbv/sbi to complement sbi/cbi?
Ulrich Prinz
ulrich.prinz at googlemail.com
Wed Jan 4 16:53:04 CET 2012
Hi!
Am 01.01.2012 17:26, schrieb Uwe Bonnes:
> Hello,
>
> a happy new year to all!
>
>>>>>> "Ulrich" == Ulrich Prinz <ulrich.prinz at googlemail.com> writes:
>
> But I see one major obstacle:
> The ST provided headers mostly only define bit values, not the bit position.
>
> As I don't know of a macro to invert the BV() macro, we have to add bit
> position defines to the header files.
> Should these definitions go into stm32_<device>.h?
>
It is the best Place to add them there.
> ...
> Ulrich> Please look at the stm32_gpio.c and it's relevant .h file. All
> Ulrich> gpio functions are single cycle single access regardless of
> Ulrich> their names.
>
> Ulrich> Using the bitband functions as a reference any Cortex Register
> Ulrich> can be access atomic for switching single bits in it.
>
> Isn't the STM GPIO a bad example. With the BSRR registers, atomic access is
> also possible without bit banding...
> So i think e.g.
> #define GpioPinSetHigh(bank, bit) \
> GPIOMEM(GPIOBITBAND((bank+GPIOBBREG_BSRR), (int)bit)) = 1
Wrong:
If you need to set a ping if a variable has a value that is non zero and
reset the pin as long as the variable is zero, you produce a lot of code
if you use BSRR / BRR as you have to do an if, free a register, write a
bitmask into it and write that bitmask into the gpio register.
if (myvar)
BSRR = MY_BIT;
else
BRR = MY_BIT;
If you use bitband any value written to the bits register will result in
a written 1 if it is not equal zero and a written 0 if it is.
bitband(MY_BIT)=myvar;
That's atomic :)
> could be happily replaced with
> #define GpioPinSetHigh(bank, bit) GPIOMEM(GPIOBBREG_BSRR, BV(bit))
> and
> #define GpioPinSetLow(bank, bit) GPIOMEM(GPIOBBREG_BSRR, BV(bit+16))
Ups...
The second isn't atomic as it requires the shift left as long as the
value is not constant at first pass of the compiler.
Sou you should use GPIOMEM(.._BRR...
As the ARM the Cortex has the BitResetRegister too, it is only shadowed
to the upper 16 bits of the BSRR.
>
> But for other devices the remark about bitbanding still holds.
>
> >> The s/cbi macro expands in devnut_m3n expands like #define cbi(_reg,
> >> _bit) outr(_reg, inr(_reg) & ~_BV(_bit)) and was used like cbi(
> >> &TIM->SR, TIM_SR_UIF ); and so things got wrong.
>
> Ulrich> You can check the bitband access from gpio and transfer it to
> Ulrich> any register of the Cortex. It is importand that the bitband
> Ulrich> macros expect the bit-number not the bit mask.
>
> Again, the ST Headers mostly lake the Bit number and only define the
> bitvalue
>
To be honest only a few bits need this special attraction.
For instance the most things could be done like I did in the PLL setup:
myreg = PLL->CtrlReg;
if () myreg |= STM_BITMASK;
else myreg &= STM_OTHER_BITMASK
...
PLL->CtrlReg = myreg;
Only for special bit that need imediate special attention to speed up
things and to optionally guarantee atomic access, you could add the
bitband thingy.
In 99,99% of all usecases this is access to gpio for chip selects, ready
signals an such.
> >> The coding style rules say that direct register access like
> TIM2-> SR |= TIM_SR_UIF
> >> is deprecated. So either explicit writing outr(_reg, inr(_reg) &
> >> _mask) is needed, or some macros to do so. In my tree I added
> >>
> Ulrich> For Cortex it doesn't make any difference and it is the
> Ulrich> preferred method to use register pointers as ARM architecture in
> Ulrich> general does not need any inr or outr things.
>
> >> #define sbv(_reg, _mask) outr(_reg, inr(_reg) | _mask) #define
> >> cbv(_reg, _mask) outr(_reg, inr(_reg) & ~_mask) #define
> >> bv_is_set(_reg, _mask) ((inr(_reg) & _mask)) != 0)
> >>
> Ulrich> For compatibility or coding style ( even I hate this typing
> Ulrich> overhead making code unreadable) you can substitude inr( reg) by
> Ulrich> (reg) and outr( reg, v) by (reg) = (v)
>
> But http://www.ethernut.de/en/documents/programming-style-guide.html tells:
>
> "Don't use the IOREG = value, value = IOREG notation
> Use outb(), outw(), outr(), inb(), inw() or inr().
> This allows trapping and emulation."
Yes and I am feeling guilty... Ahh, No I don't.
If you need to trap that register just set a watchpoint in GDB and it
will be trapped for you without any additional overhead in production of
code just to overcome a debugger problem that existed in old ARM
architectures.
In the examples and in general drivers that reside in /dev it is ok for
me, but in arch/dev it is a waste of time and typing.
If you do it like
outr( reg) (reg)
inr(reg) (reg)
you still can do outr( DEV->REG) = value
or
outr( reg, v) (reg) = (v)
outr( DEV->REG, value)
If one feels better then...
More information about the En-Nut-Discussion
mailing list