From 66a6ae41d4eca53cc933398f955263e775ee37a6 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Mon, 19 Jun 2023 10:01:55 -0700 Subject: [PATCH] Mbi6033 (#719) * two wire protocol * due to unique reset using clock pin, supports bit bang only methods. --- src/internal/NeoMethods.h | 1 + src/internal/methods/Mbi6033GenericMethod.h | 207 ++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 src/internal/methods/Mbi6033GenericMethod.h diff --git a/src/internal/NeoMethods.h b/src/internal/NeoMethods.h index d60260f..27ac2bc 100644 --- a/src/internal/NeoMethods.h +++ b/src/internal/NeoMethods.h @@ -35,6 +35,7 @@ License along with NeoPixel. If not, see #include "methods/P9813GenericMethod.h" #include "methods/Tlc5947GenericMethod.h" #include "methods/Sm16716GenericMethod.h" +#include "methods/Mbi6033GenericMethod.h" // Platform specific and One Wire (data) methods // diff --git a/src/internal/methods/Mbi6033GenericMethod.h b/src/internal/methods/Mbi6033GenericMethod.h new file mode 100644 index 0000000..5b113ae --- /dev/null +++ b/src/internal/methods/Mbi6033GenericMethod.h @@ -0,0 +1,207 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Mbi6033s using general Pins. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set +#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__) +#include "TwoWireBitBangImpleAvr.h" +#else +#include "TwoWireBitBangImple.h" +#endif + + +template class Mbi6033MethodBase +{ +public: + typedef typename T_TWOWIRE::SettingsObject SettingsObject; + + Mbi6033MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _countChips(NeoUtil::RoundUp(pixelCount * elementSize, c_countBytesPerChip) / c_countBytesPerChip), + _sizeData(_countChips * c_countBytesPerChip + settingsSize), + _pinClock(pinClock), + _wire(pinClock, pinData) + { + _data = static_cast(malloc(_sizeData)); + // data cleared later in Begin() + } + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) + Mbi6033MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + Mbi6033MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize) + { + } +#endif + + ~Mbi6033MethodBase() + { + free(_data); + } + + bool IsReadyToUpdate() const + { + return true; // clock driven chips don't have a required delay + } + +#if defined(ARDUINO_ARCH_ESP32) + void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _pinClock = sck; + _wire.begin(sck, miso, mosi, ss); + } +#endif + + void Initialize() + { + _wire.begin(); + } + + void Update(bool) + { + // non current header format: + // 8 bits: command (0xf3) = non current header mode + // 14 bits: sync (0x0000) + // 14 bits: length (count chips - 1) + // 8 bits: configuration (0x02) + // bits (6-4) refresh rate divider bits (0 for fastest) + // bit (1) on or off + // 4 bits: header code name X1 (0x0) + const uint16_t chipLength = _countChips - 1; + const uint8_t headerFrame[6] = { 0xf3, + 0x00, + static_cast(chipLength >> 12), + static_cast((chipLength >> 4) & 0xff), + static_cast((chipLength << 4) & 0xff), + 0x20 }; + + // prefix protocol, >21us clock low, clock high, >21us clock low + // expecting at least 21us since last call to show + // but using hardware SPI won't allow messing with clock + // directly like this... + //delayMicroseconds(c_usResetTime); + //digitalWrite(_pinClock, HIGH); + //digitalWrite(_pinClock, LOW); + //delayMicroseconds(c_usResetTime); + + _wire.beginTransaction(); + + // reset by toggle of clock + delayMicroseconds(c_usResetTime); + _wire.transmitBit(0); // Our Two Wire BitBang supports this + delayMicroseconds(c_usResetTime); + + // header frame + _wire.transmitBytes(headerFrame, sizeof(headerFrame)); + + // data: + // 24 bytes per chip of data (12 16 bit values) + _wire.transmitBytes(_data, _sizeData); + + _wire.endTransaction(); + } + + bool AlwaysUpdate() + { + // this method requires update to be called only if changes to buffer + return false; + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + + void applySettings([[maybe_unused]] const SettingsObject& settings) + { + _wire.applySettings(settings); + } + +private: + // while spec states 4 RGB * 16 bit values, + // its really 12 channels * 16 bit values, as they could + // be wired how ever the circuit is built, like 3 RGBW + static const uint16_t c_countBytesPerChip = 24; // twelve 16 bit values + static const uint16_t c_usResetTime = 21; + + const uint16_t _countChips; // not pixels, driver chips + const size_t _sizeData; // Size of '_data' buffer below + + uint8_t _pinClock; + T_TWOWIRE _wire; + uint8_t* _data; // Holds LED color values +}; + +typedef Mbi6033MethodBase Mbi6033Method; + +/* Due to reset model by these chips needing to control clock, we can't use hardware SPI +* as neither the normal SPI exposes a single bit send nor does it allow direct clock pulses +* using digitalWrite. If a generalized solution could be found, then this could be enabled +* +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) +#include "TwoWireSpiImple.h" +typedef Mbi6033MethodBase> Mbi6033Spi40MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Spi20MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Spi10MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Spi5MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Spi2MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Spi1MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Spi500KhzMethod; +typedef Mbi6033MethodBase> Mbi6033SpiHzMethod; + +typedef Mbi6033Spi10MhzMethod Mbi6033SpiMethod; +#endif + +#if defined(ARDUINO_ARCH_ESP32) +// Give option to use Vspi alias of Spi class if wanting to specify which SPI peripheral is used on the ESP32 +typedef Mbi6033MethodBase> Mbi6033Esp32Vspi40MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Vspi20MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Vspi10MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Vspi5MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Vspi2MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Vspi1MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Vspi500KhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32VspiHzMethod; + +typedef Mbi6033Spi10MhzMethod Mbi6033Esp32VspiMethod; + +#include "TwoWireHspiImple.h" +typedef Mbi6033MethodBase> Mbi6033Esp32Hspi40MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Hspi20MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Hspi10MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Hspi5MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Hspi2MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Hspi1MhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32Hspi500KhzMethod; +typedef Mbi6033MethodBase> Mbi6033Esp32HspiHzMethod; + +typedef Mbi6033Esp32Hspi10MhzMethod Mbi6033Esp32HspiMethod; +#endif +*/ \ No newline at end of file