From 4edddfa4aa5996ea2e313a853b0398cb924eb06b Mon Sep 17 00:00:00 2001 From: Petr Ledvina Date: Thu, 10 Nov 2022 14:53:06 +0000 Subject: [PATCH] improved GPIO slowdown --led-slowdonw-gpio x x > 0 - use dummy writes after seting GPIO c == -1 - use `dsb st` to force AXI synchronization --- examples-api-use/minimal-example.cc | 2 +- lib/gpio.h | 27 +++++++++++++++++++-------- lib/led-matrix.cc | 4 +++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/examples-api-use/minimal-example.cc b/examples-api-use/minimal-example.cc index 840e394d2..31f665cad 100644 --- a/examples-api-use/minimal-example.cc +++ b/examples-api-use/minimal-example.cc @@ -33,7 +33,7 @@ static void DrawOnCanvas(Canvas *canvas) { float angle_step = 1.0 / 360; for (float a = 0, r = 0; r < radius_max; a += angle_step, r += angle_step) { if (interrupt_received) - return; + return; float dot_x = cos(a * 2 * M_PI) * r; float dot_y = sin(a * 2 * M_PI) * r; canvas->SetPixel(center_x + dot_x, center_y + dot_y, diff --git a/lib/gpio.h b/lib/gpio.h index 2114b1834..00ccc28e4 100644 --- a/lib/gpio.h +++ b/lib/gpio.h @@ -47,26 +47,23 @@ class GPIO { inline void SetBits(gpio_bits_t value) { if (!value) return; WriteSetBits(value); - for (int i = 0; i < slowdown_; ++i) { - WriteSetBits(value); - } + delay(); } // Clear the bits that are '1' in the output. Leave the rest untouched. inline void ClearBits(gpio_bits_t value) { if (!value) return; WriteClrBits(value); - for (int i = 0; i < slowdown_; ++i) { - WriteClrBits(value); - } + delay(); } // Write all the bits of "value" mentioned in "mask". Leave the rest untouched. inline void WriteMaskedBits(gpio_bits_t value, gpio_bits_t mask) { // Writing a word is two operations. The IO is actually pretty slow, so // this should probably be unnoticable. - ClearBits(~value & mask); - SetBits(value & mask); + WriteClrBits(~value & mask); + WriteSetBits(value & mask); + delay(); } inline gpio_bits_t Read() const { return ReadRegisters() & input_bits_; } @@ -75,6 +72,20 @@ class GPIO { static bool IsPi4(); private: + inline void delay() const { + switch(slowdown_) { + case -1: +#if __ARM_ARCH >= 7 + asm volatile("dsb\tst"); +#endif + break; + case 0: + break; + default: + for (int n = 0; n < slowdown_; n++) + *gpio_clr_bits_low_ = 0; + } + } inline gpio_bits_t ReadRegisters() const { return (static_cast(*gpio_read_bits_low_) #ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE diff --git a/lib/led-matrix.cc b/lib/led-matrix.cc index abc830751..0812db0e7 100644 --- a/lib/led-matrix.cc +++ b/lib/led-matrix.cc @@ -618,7 +618,9 @@ RGBMatrix *RGBMatrix::CreateFromOptions(const RGBMatrix::Options &options, } // For the Pi4, we might need 2, maybe up to 4. Let's open up to 5. - if (runtime_options.gpio_slowdown < 0 || runtime_options.gpio_slowdown > 5) { + // on supproted architectures, -1 will emit memory barier (DSB ST) after GPIO write + if (runtime_options.gpio_slowdown < (__ARM_ARCH >= 7 ? -1 : 0) + || runtime_options.gpio_slowdown > 5) { fprintf(stderr, "--led-slowdown-gpio=%d is outside usable range\n", runtime_options.gpio_slowdown); return NULL;