cancel
Showing results for 
Search instead for 
Did you mean: 

Any atomic I/O bit access functions for STM8L?

Pavel A.
Evangelist III
Posted on October 23, 2017 at 21:36

I'm looking at file stm8l10x_gpio.c from the 'standard peripheral library'

http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm8-embedded-software/stsw-stm8012.html

 

and there does not seem to be a function to switch individual GPIO bits atomically.

For example the following compiles with Cosmic compiler to read-modify-write sequence

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint8_t GPIO_Pin)

{

GPIOx->ODR |= GPIO_Pin;

}

as well as this:

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, BitAction GPIO_BitVal)

{

if (GPIO_BitVal != RESET)

{

  SetBit(GPIOx->ODR, GPIO_Pin);

}

else

{

  ClrBit(GPIOx->ODR, GPIO_Pin);

}

}

So when interrupt handler drives some GPIO pin and the main program/other ISR uses other pin in same GPIO register, locking is needed. But ST8 has special instructions for manipulating single bits.

Macros SetBit, ClrBit are defined in stm8l10x.h and neither these are atomic.

Are there any intrinsic functions for bit set/clear (Cosmic compiler if possible)?

Thanks,

-- pa

12 REPLIES 12
Posted on October 23, 2017 at 22:47

I would suggest you refer to the STM8 processor documentation and make a determination if it supports such things architecturally. The GPIO doesn't have the BSRR type register of the STM32

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on October 24, 2017 at 00:04

Yeah STM8 supports bit instructions architecturally. Just like 8051.

But in C code this needs compiler-specific quirks. For Cosmic compiler, this looks like:

_Bool fire_missile @ GPIOA_ODR:1 ; // GPIO A bit 0x02

_Bool blink_led    

@ GPIOA_ODR:2 ; // GPIO A bit 0x04

void interrupt_handler() {

   

fire

_missile = 1;

}

void main() {

   while(1) {...   blink_led = 1; .... blink_led = 0; ... }

}

The _Bool's are translated to native ST8 bit variables and assignments are single bit set/clear instructions that affect only one bit. No locking is needed on the 

GPIOA_ODR register as in case of  

GPIOA_ODR |= 0x02.

If only I understand correctly, byte 'or' instruction has only one variant where destination is reg. A. No variant exists with destination in memory.

My question is, what people use to achieve lockless access to GPIO outputs? Disable interrupts across 'standard library' calls, or roll their own? 

Regards,

- p

S.Ma
Principal
Posted on October 24, 2017 at 04:22

As long as the IO port is declared as volatile and the compiler optimisation is properly setup, the compiler should generate the proper code, lock mecanism included.

As far as I remember, there is a bitset/bitreset read/modify/write instruction for a limited memory range.

Pavel A.
Evangelist III
Posted on October 24, 2017 at 15:46

Well, this is disassembly of stm8l10x_gpio.c

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint8_t GPIO_Pin)

{

  GPIOx->ODR |= GPIO_Pin;

}stm8l10x_gpio.c:220 GPIOx->ODR |= GPIO_Pin;

 LD A,(X)                     <--------------1

 OR A,(0x03,SP)

 LD (X),A                     <------------- 2

RET

As you see, no locking. If interrupt changes the GPIO data register (the address is in X) between points 1 and 2, the program is screwed.  At least, worth to be documented.

Regards,

- p.

luca239955_stm1_st
Senior II
Posted on October 25, 2017 at 09:47

Hello,

from the compiler point of view (Cosmic) bit accesses are converted to single BSET and BRES instructions whenever this is possible, but nothing is done automatically to ensure atomic access (the application code must take care of that)

In my memory the SetBit and ClearBit macros were converted to single instructions, but if you say this is not the case I'll check and report back here.

Regards,

Luca

Philipp Krause
Senior II
Posted on October 25, 2017 at 18:04

The stm8 bit set / bres / bcpl instructions exist only for direct addressing.

I would assume, that Cosmic, like SDCC uses them for setting / resetting / inverting bits in global variables (including I/O). But the posted code example sets bits through a pointer, so unless the function gets inlined and the pointer access somehow optimized out, compilers won't be able to use an STM8 bit set instruction.

Philipp

Posted on October 25, 2017 at 23:00

One can write a BSET/BRES instruction on the fly. It's not the fastest way to do it, and it's ugly, but it works.

Posted on October 25, 2017 at 23:40

Inlining looks OK for me. Usually the GPIO pins are referred directly. 

Regarding the 

SetBit and ClearBit macros - the .h file has alternative macros BitSet and BitClear - but I don't understand what they do. These seem to belong to some other architecture that has a limited area for bits, like 8051.

Inline implem. for Cosmic compiler can be like following:

typedef struct  {

  _Bool bit0; 

_Bool bit1; _Bool bit2; 

_Bool bit3; _Bool bit4; 

_Bool bit5; _Bool bit6; 

_Bool bit7;

} bytebits_t;

@inline void bset( volatile bytebits_t *pb, char i ) {

   switch(i) {

      case 0: pb->bit0 = 1; break;

      case 1: pb->bit1 = 1; break;

      case 2: pb->bit2 = 1; break;

      case 3: pb->bit3 = 1; break;

      case 4: pb->bit4 = 1; break;

      case 5: pb->bit5 = 1; break;

      case 6: pb->bit6 = 1; break;

      case 7: pb->bit7 = 1; break;

     }

}

@inline void bres( volatile bytebits_t *pb, char i ) {

   switch(i) {

      case 0: pb->bit0 = 0; break;

    ...............  etc.

@inline void GPIO_WriteBit(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, BitAction GPIO_BitVal)

{

if (GPIO_BitVal != RESET)

{

 

bset(&GPIOx->ODR, GPIO_Pin);

}

else

{

 

bres(&GPIOx->ODR, GPIO_Pin);

}

}

Creating BSET/BRES instructions on the fly also may work, as STM8 can execute code from RAM. 

--p

Posted on October 26, 2017 at 08:37

While the STM8 supports code execution from RAM, and thus self-modifying code, I wouldn't expect any compiler to use it here. It would be slow and complicated. Since the language doesn't require it, I wouldn't want compilers to generate slow code for such basic operations as setting a bit through a pointer. Not even with volatile.

Maybe a compiler could use self-modifying code to implement the ISO C11 atomic_fetch_or() and similar functions. But atomics are optional in ISO C11. Currently the only compiler that supports ISO C11 for the STM8 is SDCC, and SDCC defines __STDC_NO_ATOMICS__, and does not support atomics.

Philipp