ETLCPP / etl

Embedded Template Library
https://www.etlcpp.com
MIT License
2.04k stars 371 forks source link

On STM32 gcc fails compile callback_timer_atomic (but compiles queue_spsc_atomic) #891

Closed positron96 closed 1 month ago

positron96 commented 1 month ago

I am trying to use ETL for STM32G0 (cortex-m0) in platformio (with GCC 7.2.1), and I am experiencing interesting behavior in regards to _atomic class.

Specifically, queue etl::queue_spsc_atomic<char, 32, etl::memory_model::MEMORY_MODEL_SMALL> rxbuf; and code that uses it, compile fine, however using timer etl::callback_timer_atomic<5, std::atomic_int32_t> timer fails with

main.cpp:(.text.main_cpp+0xb8): undefined reference to `__atomic_fetch_add_4'
main.cpp:(.text.main_cpp+0xe0): undefined reference to `__atomic_fetch_sub_4'

As I understand it, queue uses ::load and ::store functions of atomics, which compile to correct ARM instructions, while timer uses operator++ and operator-- on atomics, which compile to intrinsics instead of arm instructions, and those are missing.

I took this etl::timer with atomic_int32_t as semaphore from ETL documentation, but upon closer inspection I am fine with just int32_t, which makes the timer not perfectly atomic.

jwellbelove commented 1 month ago

The main difference between etl::queue_spsc_atomic and etl::callback_timer_atomic is that the queue is expected to be accessed by only two threads, one writer and one reader. The writer thread only modifies the write index and the reader only modifies the read index. This means it can get away with not using atomic Read/Modify/Write behaviour.

The callback timer, on the other hand, may be accessed by N threads and therefore needs an atomic Read/Modify/Write counting semaphore.

I should probably add conditional compilation to the ETL to exclude parts of the library that cannot be used by certain processor types.

(Trying to ensure that an implementation of a lock free class works in every situation can result in stress and a headache!)

jwellbelove commented 1 month ago

For the Cortex-M0 you should look at etl::callback_timer_interrupt or etl::callback_timer_locked.

positron96 commented 1 month ago

Hi, thanks for an answer! I am only using the timer for the logic of periodically calling callbacks, and I do it in a main loop, without involving interrupts. So I don't think I actually need any synchronization complications.