Skip to content

Commit

Permalink
SPI interface as template and constructor argument
Browse files Browse the repository at this point in the history
For SPIShiftRegisterOut and MAX7219 classes
  • Loading branch information
tttapa committed Feb 7, 2021
1 parent 27143c7 commit a81bd19
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ using namespace ExtIO; // Bring the ExtIO pin functions into your sketch

// Instantiate a shift register with the SPI slave select pin as latch pin, most
// significant bit first, and a total of 8 outputs.
SPIShiftRegisterOut<8> sreg = {SS, MSBFIRST};
SPIShiftRegisterOut<8> sreg = {SPI, SS, MSBFIRST};

const pin_t ledPin = sreg.pin(0); // first pin of the shift register

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const uint8_t ShiftRegisterOutRGB::blueBit = 2;
// Create a new shift register output connected to pins 11, 13 and 10,
// shift the data out with the most significant bit first.
// There are 24 (= 3×8) outputs in total.
SPIShiftRegisterOut<24> sreg = {SS, MSBFIRST};
SPIShiftRegisterOut<24> sreg = {SPI, SS, MSBFIRST};

void setup() {
// Initialize the shift registers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ using namespace ExtIO; // Bring the ExtIO pin functions into your sketch
// Instantiate a MAX7219 with the SPI slave select pin as latch pin
// There's just 1 MAX7219 in the chain, if you have more of them daisy-chained
// together, you can increase the template argument (between angled brackets)
MAX7219<1> max7219 = SS;
MAX7219<1> max7219 = {SPI, SS};

const pin_t ledPin1 = max7219.pin(0); // first LED of the MAX7219
const pin_t ledPin2 = max7219.pin(63); // last LED of the MAX7219
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ CD74HC4067 mux = {

// Instantiate a shift register with the SPI slave select pin as latch pin, most
// significant bit first, and a total of 16 outputs.
SPIShiftRegisterOut<mux.length()> sreg = {SS, MSBFIRST};
SPIShiftRegisterOut<mux.length()> sreg = {SPI, SS, MSBFIRST};

// Instantiate an array of momentary push buttons.
// It generates an array of Buttons on pins:
Expand Down
18 changes: 17 additions & 1 deletion mock/Core-Libraries/SPI.h
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
// TODO
#include <AH/Hardware/Arduino-Hardware-Types.hpp>

// TODO
class SPIClass {
} extern SPI;

enum SPIMode {
SPI_MODE0 = 0,
SPI_MODE1 = 1,
SPI_MODE2 = 2,
SPI_MODE3 = 3,
};

class SPISettings {
public:
SPISettings(uint32_t, BitOrder_t, SPIMode) {}
};
16 changes: 11 additions & 5 deletions src/AH/Hardware/ExtendedInputOutput/MAX7219.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,24 @@ BEGIN_AH_NAMESPACE
*
* @tparam NumChips
* The number of daisy-chained MAX7219 chips.
* @tparam SPIDriver
* The SPI class to use. Usually, the default is fine.
*/
template <uint8_t NumChips = 1>
class MAX7219 : public MAX7219_Base,
template <uint8_t NumChips = 1, class SPIDriver = decltype(SPI) &>
class MAX7219 : public MAX7219_Base<SPIDriver>,
public StaticSizeExtendedIOElement<8 * 8 * NumChips> {
public:
/**
* @brief Create a MAX7219 ExtendedIOElement.
*
* @param spi
* The SPI interface to use.
* @param loadPin
* The pin connected to the load pin (C̄S̄) of the MAX7219.
*/
MAX7219(pin_t loadPin) : MAX7219_Base(loadPin, NumChips) {}
MAX7219(SPIDriver spi, pin_t loadPin)
: MAX7219_Base<SPIDriver>(std::forward<SPIDriver>(spi), loadPin,
NumChips) {}

/// Initialize.
/// @see MAX7219#init
Expand Down Expand Up @@ -176,7 +182,7 @@ class MAX7219 : public MAX7219_Base,
}

void updateBufferedOutputRow(IndexMask i) {
sendRowAll(i.rowgrp, buffer.data + i.rowgrp, 8);
this->sendRowAll(i.rowgrp, buffer.data + i.rowgrp, 8);
dirty_rows &= ~i.rowmask;
}

Expand All @@ -187,7 +193,7 @@ class MAX7219 : public MAX7219_Base,
do {
--row;
if (dirty_rows & 0x80)
sendRowAll(row, buffer.data + row, 8);
this->sendRowAll(row, buffer.data + row, 8);
dirty_rows <<= 1;
} while (row);
}
Expand Down
14 changes: 12 additions & 2 deletions src/AH/Hardware/ExtendedInputOutput/SPIShiftRegisterOut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ AH_DIAGNOSTIC_WERROR() // Enable errors on warnings

AH_DIAGNOSTIC_EXTERNAL_HEADER()
#include <AH/Arduino-Wrapper.h> // MSBFIRST, SS
#include <SPI.h>
AH_DIAGNOSTIC_POP()

BEGIN_AH_NAMESPACE
Expand All @@ -22,10 +23,12 @@ BEGIN_AH_NAMESPACE
* The number of bits in total. Usually, shift registers (e.g. the
* 74HC595) have eight bits per chip, so `length = 8 * k` where `k`
* is the number of cascaded chips.
* @tparam SPIDriver
* The SPI class to use. Usually, the default is fine.
*
* @ingroup AH_ExtIO
*/
template <uint8_t N>
template <uint8_t N, class SPIDriver = decltype(SPI) &>
class SPIShiftRegisterOut : public ShiftRegisterOutBase<N> {
public:
/**
Expand All @@ -52,7 +55,8 @@ class SPIShiftRegisterOut : public ShiftRegisterOutBase<N> {
* Either `MSBFIRST` (most significant bit first) or `LSBFIRST`
* (least significant bit first).
*/
SPIShiftRegisterOut(pin_t latchPin = SS, BitOrder_t bitOrder = MSBFIRST);
SPIShiftRegisterOut(SPIDriver spi, pin_t latchPin = SS,
BitOrder_t bitOrder = MSBFIRST);

/**
* @brief Initialize the shift register.
Expand All @@ -65,6 +69,12 @@ class SPIShiftRegisterOut : public ShiftRegisterOutBase<N> {
* @brief Write the state buffer to the physical outputs.
*/
void updateBufferedOutputs() override;

private:
SPIDriver spi;

public:
SPISettings settings{SPI_MAX_SPEED, this->bitOrder, SPI_MODE0};
};

END_AH_NAMESPACE
Expand Down
30 changes: 16 additions & 14 deletions src/AH/Hardware/ExtendedInputOutput/SPIShiftRegisterOut.ipp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifdef ARDUINO // I'm too lazy to mock the SPI library
#ifdef ARDUINO // TODO: I'm too lazy to mock the SPI library

#include "ExtendedInputOutput.hpp"
#include "SPIShiftRegisterOut.hpp"
Expand All @@ -9,33 +9,35 @@ AH_DIAGNOSTIC_POP()

BEGIN_AH_NAMESPACE

template <uint8_t N>
SPIShiftRegisterOut<N>::SPIShiftRegisterOut(pin_t latchPin, BitOrder_t bitOrder)
: ShiftRegisterOutBase<N>(latchPin, bitOrder) {}
template <uint8_t N, class SPIDriver>
SPIShiftRegisterOut<N, SPIDriver>::SPIShiftRegisterOut(SPIDriver spi,
pin_t latchPin,
BitOrder_t bitOrder)
: ShiftRegisterOutBase<N>(latchPin, bitOrder),
spi(std::forward<SPIDriver>(spi)) {}

template <uint8_t N>
void SPIShiftRegisterOut<N>::begin() {
template <uint8_t N, class SPIDriver>
void SPIShiftRegisterOut<N, SPIDriver>::begin() {
ExtIO::pinMode(this->latchPin, OUTPUT);
SPI.begin();
spi.begin();
updateBufferedOutputs();
}

template <uint8_t N>
void SPIShiftRegisterOut<N>::updateBufferedOutputs() {
template <uint8_t N, class SPIDriver>
void SPIShiftRegisterOut<N, SPIDriver>::updateBufferedOutputs() {
if (!this->dirty)
return;
SPISettings settings = {SPI_MAX_SPEED, this->bitOrder, SPI_MODE0};
SPI.beginTransaction(settings);
spi.beginTransaction(settings);
ExtIO::digitalWrite(this->latchPin, LOW);
const uint8_t bufferLength = this->buffer.getBufferLength();
if (this->bitOrder == LSBFIRST)
for (uint8_t i = 0; i < bufferLength; i++)
SPI.transfer(this->buffer.getByte(i));
spi.transfer(this->buffer.getByte(i));
else
for (int8_t i = bufferLength - 1; i >= 0; i--)
SPI.transfer(this->buffer.getByte(i));
spi.transfer(this->buffer.getByte(i));
ExtIO::digitalWrite(this->latchPin, HIGH);
SPI.endTransaction();
spi.endTransaction();
this->dirty = false;
}

Expand Down
16 changes: 12 additions & 4 deletions src/AH/Hardware/LEDs/MAX7219SevenSegmentDisplay.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,28 @@ static constexpr const uint8_t *NumericChars = &SevenSegmentCharacters[0x30];
/**
* @brief A class for 8-digit 7-segment displays with a MAX7219 driver.
*
* @tparam SPIDriver
* The SPI class to use. Usually, the default is fine.
*
* @ingroup AH_HardwareUtils
*/
class MAX7219SevenSegmentDisplay : public MAX7219_Base {
template <class SPIDriver = decltype(SPI) &>
class MAX7219SevenSegmentDisplay : public MAX7219_Base<SPIDriver> {
public:
/**
* @brief Create a MAX7219SevenSegmentDisplay.
*
* @param spi
* The SPI interface to use.
* @param loadPin
* The pin connected to the load pin (C̄S̄) of the MAX7219.
* @param chainlength
* The number of daisy-chained MAX7219 chips.
*/
MAX7219SevenSegmentDisplay(pin_t loadPin, uint8_t chainlength = 1)
: MAX7219_Base(loadPin, chainlength) {}
MAX7219SevenSegmentDisplay(SPIDriver spi, pin_t loadPin,
uint8_t chainlength = 1)
: MAX7219_Base<SPIDriver>(std::forward<SPIDriver>(spi), loadPin,
chainlength) {}

/// Initialize.
/// @see MAX7219#init
Expand Down Expand Up @@ -118,7 +126,7 @@ class MAX7219SevenSegmentDisplay : public MAX7219_Base {
} while (anumber && i <= endDigit);
if (number < 0 && i <= endDigit) {
sendDigit(i++, 0b00000001); // minus sign
}
}
if (anumber != 0) {
for (int16_t i = startDigit; i <= endDigit;)
sendDigit(i++, 0b00000001);
Expand Down
52 changes: 28 additions & 24 deletions src/AH/Hardware/LEDs/MAX7219_Base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ BEGIN_AH_NAMESPACE
/**
* @brief A base class for classes that control MAX7219 LED drivers.
*
* The SPI interface is used.
* @tparam SPIDriver
* The SPI class to use. Usually, the default is fine.
*
* @todo Wiring diagram for SPI connection.
*/
template <class SPIDriver = decltype(SPI) &>
class MAX7219_Base {
public:
/**
Expand All @@ -30,8 +32,9 @@ class MAX7219_Base {
* @param chainlength
* The number of daisy-chained MAX7219 chips.
*/
MAX7219_Base(pin_t loadPin, uint8_t chainlength = 1)
: loadPin(loadPin), chainlength(chainlength) {}
MAX7219_Base(SPIDriver spi, pin_t loadPin, uint8_t chainlength = 1)
: spi(std::forward<SPIDriver>(spi)), loadPin(loadPin),
chainlength(chainlength) {}

static constexpr uint8_t DECODEMODE = 9;
static constexpr uint8_t INTENSITY = 10;
Expand All @@ -46,7 +49,7 @@ class MAX7219_Base {
void init() {
ExtIO::digitalWrite(loadPin, HIGH);
ExtIO::pinMode(loadPin, OUTPUT);
SPI.begin();
spi.begin();
sendRawAll(DISPLAYTEST, 0); // Normal operation, no test mode
sendRawAll(SCANLIMIT, 7); // Scan all 8 digits
sendRawAll(DECODEMODE, 0); // Raw LED addressing
Expand Down Expand Up @@ -112,13 +115,13 @@ class MAX7219_Base {
uint8_t leading_dim = 1) {
uint8_t opcode = (digit & 0x7) + 1;
ExtIO::digitalWrite(loadPin, LOW);
SPI.beginTransaction(settings);
spi.beginTransaction(settings);
for (uint8_t i = 0; i < chainlength; ++i) {
SPI.transfer(opcode);
SPI.transfer(values[uint16_t(i) * leading_dim]);
spi.transfer(opcode);
spi.transfer(values[uint16_t(i) * leading_dim]);
}
ExtIO::digitalWrite(loadPin, HIGH);
SPI.endTransaction();
spi.endTransaction();
}

/**
Expand Down Expand Up @@ -154,13 +157,13 @@ class MAX7219_Base {
*/
void sendRawAll(uint8_t opcode, uint8_t value) {
ExtIO::digitalWrite(loadPin, LOW);
SPI.beginTransaction(settings);
spi.beginTransaction(settings);
for (uint8_t i = 0; i < chainlength; ++i) {
SPI.transfer(opcode);
SPI.transfer(value);
spi.transfer(opcode);
spi.transfer(value);
}
ExtIO::digitalWrite(loadPin, HIGH);
SPI.endTransaction();
spi.endTransaction();
}

/**
Expand All @@ -177,20 +180,20 @@ class MAX7219_Base {
if (chip >= chainlength)
return; // Should I throw an error?
ExtIO::digitalWrite(loadPin, LOW);
SPI.beginTransaction(settings);
spi.beginTransaction(settings);
uint8_t c = 0;
for (; c < chip; c++) {
SPI.transfer(0x00); // No-Op
SPI.transfer(0x00);
spi.transfer(0x00); // No-Op
spi.transfer(0x00);
}
SPI.transfer(opcode);
SPI.transfer(value);
spi.transfer(opcode);
spi.transfer(value);
for (c++; c < chainlength; c++) {
SPI.transfer(0x00); // No-Op
SPI.transfer(0x00);
spi.transfer(0x00); // No-Op
spi.transfer(0x00);
}
ExtIO::digitalWrite(loadPin, HIGH);
SPI.endTransaction();
spi.endTransaction();
}

/**
Expand Down Expand Up @@ -218,14 +221,15 @@ class MAX7219_Base {
/**
* @brief Get the number of daisy-chained chips.
*/
uint8_t getChainLength() const {
return chainlength;
}
uint8_t getChainLength() const { return chainlength; }

private:
SPIDriver spi;
pin_t loadPin;
uint8_t chainlength;
SPISettings settings = {SPI_MAX_SPEED, MSBFIRST, SPI_MODE0};

public:
SPISettings settings{SPI_MAX_SPEED, MSBFIRST, SPI_MODE0};
};

END_AH_NAMESPACE
Expand Down

0 comments on commit a81bd19

Please sign in to comment.