Merge remote-tracking branch 'refs/remotes/rogerclarkmelbourne/master' into generic_f4
# Conflicts: # .gitignore
This commit is contained in:
commit
f1e2cba93b
|
@ -8,3 +8,4 @@ other/maple-bootloader/*~
|
|||
*.o
|
||||
tools/src/stm32flash_serial/src/parsers/parsers.a
|
||||
*.bak
|
||||
*.1
|
||||
|
|
|
@ -13,6 +13,8 @@ This repo contains, the "Hardware" files to support STM32 based boards on Arduin
|
|||
|
||||
***PRIMARY SUPPORT FORUM: http://www.stm32duino.com/***
|
||||
|
||||
***We are also on Gitter https://gitter.im/stm32duino/Lobby/***
|
||||
|
||||
##Background & Support:
|
||||
* Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs
|
||||
* **Please read the wiki (https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki) for full details**
|
||||
|
|
|
@ -341,7 +341,6 @@ void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) {
|
|||
* @see dma_attach_interrupt()
|
||||
* @see dma_enable()
|
||||
*/
|
||||
__deprecated
|
||||
void dma_setup_transfer(dma_dev *dev,
|
||||
dma_channel channel,
|
||||
__io void *peripheral_address,
|
||||
|
|
|
@ -84,7 +84,7 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Nonblocking SPI transmit.
|
||||
* @brief Blocking SPI transmit.
|
||||
* @param dev SPI port to use for transmission
|
||||
* @param buf Buffer to transmit. The sizeof buf's elements are
|
||||
* inferred from dev's data frame format (i.e., are
|
||||
|
@ -93,15 +93,21 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) {
|
|||
* @return Number of elements transmitted.
|
||||
*/
|
||||
uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) {
|
||||
uint32 txed = 0;
|
||||
uint8 byte_frame = spi_dff(dev) == SPI_DFF_8_BIT;
|
||||
while (spi_is_tx_empty(dev) && (txed < len)) {
|
||||
if (byte_frame) {
|
||||
dev->regs->DR = ((const uint8*)buf)[txed++];
|
||||
} else {
|
||||
dev->regs->DR = ((const uint16*)buf)[txed++];
|
||||
}
|
||||
}
|
||||
uint32 txed = len;
|
||||
spi_reg_map *regs = dev->regs;
|
||||
if ( spi_dff(dev) == SPI_DFF_8_BIT ) {
|
||||
const uint8 * dp8 = (const uint8*)buf;
|
||||
while ( len-- ) {
|
||||
while ( (regs->SR & SPI_SR_TXE)==0 ) ; //while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty
|
||||
regs->DR = *dp8++;
|
||||
}
|
||||
} else {
|
||||
const uint16 * dp16 = (const uint16*)buf;
|
||||
while ( len-- ) {
|
||||
while ( (regs->SR & SPI_SR_TXE)==0 ) ; //while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty
|
||||
regs->DR = *dp16++;
|
||||
}
|
||||
}
|
||||
return txed;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,9 @@ static void ifaceSetupHook(unsigned, void*);
|
|||
*/
|
||||
|
||||
#define USB_TIMEOUT 50
|
||||
#if BOARD_HAVE_SERIALUSB
|
||||
bool USBSerial::_hasBegun = false;
|
||||
#endif
|
||||
|
||||
USBSerial::USBSerial(void) {
|
||||
#if !BOARD_HAVE_SERIALUSB
|
||||
|
@ -62,7 +65,12 @@ USBSerial::USBSerial(void) {
|
|||
}
|
||||
|
||||
void USBSerial::begin(void) {
|
||||
|
||||
#if BOARD_HAVE_SERIALUSB
|
||||
if (_hasBegun)
|
||||
return;
|
||||
_hasBegun = true;
|
||||
|
||||
usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT);
|
||||
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook);
|
||||
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook);
|
||||
|
@ -75,6 +83,7 @@ void USBSerial::begin(unsigned long ignoreBaud)
|
|||
volatile unsigned long removeCompilerWarningsIgnoreBaud=ignoreBaud;
|
||||
|
||||
ignoreBaud=removeCompilerWarningsIgnoreBaud;
|
||||
begin();
|
||||
}
|
||||
void USBSerial::begin(unsigned long ignoreBaud, uint8_t ignore)
|
||||
{
|
||||
|
@ -83,13 +92,16 @@ volatile uint8_t removeCompilerWarningsIgnore=ignore;
|
|||
|
||||
ignoreBaud=removeCompilerWarningsIgnoreBaud;
|
||||
ignore=removeCompilerWarningsIgnore;
|
||||
begin();
|
||||
}
|
||||
|
||||
void USBSerial::end(void) {
|
||||
#if BOARD_HAVE_SERIALUSB
|
||||
usb_cdcacm_disable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT);
|
||||
usb_cdcacm_remove_hooks(USB_CDCACM_HOOK_RX | USB_CDCACM_HOOK_IFACE_SETUP);
|
||||
_hasBegun = false;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
size_t USBSerial::write(uint8 ch) {
|
||||
|
|
|
@ -71,6 +71,9 @@ public:
|
|||
uint8 getDTR();
|
||||
uint8 isConnected();
|
||||
uint8 pending();
|
||||
|
||||
protected:
|
||||
static bool _hasBegun;
|
||||
};
|
||||
|
||||
#ifdef SERIAL_USB
|
||||
|
|
|
@ -32,11 +32,15 @@
|
|||
|
||||
#include <libmaple/libmaple_types.h>
|
||||
#include <libmaple/delay.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
void delay(unsigned long ms) {
|
||||
uint32 start = millis();
|
||||
while (millis() - start < ms)
|
||||
;
|
||||
do
|
||||
{
|
||||
yield();
|
||||
}
|
||||
while (millis() - start < ms);
|
||||
}
|
||||
|
||||
void delayMicroseconds(uint32 us) {
|
||||
|
|
|
@ -36,7 +36,7 @@ Adafruit_ILI9341_STM::Adafruit_ILI9341_STM(int8_t cs, int8_t dc, int8_t rst) : A
|
|||
}
|
||||
|
||||
|
||||
void Adafruit_ILI9341_STM::spiwrite(uint8_t c) {
|
||||
void Adafruit_ILI9341_STM::spiwrite(uint16_t c) {
|
||||
|
||||
//Serial.print("0x"); Serial.print(c, HEX); Serial.print(", ");
|
||||
|
||||
|
@ -178,10 +178,7 @@ void Adafruit_ILI9341_STM::begin(void) {
|
|||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
#elif defined (__STM32F1__)
|
||||
SPI.begin();
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
SPI.beginTransaction(SPISettings(36000000));
|
||||
|
||||
#elif defined (__arm__)
|
||||
SPI.begin();
|
||||
|
@ -335,6 +332,7 @@ void Adafruit_ILI9341_STM::begin(void) {
|
|||
if (hwSPI) spi_begin();
|
||||
writecommand(ILI9341_DISPON); //Display on
|
||||
if (hwSPI) spi_end();
|
||||
if (hwSPI) SPI.setDataSize(SPI_CR1_DFF);
|
||||
|
||||
}
|
||||
|
||||
|
@ -345,18 +343,14 @@ void Adafruit_ILI9341_STM::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1,
|
|||
writecommand(ILI9341_CASET); // Column addr set
|
||||
*dcport |= dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
SPI.setDataSize (SPI_CR1_DFF);
|
||||
SPI.write(x0);
|
||||
SPI.write(x1);
|
||||
// SPI.setDataSize (0);
|
||||
|
||||
writecommand(ILI9341_PASET); // Row addr set
|
||||
*dcport |= dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
// SPI.setDataSize (SPI_CR1_DFF);
|
||||
SPI.write(y0);
|
||||
SPI.write(y1);
|
||||
SPI.setDataSize (0);
|
||||
|
||||
writecommand(ILI9341_RAMWR); // write to RAM
|
||||
|
||||
|
@ -385,7 +379,6 @@ void Adafruit_ILI9341_STM::pushColor(uint16_t color) {
|
|||
//digitalWrite(_cs, LOW);
|
||||
*csport &= ~cspinmask;
|
||||
|
||||
spiwrite(color >> 8);
|
||||
spiwrite(color);
|
||||
|
||||
*csport |= cspinmask;
|
||||
|
@ -403,7 +396,6 @@ void Adafruit_ILI9341_STM::drawPixel(int16_t x, int16_t y, uint16_t color) {
|
|||
*dcport |= dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
|
||||
spiwrite(color >> 8);
|
||||
spiwrite(color);
|
||||
|
||||
*csport |= cspinmask;
|
||||
|
@ -431,10 +423,8 @@ void Adafruit_ILI9341_STM::drawFastVLine(int16_t x, int16_t y, int16_t h,
|
|||
*csport &= ~cspinmask;
|
||||
|
||||
#if defined (__STM32F1__)
|
||||
SPI.setDataSize (SPI_CR1_DFF); // Set SPI 16bit mode
|
||||
lineBuffer[0] = color;
|
||||
SPI.dmaSend(lineBuffer, h, 0);
|
||||
SPI.setDataSize (0);
|
||||
#else
|
||||
uint8_t hi = color >> 8, lo = color;
|
||||
while (h--) {
|
||||
|
@ -464,10 +454,8 @@ void Adafruit_ILI9341_STM::drawFastHLine(int16_t x, int16_t y, int16_t w,
|
|||
*csport &= ~cspinmask;
|
||||
|
||||
#if defined (__STM32F1__)
|
||||
SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode
|
||||
lineBuffer[0] = color;
|
||||
SPI.dmaSend(lineBuffer, w, 0);
|
||||
SPI.setDataSize (0);
|
||||
#else
|
||||
uint8_t hi = color >> 8, lo = color;
|
||||
while (w--) {
|
||||
|
@ -485,11 +473,9 @@ void Adafruit_ILI9341_STM::fillScreen(uint16_t color) {
|
|||
setAddrWindow(0, 0, _width - 1, _height - 1);
|
||||
*dcport |= dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode
|
||||
lineBuffer[0] = color;
|
||||
SPI.dmaSend(lineBuffer, (65535), 0);
|
||||
SPI.dmaSend(lineBuffer, ((_width * _height) - 65535), 0);
|
||||
SPI.setDataSize (0);
|
||||
|
||||
#else
|
||||
fillRect(0, 0, _width, _height, color);
|
||||
|
@ -515,7 +501,6 @@ void Adafruit_ILI9341_STM::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
|
|||
*dcport |= dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
#if defined (__STM32F1__)
|
||||
SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode
|
||||
lineBuffer[0] = color;
|
||||
if (w*h <= 65535) {
|
||||
SPI.dmaSend(lineBuffer, (w*h), 0);
|
||||
|
@ -524,7 +509,6 @@ void Adafruit_ILI9341_STM::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
|
|||
SPI.dmaSend(lineBuffer, (65535), 0);
|
||||
SPI.dmaSend(lineBuffer, ((w*h) - 65535), 0);
|
||||
}
|
||||
SPI.setDataSize (0);
|
||||
#else
|
||||
uint8_t hi = color >> 8, lo = color;
|
||||
for(y=h; y>0; y--)
|
||||
|
@ -672,6 +656,7 @@ uint16_t Adafruit_ILI9341_STM::color565(uint8_t r, uint8_t g, uint8_t b) {
|
|||
void Adafruit_ILI9341_STM::setRotation(uint8_t m) {
|
||||
|
||||
if (hwSPI) spi_begin();
|
||||
if (hwSPI) SPI.setDataSize(0);
|
||||
writecommand(ILI9341_MADCTL);
|
||||
rotation = m % 4; // can't be higher than 3
|
||||
switch (rotation) {
|
||||
|
@ -696,6 +681,7 @@ void Adafruit_ILI9341_STM::setRotation(uint8_t m) {
|
|||
_height = ILI9341_TFTWIDTH;
|
||||
break;
|
||||
}
|
||||
if (hwSPI) SPI.setDataSize(SPI_CR1_DFF);
|
||||
if (hwSPI) spi_end();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ This library has been modified for the Maple Mini
|
|||
#include <Adafruit_GFX_AS.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#ifndef swap
|
||||
#define swap(a, b) { int16_t t = a; a = b; b = t; }
|
||||
#endif
|
||||
|
||||
#define ILI9341_TFTWIDTH 240
|
||||
#define ILI9341_TFTHEIGHT 320
|
||||
|
||||
|
@ -125,7 +129,7 @@ class Adafruit_ILI9341_STM : public Adafruit_GFX {
|
|||
void dummyclock(void);
|
||||
*/
|
||||
|
||||
void spiwrite(uint8_t),
|
||||
void spiwrite(uint16_t),
|
||||
writecommand(uint8_t c),
|
||||
writedata(uint8_t d),
|
||||
commandList(uint8_t *addr);
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
#include "boards.h"
|
||||
|
||||
//#include "HardwareSerial.h"
|
||||
/** Time in ms for DMA receive timeout */
|
||||
#define DMA_TIMEOUT 100
|
||||
|
||||
#if CYCLES_PER_MICROSECOND != 72
|
||||
/* TODO [0.2.0?] something smarter than this */
|
||||
|
@ -133,9 +135,8 @@ SPIClass::SPIClass(uint32 spi_num) {
|
|||
_settings[2].spiDmaDev = DMA2;
|
||||
_settings[2].spiTxDmaChannel = DMA_CH2;
|
||||
_settings[2].spiRxDmaChannel = DMA_CH1;
|
||||
#endif
|
||||
|
||||
//pinMode(BOARD_SPI_DEFAULT_SS,OUTPUT);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -158,7 +159,7 @@ void SPIClass::begin(void) {
|
|||
void SPIClass::beginSlave(void) {
|
||||
spi_init(_currentSetting->spi_d);
|
||||
configure_gpios(_currentSetting->spi_d, 0);
|
||||
uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE);
|
||||
uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_RX_ONLY);
|
||||
#ifdef SPI_DEBUG
|
||||
Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")");
|
||||
#endif
|
||||
|
@ -212,8 +213,10 @@ void SPIClass::setBitOrder(BitOrder bitOrder)
|
|||
void SPIClass::setDataSize(uint32 datasize)
|
||||
{
|
||||
_currentSetting->dataSize = datasize;
|
||||
uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_DFF);
|
||||
_currentSetting->spi_d->regs->CR1 = cr1 | (datasize & SPI_CR1_DFF);
|
||||
uint32 cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_DFF);
|
||||
uint8 en = spi_is_enabled(_currentSetting->spi_d);
|
||||
spi_peripheral_disable(_currentSetting->spi_d);
|
||||
_currentSetting->spi_d->regs->CR1 = cr1 | (datasize & SPI_CR1_DFF) | en;
|
||||
}
|
||||
|
||||
void SPIClass::setDataMode(uint8_t dataMode)
|
||||
|
@ -256,9 +259,6 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings)
|
|||
#ifdef SPI_DEBUG
|
||||
Serial.println("SPIClass::beginTransaction");
|
||||
#endif
|
||||
//_SSPin=pin;
|
||||
//pinMode(_SSPin,OUTPUT);
|
||||
//digitalWrite(_SSPin,LOW);
|
||||
setBitOrder(settings.bitOrder);
|
||||
setDataMode(settings.dataMode);
|
||||
setDataSize(settings.dataSize);
|
||||
|
@ -304,138 +304,134 @@ void SPIClass::endTransaction(void)
|
|||
* I/O
|
||||
*/
|
||||
|
||||
uint8 SPIClass::read(void) {
|
||||
uint8 buf[1];
|
||||
this->read(buf, 1);
|
||||
return buf[0];
|
||||
uint16 SPIClass::read(void)
|
||||
{
|
||||
while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ;
|
||||
return (uint16)spi_rx_reg(_currentSetting->spi_d);
|
||||
}
|
||||
|
||||
void SPIClass::read(uint8 *buf, uint32 len) {
|
||||
uint32 rxed = 0;
|
||||
while (rxed < len) {
|
||||
while (!spi_is_rx_nonempty(_currentSetting->spi_d))
|
||||
;
|
||||
buf[rxed++] = (uint8)spi_rx_reg(_currentSetting->spi_d);
|
||||
}
|
||||
void SPIClass::read(uint8 *buf, uint32 len)
|
||||
{
|
||||
if ( len == 0 ) return;
|
||||
spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it.
|
||||
spi_reg_map * regs = _currentSetting->spi_d->regs;
|
||||
// start sequence: write byte 0
|
||||
regs->DR = 0x00FF; // write the first byte
|
||||
// main loop
|
||||
while ( (--len) ) {
|
||||
while( !(regs->SR & SPI_SR_TXE) ); // wait for TXE flag
|
||||
noInterrupts(); // go atomic level - avoid interrupts to surely get the previously received data
|
||||
regs->DR = 0x00FF; // write the next data item to be transmitted into the SPI_DR register. This clears the TXE flag.
|
||||
while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the DR register
|
||||
*buf++ = (uint8)(regs->DR); // read and store the received byte. This clears the RXNE flag.
|
||||
interrupts(); // let systick do its job
|
||||
}
|
||||
// read remaining last byte
|
||||
while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the Rx register
|
||||
*buf++ = (uint8)(regs->DR); // read and store the received byte
|
||||
}
|
||||
|
||||
void SPIClass::write(uint16 data) {
|
||||
// this->write(&data, 1);
|
||||
|
||||
void SPIClass::write(uint16 data)
|
||||
{
|
||||
/* Added for 16bit data Victor Perez. Roger Clark
|
||||
* Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte)
|
||||
* The original method, of calling write(*data, length) .
|
||||
* Improved speed by just directly writing the single byte to the SPI data reg and wait for completion,
|
||||
* by taking the Tx code from transfer(byte)
|
||||
* This almost doubles the speed of this function.
|
||||
*/
|
||||
|
||||
spi_tx_reg(_currentSetting->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
|
||||
spi_tx_reg(_currentSetting->spi_d, data); // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
}
|
||||
|
||||
//void SPIClass::write(uint8 byte) {
|
||||
// this->write(&byte, 1);
|
||||
|
||||
/* Roger Clark
|
||||
* Improved speed by just directly writing the single byte to the SPI data reg and wait for completion, * by taking the Tx code from transfer(byte)
|
||||
* The original method, of calling write(*data, length) .
|
||||
* This almost doubles the speed of this function.
|
||||
*/
|
||||
|
||||
// spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
|
||||
// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
//}
|
||||
|
||||
void SPIClass::write(const uint8 *data, uint32 length) {
|
||||
uint32 txed = 0;
|
||||
while (txed < length) {
|
||||
txed += spi_tx(_currentSetting->spi_d, data + txed, length - txed);
|
||||
}
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete."
|
||||
// taken from SdSpiSTM32F1.cpp - Victor's lib, and adapted to support device selection
|
||||
if (spi_is_rx_nonempty(_currentSetting->spi_d)) {
|
||||
uint8_t b = spi_rx_reg(_currentSetting->spi_d);
|
||||
void SPIClass::write(uint16 data, uint32 n)
|
||||
{
|
||||
// Added by stevstrong: Repeatedly send same data by the specified number of times
|
||||
spi_reg_map * regs = _currentSetting->spi_d->regs;
|
||||
while ( (n--)>0 ) {
|
||||
regs->DR = data; // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)
|
||||
while ( (regs->SR & SPI_SR_TXE)==0 ) ; // wait till Tx empty
|
||||
}
|
||||
while ( (regs->SR & SPI_SR_BSY) != 0); // wait until BSY=0 before returning
|
||||
}
|
||||
|
||||
uint16_t SPIClass::transfer16(uint16_t wr_data) const {
|
||||
spi_tx_reg(_currentSetting->spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
|
||||
while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..."
|
||||
uint16_t rd_data = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
|
||||
// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
return rd_data;
|
||||
void SPIClass::write(void *data, uint32 length)
|
||||
{
|
||||
spi_dev * spi_d = _currentSetting->spi_d;
|
||||
spi_tx(spi_d, (void*)data, length); // data can be array of bytes or words
|
||||
while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
}
|
||||
|
||||
uint8 SPIClass::transfer(uint8 byte) const {
|
||||
spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
|
||||
while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..."
|
||||
uint8 b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
return b;
|
||||
uint8 SPIClass::transfer(uint8 byte) const
|
||||
{
|
||||
spi_dev * spi_d = _currentSetting->spi_d;
|
||||
spi_rx_reg(spi_d); // read any previous data
|
||||
spi_tx_reg(spi_d, byte); // Write the data item to be transmitted into the SPI_DR register
|
||||
while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
return (uint8)spi_rx_reg(spi_d); // "... and read the last received data."
|
||||
}
|
||||
|
||||
uint16_t SPIClass::transfer16(uint16_t wr_data) const
|
||||
{
|
||||
spi_dev * spi_d = _currentSetting->spi_d;
|
||||
spi_rx_reg(spi_d); // read any previous data
|
||||
spi_tx_reg(spi_d, wr_data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
|
||||
while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
return (uint16)spi_rx_reg(spi_d); // "... and read the last received data."
|
||||
}
|
||||
|
||||
/* Roger Clark and Victor Perez, 2015
|
||||
* Performs a DMA SPI transfer with at least a receive buffer.
|
||||
* If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer.
|
||||
* On exit TX buffer is not modified, and RX buffer cotains the received data.
|
||||
* If a TX buffer is not provided, FF is sent over and over for the length of the transfer.
|
||||
* On exit TX buffer is not modified, and RX buffer contains the received data.
|
||||
* Still in progress.
|
||||
*/
|
||||
uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) {
|
||||
uint8 SPIClass::dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length)
|
||||
{
|
||||
if (length == 0) return 0;
|
||||
uint8 b = 0;
|
||||
if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) b = spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
|
||||
// dma1_ch3_Active=true;
|
||||
dma_init(_currentSetting->spiDmaDev);
|
||||
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
|
||||
|
||||
|
||||
// RX
|
||||
spi_rx_dma_enable(_currentSetting->spi_d);
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
|
||||
receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA
|
||||
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
|
||||
receiveBuf, dma_bit_size, (DMA_MINC_MODE));// receive buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length);
|
||||
|
||||
// TX
|
||||
spi_tx_dma_enable(_currentSetting->spi_d);
|
||||
if (!transmitBuf) {
|
||||
static uint8_t ff = 0XFF;
|
||||
transmitBuf = &ff;
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
|
||||
transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly
|
||||
}
|
||||
else {
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
|
||||
transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA
|
||||
}
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
|
||||
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
|
||||
|
||||
// while (dma1_ch3_Active);
|
||||
// if (receiveBuf) {
|
||||
uint32_t m = millis();
|
||||
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
|
||||
if ((millis() - m) > 100) {
|
||||
// dma1_ch3_Active = 0;
|
||||
b = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
|
||||
// }
|
||||
// TX
|
||||
uint32 flags = (DMA_MINC_MODE | DMA_FROM_MEM);
|
||||
if ( transmitBuf==0 ) {
|
||||
static uint8_t ff = 0XFF;
|
||||
transmitBuf = &ff;
|
||||
flags ^= DMA_MINC_MODE; // remove increment mode
|
||||
}
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
|
||||
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
|
||||
|
||||
spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
|
||||
spi_rx_dma_enable(_currentSetting->spi_d);
|
||||
spi_tx_dma_enable(_currentSetting->spi_d); // must be the last enable to avoid DMA error flag
|
||||
|
||||
uint32_t m = millis();
|
||||
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
|
||||
//delayMicroseconds(10);
|
||||
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
|
||||
}
|
||||
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
|
||||
spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels
|
||||
spi_tx_dma_disable(_currentSetting->spi_d);
|
||||
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
|
||||
uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
|
||||
}
|
||||
spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
@ -443,63 +439,75 @@ uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length
|
|||
* Performs a DMA SPI send using a TX buffer.
|
||||
* On exit TX buffer is not modified.
|
||||
* Still in progress.
|
||||
* 2016 - stevstrong - reworked to automatically detect bit size from SPI setting
|
||||
*/
|
||||
uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) {
|
||||
uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc)
|
||||
{
|
||||
if (length == 0) return 0;
|
||||
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
|
||||
uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
|
||||
uint8 b = 0;
|
||||
// dma1_ch3_Active=true;
|
||||
dma_init(_currentSetting->spiDmaDev);
|
||||
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
|
||||
|
||||
// TX
|
||||
spi_tx_dma_enable(_currentSetting->spi_d);
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
|
||||
transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA
|
||||
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
|
||||
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
|
||||
|
||||
// while (dma1_ch3_Active);
|
||||
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set.
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
|
||||
spi_tx_dma_enable(_currentSetting->spi_d);
|
||||
|
||||
uint32_t m = millis();
|
||||
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
|
||||
//delayMicroseconds(10);
|
||||
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
|
||||
}
|
||||
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
spi_tx_dma_disable(_currentSetting->spi_d);
|
||||
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
|
||||
uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
|
||||
}
|
||||
return b;
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
return b;
|
||||
}
|
||||
|
||||
uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) {
|
||||
if (length == 0) return 0;
|
||||
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
|
||||
uint8 b;
|
||||
dma1_ch3_Active=true;
|
||||
dma_init(_currentSetting->spiDmaDev);
|
||||
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
|
||||
|
||||
// TX
|
||||
spi_tx_dma_enable(_currentSetting->spi_d);
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_16BITS,
|
||||
transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
|
||||
|
||||
// while (dma1_ch3_Active);
|
||||
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set.
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
uint8 SPIClass::dmaSendAsync(void * transmitBuf, uint16 length, bool minc)
|
||||
{
|
||||
static bool isRunning=false;
|
||||
uint8 b = 0;
|
||||
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
spi_tx_dma_disable(_currentSetting->spi_d);
|
||||
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
|
||||
b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
|
||||
if (isRunning)
|
||||
{
|
||||
|
||||
uint32_t m = millis();
|
||||
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
|
||||
//delayMicroseconds(10);
|
||||
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
|
||||
}
|
||||
|
||||
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
|
||||
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
|
||||
spi_tx_dma_disable(_currentSetting->spi_d);
|
||||
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
isRunning=false;
|
||||
}
|
||||
return b;
|
||||
|
||||
|
||||
if (length == 0) return 0;
|
||||
uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
|
||||
|
||||
dma_init(_currentSetting->spiDmaDev);
|
||||
// TX
|
||||
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
|
||||
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
|
||||
transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
|
||||
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
|
||||
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
|
||||
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
|
||||
spi_tx_dma_enable(_currentSetting->spi_d);
|
||||
|
||||
isRunning=true;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
|
@ -536,18 +544,13 @@ uint8 SPIClass::nssPin(void) {
|
|||
*/
|
||||
|
||||
uint8 SPIClass::send(uint8 data) {
|
||||
uint8 buf[] = {data};
|
||||
return this->send(buf, 1);
|
||||
this->write(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8 SPIClass::send(uint8 *buf, uint32 len) {
|
||||
uint32 txed = 0;
|
||||
uint8 ret = 0;
|
||||
while (txed < len) {
|
||||
this->write(buf[txed++]);
|
||||
ret = this->read();
|
||||
}
|
||||
return ret;
|
||||
this->write(buf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8 SPIClass::recv(void) {
|
||||
|
|
|
@ -115,6 +115,13 @@ public:
|
|||
init_MightInline(clock, bitOrder, dataMode, dataSize);
|
||||
}
|
||||
}
|
||||
SPISettings(uint32_t clock) {
|
||||
if (__builtin_constant_p(clock)) {
|
||||
init_AlwaysInline(clock, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
|
||||
} else {
|
||||
init_MightInline(clock, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
|
||||
}
|
||||
}
|
||||
SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT); }
|
||||
private:
|
||||
void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) {
|
||||
|
@ -216,40 +223,40 @@ public:
|
|||
*/
|
||||
|
||||
/**
|
||||
* @brief Return the next unread byte.
|
||||
* @brief Return the next unread byte/word.
|
||||
*
|
||||
* If there is no unread byte waiting, this function will block
|
||||
* If there is no unread byte/word waiting, this function will block
|
||||
* until one is received.
|
||||
*/
|
||||
uint8 read(void);
|
||||
uint16 read(void);
|
||||
|
||||
/**
|
||||
* @brief Read length bytes, storing them into buffer.
|
||||
* @param buffer Buffer to store received bytes into.
|
||||
* @param length Number of bytes to store in buffer. This
|
||||
* @param length Number of bytes to store in buffer. This
|
||||
* function will block until the desired number of
|
||||
* bytes have been read.
|
||||
*/
|
||||
void read(uint8 *buffer, uint32 length);
|
||||
|
||||
/**
|
||||
* @brief Transmit a byte.
|
||||
* @param data Byte to transmit.
|
||||
*/
|
||||
// void write(uint8 data);
|
||||
|
||||
/**
|
||||
* @brief Transmit a half word.
|
||||
* @brief Transmit one byte/word.
|
||||
* @param data to transmit.
|
||||
*/
|
||||
void write(uint16 data);
|
||||
|
||||
/**
|
||||
* @brief Transmit multiple bytes.
|
||||
* @param buffer Bytes to transmit.
|
||||
* @param length Number of bytes in buffer to transmit.
|
||||
* @brief Transmit one byte/word a specified number of times.
|
||||
* @param data to transmit.
|
||||
*/
|
||||
void write(const uint8 *buffer, uint32 length);
|
||||
void write(uint16 data, uint32 n);
|
||||
|
||||
/**
|
||||
* @brief Transmit multiple bytes/words.
|
||||
* @param buffer Bytes/words to transmit.
|
||||
* @param length Number of bytes/words in buffer to transmit.
|
||||
*/
|
||||
void write(void * buffer, uint32 length);
|
||||
|
||||
/**
|
||||
* @brief Transmit a byte, then return the next unread byte.
|
||||
|
@ -264,6 +271,7 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Sets up a DMA Transfer for "length" bytes.
|
||||
* The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting.
|
||||
*
|
||||
* This function transmits and receives to buffers.
|
||||
*
|
||||
|
@ -271,31 +279,19 @@ public:
|
|||
* @param receiveBuf buffer Bytes to save received data.
|
||||
* @param length Number of bytes in buffer to transmit.
|
||||
*/
|
||||
uint8 dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length);
|
||||
uint8 dmaTransfer(void * transmitBuf, void * receiveBuf, uint16 length);
|
||||
|
||||
/**
|
||||
* @brief Sets up a DMA Transmit for bytes.
|
||||
* @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode.
|
||||
* The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting.
|
||||
*
|
||||
* This function transmits and does not care about the RX fifo.
|
||||
*
|
||||
* @param transmitBuf buffer Bytes to transmit,
|
||||
* @param length Number of bytes in buffer to transmit.
|
||||
* @param minc Set to use Memory Increment mode, clear to use Circular mode.
|
||||
*/
|
||||
uint8 dmaSend(uint8 *transmitBuf, uint16 length, bool minc = 1);
|
||||
|
||||
/**
|
||||
* @brief Sets up a DMA Transmit for half words.
|
||||
* SPI PERFIPHERAL MUST BE SET TO 16 BIT MODE BEFORE
|
||||
*
|
||||
* This function transmits and does not care about the RX fifo.
|
||||
* This function only transmits and does not care about the RX fifo.
|
||||
*
|
||||
* @param data buffer half words to transmit,
|
||||
* @param length Number of bytes in buffer to transmit.
|
||||
* @param minc Set to use Memory Increment mode (default if blank), clear to use Circular mode.
|
||||
*/
|
||||
uint8 dmaSend(uint16 *transmitBuf, uint16 length, bool minc = 1);
|
||||
|
||||
uint8 dmaSend(void * transmitBuf, uint16 length, bool minc = 1);
|
||||
uint8 dmaSendAsync(void * transmitBuf, uint16 length, bool minc = 1);
|
||||
/*
|
||||
* Pin accessors
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
# WS2812B_STM32_Libmaple
|
||||
WS2812B (Neopixel) library for Arduino STM32 (Libmaple core)
|
||||
|
||||
Written by Roger Clark www.rogerclark.net, from first principals
|
||||
|
||||
This library uses SPI DMA to control a strip of WS2812B (NeoPixel) LEDS
|
||||
|
||||
It should be generally compatible with the Adafruit NeoPixel library,
|
||||
except I have not had chance to implement one or two of the lesser used functions
|
||||
|
||||
Connect Data In of the strip to SPI1 MOSI
|
||||
|
||||
This library has only been tested on the WS2812B LED. It may not work with the older WS2812 or
|
||||
other types of addressable RGB LED, becuase it relies on a division multiple of the 72Mhz clock
|
||||
frequence on the STM32 SPI to generate the correct width T0H pulse, of 400ns +/- 150nS
|
||||
SPI DIV32 gives a pulse width of 444nS which is well within spec for the WS2812B but
|
||||
is probably too long for the WS2812 which needs a 350ns pulse for T0H
|
||||
|
||||
##Technical details
|
||||
|
||||
The library uses SPI to send the mark/space encoded data to the LED's
|
||||
|
||||
Each mark/space squarewave is generated by 3 bits of data
|
||||
A pixel 0 value is achieved by sending the bit pattern 100
|
||||
A pixel 1 value is achieved by sending the bit pattern 110
|
||||
|
||||
Where the duration of each bit is 444nS
|
||||
Hence 100 generates a mark space value of 444/888nS
|
||||
and 110 generates a mark space value of 888/444nS
|
||||
|
||||
This method results in the smallest storage requirement and the fastest send times,
|
||||
however because the 8 bit pixel channel data is encoded in 24 bits, (3 bytes) the values required in each of the 3 bytes to represent
|
||||
a specific value is not easy to generate.
|
||||
|
||||
The bit pattern in the 3 bytes is
|
||||
88877766 65554443 33222111
|
||||
|
||||
For speed of operation the values reqired for each byte for each of the 256 possible values is held in 3 separate 256 byte LUTS
|
||||
which were pre-computed by this function (which generates the full 24 bit pattern for a given input value (0-255)
|
||||
|
||||
```
|
||||
uint32_t convert(uint8_t data)
|
||||
{
|
||||
uint32_t out=0;
|
||||
for(uint8_t mask = 0x80; mask; mask >>= 1)
|
||||
{
|
||||
out=out<<3;
|
||||
if (data & mask)
|
||||
{
|
||||
out = out | 0B110;//Bit high
|
||||
}
|
||||
else
|
||||
{
|
||||
out = out | 0B100;// bit low
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
```
|
||||
|
||||
The STM32F103 has plenty of flash space (either 64 or 128k), so I used 256 byte LUTs even though the number of unique values in each LUT is
|
||||
only 8,4 and 8 bytes respectively.
|
||||
However to use small LUTS requires shifting and masking of the input data, and the code was written with a preference for speed over binary size
|
||||
|
||||
The encoded pixel buffer is 2 bytes longer than the actual encoded data.
|
||||
The first and last encoded bytes are all zeros. This is because the SPI hardware seems to preload MOSI with its output value before the start
|
||||
of the DMA transfer, which causes the first encoded pulse to be around 50ns longer than the subsequent bits, (around 490 or 500ns)
|
||||
This had the effect of causing the first LED to always think the MS bit of the green channel was set to High.
|
||||
|
||||
So having the first encoded byte of zeros, is a work-around , as although the first encoded bit is still 490nS wide its a logic zero and is therefore
|
||||
not visible, becuase the default state is of the SPI when not transmitting data is logic zero
|
||||
The last byte was also set to all zeros, as occasionally MOSI seemed to be left set to logic high on completion of the SPI DMA send
|
||||
|
||||
Adding these 2 bytes does slightly slow down the transfer, as it add 444ns * 8 = just over 3.5uS to both end.
|
||||
But the WS2812B theoretically requires a reset time of more than 50uS between transmissions, so 3.5uS can be part of that time.
|
||||
In reality the WS2812B seems to only need around 6uS of reset time, so for all practical purposes, there no delays are needed at all in the
|
||||
library to enforce the reset time, as the overead of the function call and the SPI DMA setup plus the 3.5uS gives the enough reset time.
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
#include <WS2812B.h>
|
||||
|
||||
#define NUM_LEDS 30
|
||||
/*
|
||||
* Note. Library uses SPI1
|
||||
* Connect the WS2812B data input to MOSI on your board.
|
||||
*
|
||||
*/
|
||||
WS2812B strip = WS2812B(NUM_LEDS);
|
||||
// Note. Gamma is not really supported in the library, its only included as some functions used in this example require Gamma
|
||||
uint8_t LEDGamma[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
|
||||
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
|
||||
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
|
||||
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
|
||||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
|
||||
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
|
||||
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
|
||||
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
|
||||
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
|
||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
|
||||
void setup()
|
||||
{
|
||||
strip.begin();// Sets up the SPI
|
||||
strip.show();// Clears the strip, as by default the strip data is set to all LED's off.
|
||||
// strip.setBrightness(8);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
colorWipe(strip.Color(0, 255, 0), 20); // Green
|
||||
colorWipe(strip.Color(255, 0, 0), 20); // Red
|
||||
colorWipe(strip.Color(0, 0, 255), 20); // Blue
|
||||
rainbow(10);
|
||||
rainbowCycle(10);
|
||||
theaterChase(strip.Color(255, 0, 0), 20); // Red
|
||||
theaterChase(strip.Color(0, 255, 0), 20); // Green
|
||||
theaterChase(strip.Color(0, 0, 255), 20); // Blue
|
||||
theaterChaseRainbow(10);
|
||||
whiteOverRainbow(20,75,5);
|
||||
pulseWhite(5);
|
||||
delay(250);
|
||||
fullWhite();
|
||||
delay(250);
|
||||
rainbowFade2White(3,3,1);
|
||||
}
|
||||
|
||||
// Fill the dots one after the other with a color
|
||||
void colorWipe(uint32_t c, uint8_t wait)
|
||||
{
|
||||
for(uint16_t i=0; i<strip.numPixels(); i++)
|
||||
{
|
||||
strip.setPixelColor(i, c);
|
||||
strip.show();
|
||||
delay(wait);
|
||||
}
|
||||
}
|
||||
|
||||
void rainbow(uint8_t wait) {
|
||||
uint16_t i, j;
|
||||
|
||||
for(j=0; j<256; j++) {
|
||||
for(i=0; i<strip.numPixels(); i++)
|
||||
{
|
||||
strip.setPixelColor(i, Wheel((i+j) & 255));
|
||||
}
|
||||
strip.show();
|
||||
delay(wait);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Slightly different, this makes the rainbow equally distributed throughout
|
||||
void rainbowCycle(uint8_t wait)
|
||||
{
|
||||
uint16_t i, j;
|
||||
|
||||
for(j=0; j<256*5; j++)
|
||||
{ // 5 cycles of all colors on wheel
|
||||
for(i=0; i< strip.numPixels(); i++)
|
||||
{
|
||||
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
|
||||
}
|
||||
strip.show();
|
||||
delay(wait);
|
||||
}
|
||||
}
|
||||
|
||||
// Input a value 0 to 255 to get a color value.
|
||||
// The colours are a transition r - g - b - back to r.
|
||||
uint32_t Wheel(byte WheelPos)
|
||||
{
|
||||
if(WheelPos < 85)
|
||||
{
|
||||
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(WheelPos < 170)
|
||||
{
|
||||
WheelPos -= 85;
|
||||
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
WheelPos -= 170;
|
||||
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Theatre-style crawling lights.
|
||||
void theaterChase(uint32_t c, uint8_t wait) {
|
||||
for (int j=0; j<10; j++) { //do 10 cycles of chasing
|
||||
for (int q=0; q < 3; q++) {
|
||||
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
|
||||
strip.setPixelColor(i+q, c); //turn every third pixel on
|
||||
}
|
||||
strip.show();
|
||||
|
||||
delay(wait);
|
||||
|
||||
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
|
||||
strip.setPixelColor(i+q, 0); //turn every third pixel off
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Theatre-style crawling lights with rainbow effect
|
||||
void theaterChaseRainbow(uint8_t wait) {
|
||||
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
|
||||
for (int q=0; q < 3; q++) {
|
||||
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
|
||||
strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on
|
||||
}
|
||||
strip.show();
|
||||
|
||||
delay(wait);
|
||||
|
||||
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
|
||||
strip.setPixelColor(i+q, 0); //turn every third pixel off
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pulseWhite(uint8_t wait) {
|
||||
for(int j = 0; j < 256 ; j++){
|
||||
for(uint16_t i=0; i<strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) );
|
||||
}
|
||||
delay(wait);
|
||||
strip.show();
|
||||
}
|
||||
|
||||
for(int j = 255; j >= 0 ; j--){
|
||||
for(uint16_t i=0; i<strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) );
|
||||
}
|
||||
delay(wait);
|
||||
strip.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rainbowFade2White(uint8_t wait, int rainbowLoops, int whiteLoops) {
|
||||
float fadeMax = 100.0;
|
||||
int fadeVal = 0;
|
||||
uint32_t wheelVal;
|
||||
int redVal, greenVal, blueVal;
|
||||
|
||||
for(int k = 0 ; k < rainbowLoops ; k ++){
|
||||
|
||||
for(int j=0; j<256; j++) { // 5 cycles of all colors on wheel
|
||||
|
||||
for(int i=0; i< strip.numPixels(); i++) {
|
||||
|
||||
wheelVal = Wheel(((i * 256 / strip.numPixels()) + j) & 255);
|
||||
|
||||
redVal = red(wheelVal) * float(fadeVal/fadeMax);
|
||||
greenVal = green(wheelVal) * float(fadeVal/fadeMax);
|
||||
blueVal = blue(wheelVal) * float(fadeVal/fadeMax);
|
||||
|
||||
strip.setPixelColor( i, strip.Color( redVal, greenVal, blueVal ) );
|
||||
|
||||
}
|
||||
|
||||
//First loop, fade in!
|
||||
if(k == 0 && fadeVal < fadeMax-1) {
|
||||
fadeVal++;
|
||||
}
|
||||
|
||||
//Last loop, fade out!
|
||||
else if(k == rainbowLoops - 1 && j > 255 - fadeMax ){
|
||||
fadeVal--;
|
||||
}
|
||||
|
||||
strip.show();
|
||||
delay(wait);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
delay(500);
|
||||
|
||||
|
||||
for(int k = 0 ; k < whiteLoops ; k ++){
|
||||
|
||||
for(int j = 0; j < 256 ; j++){
|
||||
|
||||
for(uint16_t i=0; i < strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) );
|
||||
}
|
||||
strip.show();
|
||||
}
|
||||
|
||||
delay(2000);
|
||||
for(int j = 255; j >= 0 ; j--){
|
||||
|
||||
for(uint16_t i=0; i < strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) );
|
||||
}
|
||||
strip.show();
|
||||
}
|
||||
}
|
||||
|
||||
delay(500);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void whiteOverRainbow(uint8_t wait, uint8_t whiteSpeed, uint8_t whiteLength ) {
|
||||
|
||||
if(whiteLength >= strip.numPixels()) whiteLength = strip.numPixels() - 1;
|
||||
|
||||
int head = whiteLength - 1;
|
||||
int tail = 0;
|
||||
|
||||
int loops = 3;
|
||||
int loopNum = 0;
|
||||
|
||||
static unsigned long lastTime = 0;
|
||||
|
||||
|
||||
while(true){
|
||||
for(int j=0; j<256; j++) {
|
||||
for(uint16_t i=0; i<strip.numPixels(); i++) {
|
||||
if((i >= tail && i <= head) || (tail > head && i >= tail) || (tail > head && i <= head) ){
|
||||
strip.setPixelColor(i, strip.Color(0,0,0, 255 ) );
|
||||
}
|
||||
else{
|
||||
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(millis() - lastTime > whiteSpeed) {
|
||||
head++;
|
||||
tail++;
|
||||
if(head == strip.numPixels()){
|
||||
loopNum++;
|
||||
}
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
if(loopNum == loops) return;
|
||||
|
||||
head%=strip.numPixels();
|
||||
tail%=strip.numPixels();
|
||||
strip.show();
|
||||
delay(wait);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void fullWhite() {
|
||||
|
||||
for(uint16_t i=0; i<strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, strip.Color(0,0,0, 255 ) );
|
||||
}
|
||||
strip.show();
|
||||
}
|
||||
|
||||
uint8_t red(uint32_t c) {
|
||||
return (c >> 16);
|
||||
}
|
||||
uint8_t green(uint32_t c) {
|
||||
return (c >> 8);
|
||||
}
|
||||
uint8_t blue(uint32_t c) {
|
||||
return (c);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For WS2812B
|
||||
# Class
|
||||
#######################################
|
||||
|
||||
WS2812B KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions
|
||||
#######################################
|
||||
|
||||
setPixelColor KEYWORD2
|
||||
numPixels KEYWORD2
|
||||
Color KEYWORD2
|
||||
show KEYWORD2
|
||||
|
||||
clear KEYWORD2
|
||||
updateLength KEYWORD2
|
||||
|
||||
canShow KEYWORD2
|
||||
|
||||
|
||||
#######################################
|
||||
# Constants
|
||||
#######################################
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
name=WS2812B
|
||||
version=1.0
|
||||
author=Roger Clark, based on the Adafruit Neopixel library API
|
||||
email=
|
||||
sentence=WS2812B (Neopixel) library
|
||||
paragraph=WS2812B (Neopixel) library for STM32F1 LibMaple
|
||||
url=
|
||||
architectures=STM32F1
|
||||
maintainer=Roger Clark
|
||||
category=Uncategorized
|
|
@ -0,0 +1,238 @@
|
|||
/*-----------------------------------------------------------------------------------------------
|
||||
Arduino library to control WS2812B RGB Led strips using the Arduino STM32 LibMaple core
|
||||
-----------------------------------------------------------------------------------------------
|
||||
|
||||
Note.
|
||||
This library has only been tested on the WS2812B LED. It may not work with the older WS2812 or
|
||||
other types of addressable RGB LED, becuase it relies on a division multiple of the 72Mhz clock
|
||||
frequence on the STM32 SPI to generate the correct width T0H pulse, of 400ns +/- 150nS
|
||||
SPI DIV32 gives a pulse width of 444nS which is well within spec for the WS2812B but
|
||||
is probably too long for the WS2812 which needs a 350ns pulse for T0H
|
||||
|
||||
This WS2811B library 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.
|
||||
|
||||
It 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.
|
||||
|
||||
See <http://www.gnu.org/licenses/>.
|
||||
-----------------------------------------------------------------------------------------------*/
|
||||
|
||||
#include "WS2812B.h"
|
||||
#include "pins_arduino.h"
|
||||
#include "wiring_private.h"
|
||||
#include <SPI.h>
|
||||
|
||||
|
||||
// Constructor when n is the number of LEDs in the strip
|
||||
WS2812B::WS2812B(uint16_t number_of_leds) :
|
||||
brightness(0), pixels(NULL)
|
||||
{
|
||||
updateLength(number_of_leds);
|
||||
}
|
||||
|
||||
|
||||
WS2812B::~WS2812B()
|
||||
{
|
||||
if(pixels)
|
||||
{
|
||||
free(pixels);
|
||||
}
|
||||
SPI.end();
|
||||
}
|
||||
|
||||
void WS2812B::begin(void) {
|
||||
|
||||
if (!begun)
|
||||
{
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV32);// need bit rate of 400nS but closest we can do @ 72Mhz is 444ns (which is within spec)
|
||||
SPI.begin();
|
||||
begun = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812B::updateLength(uint16_t n)
|
||||
{
|
||||
if(doubleBuffer)
|
||||
{
|
||||
free(doubleBuffer);
|
||||
}
|
||||
|
||||
numBytes = (n<<3) + n + 2; // 9 encoded bytes per pixel. 1 byte empty peamble to fix issue with SPI MOSI and on byte at the end to clear down MOSI
|
||||
// Note. (n<<3) +n is a fast way of doing n*9
|
||||
if((doubleBuffer = (uint8_t *)malloc(numBytes*2)))
|
||||
{
|
||||
numLEDs = n;
|
||||
pixels = doubleBuffer;
|
||||
// Only need to init the part of the double buffer which will be interacted with by the API e.g. setPixelColor
|
||||
*pixels=0;//clear the preamble byte
|
||||
*(pixels+numBytes-1)=0;// clear the post send cleardown byte.
|
||||
clear();// Set the encoded data to all encoded zeros
|
||||
}
|
||||
else
|
||||
{
|
||||
numLEDs = numBytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Sends the current buffer to the leds
|
||||
void WS2812B::show(void)
|
||||
{
|
||||
SPI.dmaSendAsync(pixels,numBytes);// Start the DMA transfer of the current pixel buffer to the LEDs and return immediately.
|
||||
|
||||
// Need to copy the last / current buffer to the other half of the double buffer as most API code does not rebuild the entire contents
|
||||
// from scratch. Often just a few pixels are changed e.g in a chaser effect
|
||||
|
||||
if (pixels==doubleBuffer)
|
||||
{
|
||||
// pixels was using the first buffer
|
||||
pixels = doubleBuffer+numBytes; // set pixels to second buffer
|
||||
memcpy(pixels,doubleBuffer,numBytes);// copy first buffer to second buffer
|
||||
}
|
||||
else
|
||||
{
|
||||
// pixels was using the second buffer
|
||||
pixels = doubleBuffer; // set pixels to first buffer
|
||||
memcpy(pixels,doubleBuffer+numBytes,numBytes); // copy second buffer to first buffer
|
||||
}
|
||||
}
|
||||
|
||||
/*Sets a specific pixel to a specific r,g,b colour
|
||||
* Because the pixels buffer contains the encoded bitstream, which is in triplets
|
||||
* the lookup table need to be used to find the correct pattern for each byte in the 3 byte sequence.
|
||||
*/
|
||||
void WS2812B::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
uint8_t *bptr = pixels + (n<<3) + n +1;
|
||||
uint8_t *tPtr = (uint8_t *)encoderLookup + g*2 + g;// need to index 3 x g into the lookup
|
||||
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
|
||||
tPtr = (uint8_t *)encoderLookup + r*2 + r;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
|
||||
tPtr = (uint8_t *)encoderLookup + b*2 + b;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
}
|
||||
|
||||
void WS2812B::setPixelColor(uint16_t n, uint32_t c)
|
||||
{
|
||||
uint8_t r,g,b;
|
||||
|
||||
if(brightness)
|
||||
{
|
||||
r = ((int)((uint8_t)(c >> 16)) * (int)brightness) >> 8;
|
||||
g = ((int)((uint8_t)(c >> 8)) * (int)brightness) >> 8;
|
||||
b = ((int)((uint8_t)c) * (int)brightness) >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = (uint8_t)(c >> 16),
|
||||
g = (uint8_t)(c >> 8),
|
||||
b = (uint8_t)c;
|
||||
}
|
||||
|
||||
uint8_t *bptr = pixels + (n<<3) + n +1;
|
||||
uint8_t *tPtr = (uint8_t *)encoderLookup + g*2 + g;// need to index 3 x g into the lookup
|
||||
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
|
||||
tPtr = (uint8_t *)encoderLookup + r*2 + r;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
|
||||
tPtr = (uint8_t *)encoderLookup + b*2 + b;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
}
|
||||
|
||||
// Convert separate R,G,B into packed 32-bit RGB color.
|
||||
// Packed format is always RGB, regardless of LED strand color order.
|
||||
uint32_t WS2812B::Color(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
|
||||
// Convert separate R,G,B,W into packed 32-bit WRGB color.
|
||||
// Packed format is always WRGB, regardless of LED strand color order.
|
||||
uint32_t WS2812B::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||
return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
|
||||
|
||||
uint16_t WS2812B::numPixels(void) const {
|
||||
return numLEDs;
|
||||
}
|
||||
|
||||
// Adjust output brightness; 0=darkest (off), 255=brightest. This does
|
||||
// NOT immediately affect what's currently displayed on the LEDs. The
|
||||
// next call to show() will refresh the LEDs at this level. However,
|
||||
// this process is potentially "lossy," especially when increasing
|
||||
// brightness. The tight timing in the WS2811/WS2812 code means there
|
||||
// aren't enough free cycles to perform this scaling on the fly as data
|
||||
// is issued. So we make a pass through the existing color data in RAM
|
||||
// and scale it (subsequent graphics commands also work at this
|
||||
// brightness level). If there's a significant step up in brightness,
|
||||
// the limited number of steps (quantization) in the old data will be
|
||||
// quite visible in the re-scaled version. For a non-destructive
|
||||
// change, you'll need to re-render the full strip data. C'est la vie.
|
||||
void WS2812B::setBrightness(uint8_t b) {
|
||||
// Stored brightness value is different than what's passed.
|
||||
// This simplifies the actual scaling math later, allowing a fast
|
||||
// 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t,
|
||||
// adding 1 here may (intentionally) roll over...so 0 = max brightness
|
||||
// (color values are interpreted literally; no scaling), 1 = min
|
||||
// brightness (off), 255 = just below max brightness.
|
||||
uint8_t newBrightness = b + 1;
|
||||
if(newBrightness != brightness) { // Compare against prior value
|
||||
// Brightness has changed -- re-scale existing data in RAM
|
||||
uint8_t c,
|
||||
*ptr = pixels,
|
||||
oldBrightness = brightness - 1; // De-wrap old brightness value
|
||||
uint16_t scale;
|
||||
if(oldBrightness == 0) scale = 0; // Avoid /0
|
||||
else if(b == 255) scale = 65535 / oldBrightness;
|
||||
else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness;
|
||||
for(uint16_t i=0; i<numBytes; i++)
|
||||
{
|
||||
c = *ptr;
|
||||
*ptr++ = (c * scale) >> 8;
|
||||
}
|
||||
brightness = newBrightness;
|
||||
}
|
||||
}
|
||||
|
||||
//Return the brightness value
|
||||
uint8_t WS2812B::getBrightness(void) const {
|
||||
return brightness - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the encoded pixel data to turn all the LEDs off.
|
||||
*/
|
||||
void WS2812B::clear()
|
||||
{
|
||||
uint8_t * bptr= pixels+1;// Note first byte in the buffer is a preable and is always zero. hence the +1
|
||||
uint8_t *tPtr;
|
||||
|
||||
for(int i=0;i< (numLEDs *3);i++)
|
||||
{
|
||||
tPtr = (uint8_t *)encoderLookup;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
*bptr++ = *tPtr++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*--------------------------------------------------------------------
|
||||
The WS2812B library 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.
|
||||
|
||||
It 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.
|
||||
|
||||
See <http://www.gnu.org/licenses/>.
|
||||
--------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WS2812B_H
|
||||
#define WS2812B_H
|
||||
|
||||
#include <Arduino.h>
|
||||
/*
|
||||
* old version used 3 separate tables, one per byte of the 24 bit encoded data
|
||||
*
|
||||
static const uint8_t byte0Lookup[256]={0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9A,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD2,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xD3,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB};
|
||||
static const uint8_t byte1Lookup[256]={0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D,0x6D};
|
||||
static const uint8_t byte2Lookup[256]={0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6,0x24,0x26,0x34,0x36,0xA4,0xA6,0xB4,0xB6};
|
||||
*/
|
||||
|
||||
// New version uses one large LUT as its faster index into sequential bytes for the GRB pattern
|
||||
static uint8_t encoderLookup[256*3]={ 0x92,0x49,0x24,0x92,0x49,0x26,0x92,0x49,0x34,0x92,0x49,0x36,0x92,0x49,0xA4,0x92,0x49,0xA6,0x92,0x49,0xB4,0x92,0x49,0xB6,0x92,0x4D,0x24,0x92,0x4D,0x26,0x92,0x4D,0x34,0x92,0x4D,0x36,0x92,0x4D,0xA4,0x92,0x4D,0xA6,0x92,0x4D,0xB4,0x92,0x4D,0xB6,0x92,0x69,0x24,0x92,0x69,0x26,0x92,0x69,0x34,0x92,0x69,0x36,0x92,0x69,0xA4,0x92,0x69,0xA6,0x92,0x69,0xB4,0x92,0x69,0xB6,0x92,0x6D,0x24,0x92,0x6D,0x26,0x92,0x6D,0x34,0x92,0x6D,0x36,0x92,0x6D,0xA4,0x92,0x6D,0xA6,0x92,0x6D,0xB4,0x92,0x6D,0xB6,0x93,0x49,0x24,0x93,0x49,0x26,0x93,0x49,0x34,0x93,0x49,0x36,0x93,0x49,0xA4,0x93,0x49,0xA6,0x93,0x49,0xB4,0x93,0x49,0xB6,0x93,0x4D,0x24,0x93,0x4D,0x26,0x93,0x4D,0x34,0x93,0x4D,0x36,0x93,0x4D,0xA4,0x93,0x4D,0xA6,0x93,0x4D,0xB4,0x93,0x4D,0xB6,0x93,0x69,0x24,0x93,0x69,0x26,0x93,0x69,0x34,0x93,0x69,0x36,0x93,0x69,0xA4,0x93,0x69,0xA6,0x93,0x69,0xB4,0x93,0x69,0xB6,0x93,0x6D,0x24,0x93,0x6D,0x26,0x93,0x6D,0x34,0x93,0x6D,0x36,0x93,0x6D,0xA4,0x93,0x6D,0xA6,0x93,0x6D,0xB4,0x93,0x6D,0xB6,0x9A,0x49,0x24,0x9A,0x49,0x26,0x9A,0x49,0x34,0x9A,0x49,0x36,0x9A,0x49,0xA4,0x9A,0x49,0xA6,0x9A,0x49,0xB4,0x9A,0x49,0xB6,0x9A,0x4D,0x24,0x9A,0x4D,0x26,0x9A,0x4D,0x34,0x9A,0x4D,0x36,0x9A,0x4D,0xA4,0x9A,0x4D,0xA6,0x9A,0x4D,0xB4,0x9A,0x4D,0xB6,0x9A,0x69,0x24,0x9A,0x69,0x26,0x9A,0x69,0x34,0x9A,0x69,0x36,0x9A,0x69,0xA4,0x9A,0x69,\
|
||||
0xA6,0x9A,0x69,0xB4,0x9A,0x69,0xB6,0x9A,0x6D,0x24,0x9A,0x6D,0x26,0x9A,0x6D,0x34,0x9A,0x6D,0x36,0x9A,0x6D,0xA4,0x9A,0x6D,0xA6,0x9A,0x6D,0xB4,0x9A,0x6D,0xB6,0x9B,0x49,0x24,0x9B,0x49,0x26,0x9B,0x49,0x34,0x9B,0x49,0x36,0x9B,0x49,0xA4,0x9B,0x49,0xA6,0x9B,0x49,0xB4,0x9B,0x49,0xB6,0x9B,0x4D,0x24,0x9B,0x4D,0x26,0x9B,0x4D,0x34,0x9B,0x4D,0x36,0x9B,0x4D,0xA4,0x9B,0x4D,0xA6,0x9B,0x4D,0xB4,0x9B,0x4D,0xB6,0x9B,0x69,0x24,0x9B,0x69,0x26,0x9B,0x69,0x34,0x9B,0x69,0x36,0x9B,0x69,0xA4,0x9B,0x69,0xA6,0x9B,0x69,0xB4,0x9B,0x69,0xB6,0x9B,0x6D,0x24,0x9B,0x6D,0x26,0x9B,0x6D,0x34,0x9B,0x6D,0x36,0x9B,0x6D,0xA4,0x9B,0x6D,0xA6,0x9B,0x6D,0xB4,0x9B,0x6D,0xB6,0xD2,0x49,0x24,0xD2,0x49,0x26,0xD2,0x49,0x34,0xD2,0x49,0x36,0xD2,0x49,0xA4,0xD2,0x49,0xA6,0xD2,0x49,0xB4,0xD2,0x49,0xB6,0xD2,0x4D,0x24,0xD2,0x4D,0x26,0xD2,0x4D,0x34,0xD2,0x4D,0x36,0xD2,0x4D,0xA4,0xD2,0x4D,0xA6,0xD2,0x4D,0xB4,0xD2,0x4D,0xB6,0xD2,0x69,0x24,0xD2,0x69,0x26,0xD2,0x69,0x34,0xD2,0x69,0x36,0xD2,0x69,0xA4,0xD2,0x69,0xA6,0xD2,0x69,0xB4,0xD2,0x69,0xB6,0xD2,0x6D,0x24,0xD2,0x6D,0x26,0xD2,0x6D,0x34,0xD2,0x6D,0x36,0xD2,0x6D,0xA4,0xD2,0x6D,0xA6,0xD2,0x6D,0xB4,0xD2,0x6D,0xB6,0xD3,0x49,0x24,0xD3,0x49,0x26,0xD3,0x49,0x34,0xD3,0x49,0x36,0xD3,0x49,0xA4,0xD3,0x49,0xA6,0xD3,0x49,0xB4,0xD3,0x49,0xB6,0xD3,0x4D,0x24,0xD3,0x4D,0x26,0xD3,0x4D,0x34,0xD3,\
|
||||
0x4D,0x36,0xD3,0x4D,0xA4,0xD3,0x4D,0xA6,0xD3,0x4D,0xB4,0xD3,0x4D,0xB6,0xD3,0x69,0x24,0xD3,0x69,0x26,0xD3,0x69,0x34,0xD3,0x69,0x36,0xD3,0x69,0xA4,0xD3,0x69,0xA6,0xD3,0x69,0xB4,0xD3,0x69,0xB6,0xD3,0x6D,0x24,0xD3,0x6D,0x26,0xD3,0x6D,0x34,0xD3,0x6D,0x36,0xD3,0x6D,0xA4,0xD3,0x6D,0xA6,0xD3,0x6D,0xB4,0xD3,0x6D,0xB6,0xDA,0x49,0x24,0xDA,0x49,0x26,0xDA,0x49,0x34,0xDA,0x49,0x36,0xDA,0x49,0xA4,0xDA,0x49,0xA6,0xDA,0x49,0xB4,0xDA,0x49,0xB6,0xDA,0x4D,0x24,0xDA,0x4D,0x26,0xDA,0x4D,0x34,0xDA,0x4D,0x36,0xDA,0x4D,0xA4,0xDA,0x4D,0xA6,0xDA,0x4D,0xB4,0xDA,0x4D,0xB6,0xDA,0x69,0x24,0xDA,0x69,0x26,0xDA,0x69,0x34,0xDA,0x69,0x36,0xDA,0x69,0xA4,0xDA,0x69,0xA6,0xDA,0x69,0xB4,0xDA,0x69,0xB6,0xDA,0x6D,0x24,0xDA,0x6D,0x26,0xDA,0x6D,0x34,0xDA,0x6D,0x36,0xDA,0x6D,0xA4,0xDA,0x6D,0xA6,0xDA,0x6D,0xB4,0xDA,0x6D,0xB6,0xDB,0x49,0x24,0xDB,0x49,0x26,0xDB,0x49,0x34,0xDB,0x49,0x36,0xDB,0x49,0xA4,0xDB,0x49,0xA6,0xDB,0x49,0xB4,0xDB,0x49,0xB6,0xDB,0x4D,0x24,0xDB,0x4D,0x26,0xDB,0x4D,0x34,0xDB,0x4D,0x36,0xDB,0x4D,0xA4,0xDB,0x4D,0xA6,0xDB,0x4D,0xB4,0xDB,0x4D,0xB6,0xDB,0x69,0x24,0xDB,0x69,0x26,0xDB,0x69,0x34,0xDB,0x69,0x36,0xDB,0x69,0xA4,0xDB,0x69,0xA6,0xDB,0x69,0xB4,0xDB,0x69,0xB6,0xDB,0x6D,0x24,0xDB,0x6D,0x26,0xDB,0x6D,0x34,0xDB,0x6D,0x36,0xDB,0x6D,0xA4,0xDB,0x6D,0xA6,0xDB,0x6D,0xB4,0xDB,0x6D,0xB6};
|
||||
|
||||
class WS2812B {
|
||||
public:
|
||||
|
||||
// Constructor: number of LEDs
|
||||
WS2812B (uint16_t number_of_leds);// Constuctor
|
||||
~WS2812B();
|
||||
void
|
||||
begin(void),
|
||||
show(void),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
|
||||
// setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setBrightness(uint8_t),
|
||||
clear(),
|
||||
updateLength(uint16_t n);
|
||||
uint8_t
|
||||
// *getPixels(void) const,
|
||||
getBrightness(void) const;
|
||||
uint16_t
|
||||
numPixels(void) const;
|
||||
static uint32_t
|
||||
Color(uint8_t r, uint8_t g, uint8_t b),
|
||||
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w);
|
||||
// uint32_t
|
||||
// getPixelColor(uint16_t n) const;
|
||||
inline bool
|
||||
canShow(void) { return (micros() - endTime) >= 300L; }
|
||||
|
||||
private:
|
||||
|
||||
boolean
|
||||
begun; // true if begin() previously called
|
||||
uint16_t
|
||||
numLEDs, // Number of RGB LEDs in strip
|
||||
numBytes; // Size of 'pixels' buffer
|
||||
|
||||
uint8_t
|
||||
brightness,
|
||||
*pixels, // Holds the current LED color values, which the external API calls interact with 9 bytes per pixel + start + end empty bytes
|
||||
*doubleBuffer, // Holds the start of the double buffer (1 buffer for async DMA transfer and one for the API interaction.
|
||||
rOffset, // Index of red byte within each 3- or 4-byte pixel
|
||||
gOffset, // Index of green byte
|
||||
bOffset, // Index of blue byte
|
||||
wOffset; // Index of white byte (same as rOffset if no white)
|
||||
uint32_t
|
||||
endTime; // Latch timing reference
|
||||
};
|
||||
|
||||
|
||||
#endif // WS2812B_H
|
|
@ -75,3 +75,8 @@ HardWire::~HardWire() {
|
|||
void HardWire::begin(uint8 self_addr) {
|
||||
i2c_master_enable(sel_hard, dev_flags);
|
||||
}
|
||||
|
||||
void HardWire::end() {
|
||||
i2c_disable(sel_hard);
|
||||
sel_hard = 0;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,11 @@ public:
|
|||
* passed flags
|
||||
*/
|
||||
HardWire(uint8, uint8 = 0);
|
||||
|
||||
/*
|
||||
* Shuts down (disables) the hardware I2C
|
||||
*/
|
||||
void end();
|
||||
|
||||
/*
|
||||
* Disables the I2C device and remove the device address.
|
||||
|
|
|
@ -184,6 +184,18 @@ void TwoWire::begin(uint8 self_addr) {
|
|||
set_sda(HIGH);
|
||||
}
|
||||
|
||||
void TwoWire::end()
|
||||
{
|
||||
if (this->scl_pin)
|
||||
{
|
||||
pinMode(this->scl_pin, INPUT);
|
||||
}
|
||||
if (this->sda_pin)
|
||||
{
|
||||
pinMode(this->sda_pin, INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
TwoWire::~TwoWire() {
|
||||
this->scl_pin=0;
|
||||
this->sda_pin=0;
|
||||
|
|
|
@ -111,6 +111,10 @@ class TwoWire : public WireBase {
|
|||
* Shifts out the data through SDA and clocks SCL for the slave device
|
||||
*/
|
||||
void i2c_shift_out(uint8);
|
||||
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Processes the incoming I2C message defined by WireBase
|
||||
|
@ -130,6 +134,11 @@ class TwoWire : public WireBase {
|
|||
*/
|
||||
void begin(uint8 = 0x00);
|
||||
|
||||
/*
|
||||
* Sets pins SDA and SCL to INPUT
|
||||
*/
|
||||
void end();
|
||||
|
||||
/*
|
||||
* If object is destroyed, set pin numbers to 0.
|
||||
*/
|
||||
|
|
|
@ -559,7 +559,6 @@ typedef enum dma_mode_flags {
|
|||
*
|
||||
* (It's not possible to fully configure a DMA stream on F2 with just
|
||||
* this information, so this interface is too tied to the F1.) */
|
||||
__deprecated
|
||||
void dma_setup_transfer(dma_dev *dev,
|
||||
dma_channel channel,
|
||||
__io void *peripheral_address,
|
||||
|
|
Loading…
Reference in New Issue