Class OpenSkyhawk::ShiftBus
ClassList > OpenSkyhawk > ShiftBus
One shared SPI shift-register bus ('165 inputs + '595 outputs). More...
#include <ShiftBus.h>
Public Static Attributes
| Type | Name |
|---|---|
| constexpr uint8_t | MAX_CHAIN = 8chips per direction (64 in + 64 out) |
| constexpr uint8_t | MAX_ISR_CONSUMERS = 16sampled encoders per bus |
Public Functions
| Type | Name |
|---|---|
| ShiftBus (SPIClass & spi, uint8_t sckPin, uint8_t misoPin, uint8_t mosiPin, uint8_t loadPin, uint8_t latchPin) Construct a bus. No hardware activity — begin() runs inPanelGroup::setup() . |
|
| bool | active () const Any SR pin configured on this bus? Dormant buses skip begin() entirely. |
| void | addIsrConsumer (void(*)(void *ctx) hook, void * ctx) Register a hook called from the sampling ISR after each transfer() . Used byRotaryEncoder::configure() to auto-attach SR-pinned encoders. |
| void | begin () Claim pins + start SPI. Called by PanelGroup::setup() for active buses only. |
| void | beginIsrSampling (TIM_TypeDef * tim, uint16_t sampleHz) Start a hardware timer that runs transfer() + all registered consumer hooks every tick. Called byPanelGroup::setup() when SHIFTBUS_ISR_HZ is defined. |
| bool | dirty () const Pending output changes not yet shifted? |
| void | flushNow () transfer() immediately —StepperMotor 's per-step flush path. |
| bool | isrActive () const True once beginIsrSampling() has started the timer. |
| void | noteInput (uint8_t chip) configureAsInput() hook: mark active, grow the '165 chain to cover chip . |
| void | noteOutput (uint8_t chip) configureAsOutput() hook: mark active, grow the '595 chain to cover chip . |
| bool | readBit (uint8_t chip, uint8_t bit) const Cached '165 input bit — no bus traffic. |
| bool | readLiveBit (uint8_t chip, uint8_t bit) Live '165 read — one transfer() , then the cached bit. |
| bool | readOutBit (uint8_t chip, uint8_t bit) const Last written '595 output bit ( PinRef::read() on an output pin). |
| void | transfer () One bus transaction: LOAD pulse → full-duplex SPI of the auto-sized frame (outputs written, inputs captured) → LATCH pulse. Clears the dirty flag. |
| void | writeBit (uint8_t chip, uint8_t bit, bool v) Set a '595 stage bit + mark the stage dirty. Published by the next loop-context transfer() /flushNow() (commit), never mid-group by the sampling ISR. |
Detailed Description
Constructor stores parameters only — no SPI, no GPIO, no cross-global calls (static-init safe; the PIN_NC lesson). All hardware work happens in begin(), called by PanelGroup::setup() for buses that have at least one configured SR pin.
Public Static Attributes Documentation
variable MAX_CHAIN
chips per direction (64 in + 64 out)
constexpr uint8_t OpenSkyhawk::ShiftBus::MAX_CHAIN;
variable MAX_ISR_CONSUMERS
sampled encoders per bus
constexpr uint8_t OpenSkyhawk::ShiftBus::MAX_ISR_CONSUMERS;
Public Functions Documentation
function ShiftBus
Construct a bus. No hardware activity — begin() runs inPanelGroup::setup() .
OpenSkyhawk::ShiftBus::ShiftBus (
SPIClass & spi,
uint8_t sckPin,
uint8_t misoPin,
uint8_t mosiPin,
uint8_t loadPin,
uint8_t latchPin
)
Parameters:
spiSPI peripheral. Dedicated to this bus — the '165 QH output is never tristated, so MISO cannot be shared with another SPI reader.sckPinSPI clock pin (must belong tospi— e.g. PB3 for SPI1-remap).misoPinSPI MISO pin (← '165 QH).mosiPinSPI MOSI pin (→ '595 DS).loadPin'165 SH/LD̄ strobe (idles HIGH; pulsed LOW to capture inputs).latchPin'595 STCP strobe (pulsed HIGH to publish outputs).
function active
Any SR pin configured on this bus? Dormant buses skip begin() entirely.
inline bool OpenSkyhawk::ShiftBus::active () const
function addIsrConsumer
Register a hook called from the sampling ISR after each transfer() . Used byRotaryEncoder::configure() to auto-attach SR-pinned encoders.
void OpenSkyhawk::ShiftBus::addIsrConsumer (
void(*)(void *ctx) hook,
void * ctx
)
function begin
Claim pins + start SPI. Called by PanelGroup::setup() for active buses only.
void OpenSkyhawk::ShiftBus::begin ()
Releases JTAG (SWJ → SWD-only; PB3/PB4 are JTDO/NJTRST) so the SPI1-remap pins are usable, configures LOAD/LATCH strobes, starts SPI, shifts an all-zeros output frame * latch (defined '595 state as early as possible), then runs one transfer() to prime the input cache before the forceReport() boot burst reads it.
function beginIsrSampling
Start a hardware timer that runs transfer() + all registered consumer hooks every tick. Called byPanelGroup::setup() when SHIFTBUS_ISR_HZ is defined.
void OpenSkyhawk::ShiftBus::beginIsrSampling (
TIM_TypeDef * tim,
uint16_t sampleHz
)
Parameters:
timTimer instance (TIM2 by default — TIM3 is backlight PWM).sampleHzSample rate (e.g. 1000).
Note:
The ISR performs no CAN, no I2C, no allocation. Consumers read cached bits only.
function dirty
Pending output changes not yet shifted?
inline bool OpenSkyhawk::ShiftBus::dirty () const
function flushNow
transfer() immediately —StepperMotor 's per-step flush path.
inline void OpenSkyhawk::ShiftBus::flushNow ()
function isrActive
True once beginIsrSampling() has started the timer.
inline bool OpenSkyhawk::ShiftBus::isrActive () const
function noteInput
configureAsInput() hook: mark active, grow the '165 chain to cover chip .
void OpenSkyhawk::ShiftBus::noteInput (
uint8_t chip
)
function noteOutput
configureAsOutput() hook: mark active, grow the '595 chain to cover chip .
void OpenSkyhawk::ShiftBus::noteOutput (
uint8_t chip
)
function readBit
Cached '165 input bit — no bus traffic.
bool OpenSkyhawk::ShiftBus::readBit (
uint8_t chip,
uint8_t bit
) const
Note:
With ISR sampling active, a multi-bit consumer reading bit-by-bit can see two sample instants mixed within one poll (the ISR replaces the whole frame between reads). Debounced/hold-last consumers (MultiPosInput) absorb this; do not add an unfiltered multi-bit consumer without considering it.
function readLiveBit
Live '165 read — one transfer() , then the cached bit.
bool OpenSkyhawk::ShiftBus::readLiveBit (
uint8_t chip,
uint8_t bit
)
function readOutBit
Last written '595 output bit ( PinRef::read() on an output pin).
bool OpenSkyhawk::ShiftBus::readOutBit (
uint8_t chip,
uint8_t bit
) const
function transfer
One bus transaction: LOAD pulse → full-duplex SPI of the auto-sized frame (outputs written, inputs captured) → LATCH pulse. Clears the dirty flag.
void OpenSkyhawk::ShiftBus::transfer ()
When ISR sampling is active, loop-context callers are wrapped in a short interrupt-masked critical section so the frame buffers stay single-owner.
function writeBit
Set a '595 stage bit + mark the stage dirty. Published by the next loop-context transfer() /flushNow() (commit), never mid-group by the sampling ISR.
void OpenSkyhawk::ShiftBus::writeBit (
uint8_t chip,
uint8_t bit,
bool v
)
Writes land in a loop-owned stage frame; the ISR ships only the last committed frame. A multi-pin group (StepperMotor's four coils) therefore always reaches the '595 outputs as one atomic pattern, regardless of ISR timing between the writes.
The documentation for this class was generated from the following file Firmware/Libraries/PanelGroup/Helpers/ShiftBus/ShiftBus.h