2014-06-26 02:40 AM
I would like to optimize next snippet:
void
write16Data(u16 data) {
GPIOA->BSRR = 0x00ff0000 | (u8)(data & 0xff);
GPIOB->BSRR = 0x00ff0000 | (u8)(data >> 8);
}
Any ideas?
2014-06-26 04:48 AM
If you call this repetitively in a loop, inline, of pull into the loop. Unroll to loop. Use constant pointers. Use assembler.
2014-06-26 05:31 AM
Indeed this function called in a loop so I will add ''inline''
But I would like to do something like:union
{
u16 word;
u8 bytes[2];
} data;
(u8 * ) portA = data.bytes[0];
(u8 * ) portB = data.bytes[1];
So to avoid shift and other operations - just right usage of pointers
2014-06-26 05:58 AM
I didn't notice which stm32 microcontroller you are using.
This is possible in stm32f4xx, where the reference manual section 8.4 says GPIO registers are byte-addressable.So how about trying*(uint8_t*)GPIOA->ODR = data.bytes[0];*(uint8_t*)GPIOB->ODR = data.bytes[1];But not possible in stm32f10x where section 9.1 says the GPIO registers are only addressable as 32-bit words. - DanishEdit: I forgot stm32f10x does not support byte-addressing2014-06-26 06:27 AM
GCC allows to do that very ugly stuff:
void gpiotest(uint data) {
uint32_t da = 0x00ff0000 | (u8)(data & 0xff);
uint32_t db = 0x00ff0000 | (u8)(data >> 8);
asm volatile (
''str %0, %1;''
''str %2, %3;''::
''r''(da),''m''(GPIOA->BSRRL),
''r''(db),''m''(GPIOB->BSRRL)
);
}
Which compiles down to:
c0000c20: b2c3 uxtb r3, r0
c0000c22: f3c0 2007 ubfx r0, r0, #8, #8
c0000c26: f443 037f orr.w r3, r3, #16711680 ; 0xff0000
c0000c2a: f440 007f orr.w r0, r0, #16711680 ; 0xff0000
c0000c2e: 4902 ldr r1, [pc, #8] ; (c0000c38 <
gpiotest
+0x18>)
c0000c30: 4a02 ldr r2, [pc, #8] ; (c0000c3c <
gpiotest
+0x1c>)
c0000c32: 6193 str r3, [r2, #24]
c0000c34: 6188 str r0, [r1, #24]
c0000c36: 4770 bx lr
c0000c38: 40020400 .word 0x40020400
c0000c3c: 40020000 .word 0x40020000
IMHO, it is the only way to make sure store instructions will be beside each other.
Moreover, that way, it can be even more optimized when inlining and loop unrolling are automatically performed by the compiler.
Solutions like (type*)<addr>=<value> are very good, as long as you use the volatile keyword to qualify the type, otherwise optimization may kill some writes.
2014-06-26 07:25 AM
Got it,
So((uint8_t __IO*)&GPIOA->ODR)[0] = data.bytes[0];
will not work on stm32f100 :(