You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.9 KiB
C
150 lines
4.9 KiB
C
1 year ago
|
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
||
|
// Copyright (C) 2013 Henner Zeller <h.zeller@acm.org>
|
||
|
//
|
||
|
// This program is free software; you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU General Public License as published by
|
||
|
// the Free Software Foundation version 2.
|
||
|
//
|
||
|
// This program is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License
|
||
|
// along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>
|
||
|
|
||
|
#ifndef RPI_GPIO_INTERNAL_H
|
||
|
#define RPI_GPIO_INTERNAL_H
|
||
|
|
||
|
#include "gpio-bits.h"
|
||
|
|
||
|
#include <vector>
|
||
|
|
||
|
// Putting this in our namespace to not collide with other things called like
|
||
|
// this.
|
||
|
namespace rgb_matrix {
|
||
|
// For now, everything is initialized as output.
|
||
|
class GPIO {
|
||
|
public:
|
||
|
GPIO();
|
||
|
|
||
|
// Initialize before use. Returns 'true' if successful, 'false' otherwise
|
||
|
// (e.g. due to a permission problem).
|
||
|
bool Init(int slowdown);
|
||
|
|
||
|
// Initialize outputs.
|
||
|
// 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);
|
||
|
|
||
|
// Request given bitmap of GPIO inputs.
|
||
|
// Returns the bits that were available and could be reserved.
|
||
|
gpio_bits_t RequestInputs(gpio_bits_t inputs);
|
||
|
|
||
|
// Set the bits that are '1' in the output. Leave the rest untouched.
|
||
|
inline void SetBits(gpio_bits_t value) {
|
||
|
if (!value) return;
|
||
|
WriteSetBits(value);
|
||
|
for (int i = 0; i < slowdown_; ++i) {
|
||
|
WriteSetBits(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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);
|
||
|
}
|
||
|
|
||
|
inline gpio_bits_t Read() const { return ReadRegisters() & input_bits_; }
|
||
|
|
||
|
// Return if this is appears to be a Pi4
|
||
|
static bool IsPi4();
|
||
|
|
||
|
private:
|
||
|
inline gpio_bits_t ReadRegisters() const {
|
||
|
return (static_cast<gpio_bits_t>(*gpio_read_bits_low_)
|
||
|
#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 (uses_64_bit_)
|
||
|
*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 (uses_64_bit_)
|
||
|
*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_;
|
||
|
|
||
|
volatile uint32_t *gpio_set_bits_low_;
|
||
|
volatile uint32_t *gpio_clr_bits_low_;
|
||
|
volatile uint32_t *gpio_read_bits_low_;
|
||
|
|
||
|
#ifdef ENABLE_WIDE_GPIO_COMPUTE_MODULE
|
||
|
bool uses_64_bit_;
|
||
|
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
|
||
|
// implementations.
|
||
|
class PinPulser {
|
||
|
public:
|
||
|
// Factory for a PinPulser. Chooses the right implementation depending
|
||
|
// on the context (CPU and which pins are affected).
|
||
|
// "gpio_mask" is the mask that should be output (since we only
|
||
|
// need negative pulses, this is what it does)
|
||
|
// "nano_wait_spec" contains a list of time periods we'd like
|
||
|
// invoke later. This can be used to pre-process timings if needed.
|
||
|
static PinPulser *Create(GPIO *io, gpio_bits_t gpio_mask,
|
||
|
bool allow_hardware_pulsing,
|
||
|
const std::vector<int> &nano_wait_spec);
|
||
|
|
||
|
virtual ~PinPulser() {}
|
||
|
|
||
|
// Send a pulse with a given length (index into nano_wait_spec array).
|
||
|
virtual void SendPulse(int time_spec_number) = 0;
|
||
|
|
||
|
// If SendPulse() is asynchronously implemented, wait for pulse to finish.
|
||
|
virtual void WaitPulseFinished() {}
|
||
|
};
|
||
|
|
||
|
// Get rolling over microsecond counter. We get this from a hardware register
|
||
|
// if possible and a terrible slow fallback otherwise.
|
||
|
uint32_t GetMicrosecondCounter();
|
||
|
|
||
|
} // end namespace rgb_matrix
|
||
|
|
||
|
#endif // RPI_GPIO_INGERNALH
|