Category Archives: Uncategorized

Embedded Signal-Slot

c++ embedded signal slot event loop -qt

github.com/andsmedeiros/uevloop, A fast and lightweight event loop for embedded platforms.
github.com/wqking/eventpp, Event Dispatcher and callback list for C++
Yassi: Yet Another Signal/Slot Implementation
Signal-Slot Implementation — Part 1
Signal-Slot Implementation — Part 2
Signal-Slot Implementation — Part 3
Signal-Slot Implementation — Part 4
Signal-Slot Mechanism Explained
ecl_sigslots
Introduction to Sigslots
Relaying Signals
ecl_sigslots Documentation – Embedded Control Library
miso: Micro Signal/Slot Implementation
Qt for non-graphical applications

STM32 Spinlock vs. Interruptlock

EnterCritical() and ExitCritical(): Why Things are Failing Badly
Cortex M atomic operations – Critical section
STM32: LDREX/STREX vs Interruptsperre
Interrupts ein-/ausschalten beim ARM cortex-M3
atomic-lib für stm32
Critical sections on Cortex-M3
LDREX/STREX race condition
DMB instructions in an interrupt-safe FIFO
Lock-free programming: how fresh is atomic value?

YouTube

Spinlocks – Part 1 – A Basic Spinlock
Spinlocks – Part 2 – Locally Spinning
Spinlocks – Part 3 – Active Backoff
Spinlocks – Part 4 – Passive Backoff
What’s Spin Lock? Spin Lock Vs. Mutex.
Bare-metal ARM firmware reverse engineering with Ghidra and SVD-Loader

STM32 Rotary Encoder

How to interface the rotary encoder to STM32 (CUBE-MX + ATOLLIC)
ROTARY ENCODER AND STM32
Implementing a simple menu interface on OLED display
Hardware Debounced Rotary Encoder

LVGL

LittlevGL on a Monochrome OLED
Demo of LvGL + Zephyr (v2.3) with SSD1306 display
, Demo of LittlevGL controlling a SSD1306 display on Zephyr + nRF52 (PCA10040)

LCDMenuLib2

github.com/Jomelo/LCDMenuLib2, Create a tree menu. Use it with different lcd types / console output / ssh console.
Display LCD with Menu and Rotary Encoder – Ug8lib – Arduino

STM32 I2S

Arduino / stm32duino

I2S Interface? HAL?

Arduino I2S sine wave

github.com/adafruit/Adafruit_ZeroI2S/blob/master/examples/tone_generator/tone_generator.ino

github.com/GrumpyOldPizza/arduino-STM32L4/blob/master/libraries/I2S/src/I2S.h
github.com/GrumpyOldPizza/arduino-STM32L4/blob/master/libraries/I2S/src/I2S.cpp

PCM5102 + PAM8406

2.4 – PCM5102 Sound Board + Loudspeakers

WAVE PCM Soundfile Format

WAVE PCM soundfile format

ChibiOS

STM32F4 Discovery MP3 player working – with source code

SEEED STUDIO Blog

Basic Electronics: High-Quality Audio with Inter-IC Sound(I2S) Bus

EFM32

High Quality Audio with I2S – Part 1
High Quality Audio with I2S – Part 2
High Quality Audio with I2S – Part 3

mikrocontroller.net

STM32 I2S mit DMA

eax.me

Учимся передавать звук с использованием протокола I2S
github.com/afiskon/stm32-i2s-examples, STM32: examples of I2S protocol usage

sparklogic.ru

I2S example code

ESP32 I2S

esp-idf

API Reference » Peripherals API » I2S

xtronical.com

ESP32 – Intro to I2S Part 1
I2S on ESP3 – Part 2, WAV’s
ESP32 I2S Part 3 – Playing Wavs from SD Cards
I2S Player (Part 4) : Adding volume control

YouTube

ESP32 – Intro to I2S Episode 1, explanation with basic example outputting a square wave
Understanding & playing WAV files on ESP32 using I2S. An In-Depth Tutorial with very simple example.

ARM Cortex-M4 Atomic / Mutex / Read-Modify-Write


Wikipedia

Test-and-set
Load-link/store-conditional (LL/SC)

  • Load-link returns the current value of a memory location…
  • …while a subsequent store-conditional to the same memory location will store a new value only if no updates have occurred to that location since the load-link.
  • Together, this implements a lock-free atomic read-modify-write operation.

Read–modify–write
RMW-Befehl


ARM Assembly

LDR/STR – Load/Store
LDM/STM – Load/Store Multiple
the speed of arm assembly ldm and ldr

LDREX – Load Register Exclusive

Cortex-M0+

CPS – Change Processor State

CPSID i ; Disable all interrupts except NMI (set PRIMASK)
CPSIE i ; Enable interrupts (clear PRIMASK)

StackOverflow

Which variable types/sizes are atomic on STM32 microcontrollers?

