Skip to content

Commit

Permalink
Make it possible to switch 64 bit wide GPIO at compile time.
Browse files Browse the repository at this point in the history
This requires a follow-up step: reduce the public interface of
the GPIO class that is leaking into the user-realm that should not
need to set the compile-time defines.
  • Loading branch information
hzeller committed Aug 15, 2020
1 parent f89bd15 commit 8267b1a
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 22 deletions.
4 changes: 4 additions & 0 deletions include/gpio-bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#define RPI_GPIOBITS_H

#include <stdint.h>
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
typedef uint64_t gpio_bits_t;
#else
typedef uint32_t gpio_bits_t;
#endif

#endif
34 changes: 25 additions & 9 deletions include/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@

#include <vector>

// TODO: reduce the public interface, so that we're not depending on
// compile-time gpio-bits.h.
// All of the interface that should be needed for users is RequestInputs()
// and Read().

// Putting this in our namespace to not collide with other things called like
// this.
namespace rgb_matrix {
Expand All @@ -46,12 +51,12 @@ class GPIO {
// Returns the bits that were available and could be set for output.
// (never use the optional adafruit_hack_needed parameter, it is used
// internally to this library).
gpio_bits_t InitOutputs(gpio_bits_t outputs,
bool adafruit_hack_needed = false);
uint64_t InitOutputs(uint64_t outputs,
bool adafruit_hack_needed = false);

// Request given bitmap of GPIO inputs.
// Returns the bits that were available and could be reserved.
gpio_bits_t RequestInputs(gpio_bits_t inputs);
uint64_t RequestInputs(uint64_t inputs);

// Set the bits that are '1' in the output. Leave the rest untouched.
inline void SetBits(gpio_bits_t value) {
Expand Down Expand Up @@ -85,33 +90,44 @@ class GPIO {
private:
inline gpio_bits_t ReadRegisters() const {
return (static_cast<gpio_bits_t>(*gpio_read_bits_low_)
| (static_cast<gpio_bits_t>(*gpio_read_bits_low_) << 32));
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
| (static_cast<gpio_bits_t>(*gpio_read_bits_low_) << 32)
#endif
);
}

inline void WriteSetBits(gpio_bits_t value) {
*gpio_set_bits_low_ = static_cast<uint32_t>(value & 0xFFFFFFFF);
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
if (enable_64_)
*gpio_set_bits_high_ = static_cast<uint32_t>((value & 0xFFFFFFFF00000000ull) >> 32);
*gpio_set_bits_high_ = static_cast<uint32_t>(value >> 32);
#endif
}

inline void WriteClrBits(gpio_bits_t value) {
*gpio_clr_bits_low_ = static_cast<uint32_t>(value & 0xFFFFFFFF);
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
if (enable_64_)
*gpio_clr_bits_high_ = static_cast<uint32_t>((value & 0xFFFFFFFF00000000ull) >> 32);
*gpio_clr_bits_high_ = static_cast<uint32_t>(value >> 32);
#endif
}

private:
gpio_bits_t output_bits_;
gpio_bits_t input_bits_;
gpio_bits_t reserved_bits_;
int slowdown_;
bool enable_64_;

volatile uint32_t *gpio_set_bits_low_;
volatile uint32_t *gpio_set_bits_high_;
volatile uint32_t *gpio_clr_bits_low_;
volatile uint32_t *gpio_clr_bits_high_;
volatile uint32_t *gpio_read_bits_low_;

#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
bool enable_64_;
volatile uint32_t *gpio_set_bits_high_;
volatile uint32_t *gpio_clr_bits_high_;
volatile uint32_t *gpio_read_bits_high_;
#endif
};

// A PinPulser is a utility class that pulses a GPIO pin. There can be various
Expand Down
3 changes: 3 additions & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ HARDWARE_DESC?=regular
# Flag: --led-limit-refresh
#DEFINES+=-DFIXED_FRAME_MICROSECONDS=5000

# Enable wide 64 bit GPIO offered with the compute module
DEFINES+=-DENABLE_WIDE_GPIO_COMPUTE_MODULE

# ---- Pinout options for hardware variants; usually no change needed here ----

# Uncomment if you want to use the Adafruit HAT with stable PWM timings.
Expand Down
47 changes: 34 additions & 13 deletions lib/gpio.cc
Original file line number Diff line number Diff line change
Expand Up @@ -137,20 +137,27 @@ namespace rgb_matrix {

// support for A+/B+ and RPi2 with additional GPIO pins.
GPIO_BIT( 5) | GPIO_BIT( 6) | GPIO_BIT(12) | GPIO_BIT(13) | GPIO_BIT(16) |
GPIO_BIT(19) | GPIO_BIT(20) | GPIO_BIT(21) | GPIO_BIT(26) |
GPIO_BIT(19) | GPIO_BIT(20) | GPIO_BIT(21) | GPIO_BIT(26)

//Compute Module GPIO pins
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
|
// Compute Module GPIO pins
GPIO_BIT(28) | GPIO_BIT(29) | GPIO_BIT(30) | GPIO_BIT(31) |
GPIO_BIT(32) | GPIO_BIT(33) | GPIO_BIT(34) | GPIO_BIT(35) | GPIO_BIT(36) |
GPIO_BIT(37) | GPIO_BIT(38) | GPIO_BIT(39) | GPIO_BIT(40) | GPIO_BIT(41) |
GPIO_BIT(42) | GPIO_BIT(43) | GPIO_BIT(44) | GPIO_BIT(45)
#endif
);

GPIO::GPIO() : output_bits_(0), input_bits_(0), reserved_bits_(0),
slowdown_(1), enable_64_(false) {
slowdown_(1)
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
, enable_64_(false)
#endif
{
}

gpio_bits_t GPIO::InitOutputs(gpio_bits_t outputs,
uint64_t GPIO::InitOutputs(uint64_t outputs,
bool adafruit_pwm_transition_hack_needed) {
if (s_GPIO_registers == NULL) {
fprintf(stderr, "Attempt to init outputs but not yet Init()-ialized.\n");
Expand All @@ -177,9 +184,14 @@ gpio_bits_t GPIO::InitOutputs(gpio_bits_t outputs,

outputs &= kValidBits; // Sanitize: only bits on GPIO header allowed.
outputs &= ~(output_bits_ | input_bits_ | reserved_bits_);
for (gpio_bits_t b = 0; b <= 45; ++b) {
if ((outputs & 0xFFFFFFFF00000000) != 0)
enable_64_ = true;
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
if ((outputs & 0xFFFFFFFF00000000) != 0)
enable_64_ = true;
const int kMaxAvailableBit = 45;
#else
const int kMaxAvailableBit = 26;
#endif
for (int b = 0; b <= kMaxAvailableBit; ++b) {
if (outputs & GPIO_BIT(b)) {
INP_GPIO(b); // for writing, we first need to set as input.
OUT_GPIO(b);
Expand All @@ -189,17 +201,22 @@ gpio_bits_t GPIO::InitOutputs(gpio_bits_t outputs,
return outputs;
}

gpio_bits_t GPIO::RequestInputs(gpio_bits_t inputs) {
uint64_t GPIO::RequestInputs(uint64_t inputs) {
if (s_GPIO_registers == NULL) {
fprintf(stderr, "Attempt to init inputs but not yet Init()-ialized.\n");
return 0;
}

inputs &= kValidBits; // Sanitize: only bits on GPIO header allowed.
inputs &= ~(output_bits_ | input_bits_ | reserved_bits_);
for (gpio_bits_t b = 0; b <= 45; ++b) {
if ((inputs & 0xFFFFFFFF00000000) != 0)
enable_64_ = true;
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
if ((inputs & 0xFFFFFFFF00000000) != 0)
enable_64_ = true;
const int kMaxAvailableBit = 45;
#else
const int kMaxAvailableBit = 26;
#endif
for (int b = 0; b <= kMaxAvailableBit; ++b) {
if (inputs & GPIO_BIT(b)) {
INP_GPIO(b);
}
Expand Down Expand Up @@ -353,11 +370,15 @@ bool GPIO::Init(int slowdown) {
return false;

gpio_set_bits_low_ = s_GPIO_registers + (0x1C / sizeof(uint32_t));
gpio_set_bits_high_ = s_GPIO_registers + (0x20 / sizeof(uint32_t));
gpio_clr_bits_low_ = s_GPIO_registers + (0x28 / sizeof(uint32_t));
gpio_clr_bits_high_ = s_GPIO_registers + (0x2C / sizeof(uint32_t));
gpio_read_bits_low_ = s_GPIO_registers + (0x34 / sizeof(uint32_t));

#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
gpio_set_bits_high_ = s_GPIO_registers + (0x20 / sizeof(uint32_t));
gpio_clr_bits_high_ = s_GPIO_registers + (0x2C / sizeof(uint32_t));
gpio_read_bits_high_ = s_GPIO_registers + (0x38 / sizeof(uint32_t));
#endif

return true;
}

Expand Down
2 changes: 2 additions & 0 deletions lib/hardware-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ struct HardwareMapping matrix_hardware_mappings[] = {
.p0_b2 = GPIO_BIT(25),
},

#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
/*
* Custom pin-out for compute-module
*/
Expand Down Expand Up @@ -280,6 +281,7 @@ struct HardwareMapping matrix_hardware_mappings[] = {
.p5_g2 = GPIO_BIT(44),
.p5_b2 = GPIO_BIT(45),
},
#endif

{0}
};

0 comments on commit 8267b1a

Please sign in to comment.