And, per this link, the following is true for “basic data types implemented in ARM C and C++” (ie: on STM32):

  1. bool/_Bool is “byte-aligned” (1-byte-aligned)
  2. int8_t/uint8_t is “byte-aligned” (1-byte-aligned)
  3. int16_t/uint16_t is “halfword-aligned” (2-byte-aligned)
  4. int32_t/uint32_t is “word-aligned” (4-byte-aligned)
  5. int64_t/uint64_t is “doubleword-aligned” (8-byte-aligned) <-- NOT GUARANTEED ATOMIC
  6. float is “word-aligned” (4-byte-aligned)
  7. double is “doubleword-aligned” (8-byte-aligned) <-- NOT GUARANTEED ATOMIC
  8. long double is “doubleword-aligned” (8-byte-aligned) <-- NOT GUARANTEED ATOMIC
  9. all pointers are “word-aligned” (4-byte-aligned)

ARM Community

C/C++ atomic operation on ARM9 and ARM Cortex-M4
Access of 64-bit data can be interrupted on Cortex-M3/M4:

  • If a 64-bit data is accessed using LDM/STM instructions, as Jens said, the instruction can get interrupted in the middle, the processor execute the ISR and then resume the LDM/STM from where it was interrupted.
  • If the 64-bit data is accessed using LDRD/STRD instructions, the instruction can get abandoned and restart after the ISR.
  • A compiler could also use multiple LDR/STR to access a 64-bit data.

For 8-bit/16-bit/32-bit data, provided that the memory instruction generated is a single LDR/STR instruction, interrupt cannot happen in between. The external memory controller might convert 16-bit / 32-bit access into multiple transfers on the memory bus, but the processor doesn’t know this and will wait until the transfer is done before taking the interrupt.

One more thing to add: there is no 64-bit exclusive access instructions for Cortex-M4.

LDREX/STREX on the M3,M4,M7

Each exclusive access sequence (typically contains a read-modify-write) of a semaphore variable is very short. So you can have as many mutex as you like, it is just not all of them being updated at the same time.


mikrocontroller.net

STM32: LDREX/STREX vs Interruptsperre

Wenn ich also LDREX ausführe, wird der execlusive access monitor gesetzt. wenn nun ein Interrupt (Exception) kommt, wird er wieder gelöscht und STREX schlägt fehl.

The Cortex-M3 includes an exclusive access monitor, that tags the fact that the processor has executed a Load-Exclusive instruction.
The processor removes its exclusive access tag if:

  • It executes a CLREX instruction
  • It executes a Store-Exclusive instruction, regardless of whether the write succeeds.
  • An exception occurs. This means the processor can resolve semaphore conflicts between different threads.

atomic-lib für stm32
Interrupts ein-/ausschalten beim ARM cortex-M3

someNonAtomicCode();
ATOMIC_BLOCK(...)
{
    doSomeThing();
    // some comment
    doAtomicStuff();
    // another comment
    lastAtomicOperation();
}
someNonAtomicCode();
template <typename F> inline void doAtomic (F f)  {
  __disable_irq ();
  f ();
  __enable_irq ();
}
int main () {
  doAtomic ([] () {
    // ... geschützte Operationen ...
  });
}
 for( __disable_irq(), uint8_t cont = 1; cont == 1; __enable_irq(), cont = 0 )
  {
    Anweisungen ....
  }

#define ATOMIC_BLOCK() for( __disable_irq(), uint8_t __cont = 1; __cont == 1; __enable_irq(), __cont = 0 )

Die korrekte Vorgehensweise ist:

  1. Zustand der Interrupts in einer Variablen sichern
  2. Interrupt deaktivieren (einen oder alle…)
  3. Atomarer Block…
  4. Ursprünglichen Zustand der Interrupts wieder herstellen!

__disable_irq intrinsic
disable interrupts and enable interrupts if they where enabled

__istate_t  interruptstate = __get_interrupt_state();
__disable_interrupt();
// Atomarer Block…
__set_interrupt_state(interruptstate);

Variante mit extra Klasse

class IRQLocker {
  private:
    uint32_t m;
  public:
    inline IRQLocker () { m = __get_PRIMASK (); __disable_irq (); }
    inline ~IRQLocker () { if (m == 0) __enable_irq (); }
};
template <typename F>
inline void doAtomic (F f) {
  IRQLocker l;
  f ();
}
void test1 () {
  doAtomic ([] () {
    /* tu was atomisches */
  });
}
void test2 () {
  {
    IRQLocker l;
    /* tu was atomisches */
  } // bei der Schließenden Klammer erfolgt das entsperren
}

Da ist ein __disable_interrupt()…. deterministischer. Was ist eure Erfahrung?

bool ATOMIC_int32Add(int32_t *var, int32_t off)
{
  int32_t tempVal;
  int32_t lockedOut;
  do
  {
    tempVal = (int32_t) __LDREX((unsigned long *)var); 
    tempVal += off;
    lockedOut = __STREX(tempVal,(unsigned long *)var); 
  }
  while ( lockedOut ); // lockedOut: 0==Success, 1==instruction is locked out
  __DMB(10);  // recommended by arm -> make sure every memory access is done
  return true;
}

Sehr deterministisch und im Fall von DMA auch sehr sinnlos. Gegen DMA hilft die Abschaltung von Interrupts überhaupt nicht. Bei mehreren Cores sieht es ähnlich aus.

Wenn man die Sorge hat, in diese Falle laufen zu können, dann kann man solche Spinlocks auch ent-determinisieren, indem das Verhalten (Timing) abhängig von einem Durchlaufzähler variiert.