forked from Makuna/NeoPixelBus
Merge pull request #108 from unaiur/esp8266-async-uart
Esp8266 async uart
This commit is contained in:
216
src/internal/NeoEsp8266UartMethod.cpp
Normal file
216
src/internal/NeoEsp8266UartMethod.cpp
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
NeoPixel library helper functions for Esp8266 UART hardware
|
||||||
|
|
||||||
|
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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
#include "NeoEsp8266UartMethod.h"
|
||||||
|
#include <utility>
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <eagle_soc.h>
|
||||||
|
#include <ets_sys.h>
|
||||||
|
#include <uart.h>
|
||||||
|
#include <uart_register.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UART1 1
|
||||||
|
#define UART1_INV_MASK (0x3f << 19)
|
||||||
|
|
||||||
|
// Gets the number of bytes waiting in the TX FIFO of UART1
|
||||||
|
static inline uint8_t getUartTxFifoLength()
|
||||||
|
{
|
||||||
|
return (U1S >> USTXC) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a byte to the TX FIFO of UART1
|
||||||
|
// You must ensure the TX FIFO isn't full
|
||||||
|
static inline void enqueue(uint8_t byte)
|
||||||
|
{
|
||||||
|
U1F = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t* esp8266_uart1_async_buf;
|
||||||
|
static const uint8_t* esp8266_uart1_async_buf_end;
|
||||||
|
|
||||||
|
NeoEsp8266Uart::NeoEsp8266Uart(uint8_t pin, uint16_t pixelCount, size_t elementSize)
|
||||||
|
{
|
||||||
|
_sizePixels = pixelCount * elementSize;
|
||||||
|
_pixels = (uint8_t*)malloc(_sizePixels);
|
||||||
|
memset(_pixels, 0x00, _sizePixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoEsp8266Uart::~NeoEsp8266Uart()
|
||||||
|
{
|
||||||
|
free(_pixels);
|
||||||
|
|
||||||
|
// Wait until the TX fifo is empty. This way we avoid broken frames
|
||||||
|
// when destroying & creating a NeoPixelBus to change its length.
|
||||||
|
while (getUartTxFifoLength() > 0)
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NeoEsp8266Uart::InitializeUart(uint32_t uartBaud)
|
||||||
|
{
|
||||||
|
// Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1)
|
||||||
|
Serial1.begin(uartBaud, SERIAL_6N1, SERIAL_TX_ONLY);
|
||||||
|
|
||||||
|
// Invert the TX voltage associated with logic level so:
|
||||||
|
// - A logic level 0 will generate a Vcc signal
|
||||||
|
// - A logic level 1 will generate a Gnd signal
|
||||||
|
CLEAR_PERI_REG_MASK(UART_CONF0(UART1), UART1_INV_MASK);
|
||||||
|
SET_PERI_REG_MASK(UART_CONF0(UART1), (BIT(22)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NeoEsp8266Uart::UpdateUart()
|
||||||
|
{
|
||||||
|
// Since the UART can finish sending queued bytes in the FIFO in
|
||||||
|
// the background, instead of waiting for the FIFO to flush
|
||||||
|
// we annotate the start time of the frame so we can calculate
|
||||||
|
// when it will finish.
|
||||||
|
_startTime = micros();
|
||||||
|
|
||||||
|
// Then keep filling the FIFO until done
|
||||||
|
const uint8_t* ptr = _pixels;
|
||||||
|
const uint8_t* end = ptr + _sizePixels;
|
||||||
|
while (ptr != end)
|
||||||
|
{
|
||||||
|
ptr = FillUartFifo(ptr, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* ICACHE_RAM_ATTR NeoEsp8266Uart::FillUartFifo(const uint8_t* pixels, const uint8_t* end)
|
||||||
|
{
|
||||||
|
// Remember: UARTs send less significant bit (LSB) first so
|
||||||
|
// pushing ABCDEF byte will generate a 0FEDCBA1 signal,
|
||||||
|
// including a LOW(0) start & a HIGH(1) stop bits.
|
||||||
|
// Also, we have configured UART to invert logic levels, so:
|
||||||
|
const uint8_t _uartData[4] = {
|
||||||
|
0b110111, // On wire: 1 000 100 0 [Neopixel reads 00]
|
||||||
|
0b000111, // On wire: 1 000 111 0 [Neopixel reads 01]
|
||||||
|
0b110100, // On wire: 1 110 100 0 [Neopixel reads 10]
|
||||||
|
0b000100, // On wire: 1 110 111 0 [NeoPixel reads 11]
|
||||||
|
};
|
||||||
|
uint8_t avail = (UART_TX_FIFO_SIZE - getUartTxFifoLength()) / 4;
|
||||||
|
if (end - pixels > avail)
|
||||||
|
{
|
||||||
|
end = pixels + avail;
|
||||||
|
}
|
||||||
|
while (pixels < end)
|
||||||
|
{
|
||||||
|
uint8_t subpix = *pixels++;
|
||||||
|
enqueue(_uartData[(subpix >> 6) & 0x3]);
|
||||||
|
enqueue(_uartData[(subpix >> 4) & 0x3]);
|
||||||
|
enqueue(_uartData[(subpix >> 2) & 0x3]);
|
||||||
|
enqueue(_uartData[ subpix & 0x3]);
|
||||||
|
}
|
||||||
|
return pixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoEsp8266AsyncUart::NeoEsp8266AsyncUart(uint8_t pin, uint16_t pixelCount, size_t elementSize)
|
||||||
|
: NeoEsp8266Uart(pin, pixelCount, elementSize)
|
||||||
|
{
|
||||||
|
_asyncPixels = (uint8_t*)malloc(_sizePixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoEsp8266AsyncUart::~NeoEsp8266AsyncUart()
|
||||||
|
{
|
||||||
|
// Remember: the UART interrupt can be sending data from _asyncPixels in the background
|
||||||
|
while (esp8266_uart1_async_buf != esp8266_uart1_async_buf_end)
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
free(_asyncPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR NeoEsp8266AsyncUart::InitializeUart(uint32_t uartBaud)
|
||||||
|
{
|
||||||
|
NeoEsp8266Uart::InitializeUart(uartBaud);
|
||||||
|
|
||||||
|
// Disable all interrupts
|
||||||
|
ETS_UART_INTR_DISABLE();
|
||||||
|
|
||||||
|
// Clear the RX & TX FIFOS
|
||||||
|
SET_PERI_REG_MASK(UART_CONF0(UART1), UART_RXFIFO_RST | UART_TXFIFO_RST);
|
||||||
|
CLEAR_PERI_REG_MASK(UART_CONF0(UART1), UART_RXFIFO_RST | UART_TXFIFO_RST);
|
||||||
|
|
||||||
|
// Set the interrupt handler
|
||||||
|
ETS_UART_INTR_ATTACH(IntrHandler, NULL);
|
||||||
|
|
||||||
|
// Set tx fifo trigger. 80 bytes gives us 200 microsecs to refill the FIFO
|
||||||
|
WRITE_PERI_REG(UART_CONF1(UART1), 80 << UART_TXFIFO_EMPTY_THRHD_S);
|
||||||
|
|
||||||
|
// Disable RX & TX interrupts. It is enabled by uart.c in the SDK
|
||||||
|
CLEAR_PERI_REG_MASK(UART_INT_ENA(UART1), UART_RXFIFO_FULL_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA);
|
||||||
|
|
||||||
|
// Clear all pending interrupts in UART1
|
||||||
|
WRITE_PERI_REG(UART_INT_CLR(UART1), 0xffff);
|
||||||
|
|
||||||
|
// Reenable interrupts
|
||||||
|
ETS_UART_INTR_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NeoEsp8266AsyncUart::UpdateUart()
|
||||||
|
{
|
||||||
|
// Instruct ESP8266 hardware uart1 to send the pixels asynchronously
|
||||||
|
esp8266_uart1_async_buf = _pixels;
|
||||||
|
esp8266_uart1_async_buf_end = _pixels + _sizePixels;
|
||||||
|
SET_PERI_REG_MASK(UART_INT_ENA(1), UART_TXFIFO_EMPTY_INT_ENA);
|
||||||
|
|
||||||
|
// Annotate when we started to send bytes, so we can calculate when we are ready to send again
|
||||||
|
_startTime = micros();
|
||||||
|
|
||||||
|
// Copy the pixels to the idle buffer and swap them
|
||||||
|
memcpy(_asyncPixels, _pixels, _sizePixels);
|
||||||
|
std::swap(_asyncPixels, _pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_RAM_ATTR NeoEsp8266AsyncUart::IntrHandler(void* param)
|
||||||
|
{
|
||||||
|
// Interrupt handler is shared between UART0 & UART1
|
||||||
|
if (READ_PERI_REG(UART_INT_ST(UART1))) //any UART1 stuff
|
||||||
|
{
|
||||||
|
// Fill the FIFO with new data
|
||||||
|
esp8266_uart1_async_buf = FillUartFifo(esp8266_uart1_async_buf, esp8266_uart1_async_buf_end);
|
||||||
|
// Disable TX interrupt when done
|
||||||
|
if (esp8266_uart1_async_buf == esp8266_uart1_async_buf_end)
|
||||||
|
{
|
||||||
|
CLEAR_PERI_REG_MASK(UART_INT_ENA(UART1), UART_TXFIFO_EMPTY_INT_ENA);
|
||||||
|
}
|
||||||
|
// Clear all interrupts flags (just in case)
|
||||||
|
WRITE_PERI_REG(UART_INT_CLR(UART1), 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (READ_PERI_REG(UART_INT_ST(UART0)))
|
||||||
|
{
|
||||||
|
// TODO: gdbstub uses the interrupt of UART0, but there is no way to call its
|
||||||
|
// interrupt handler gdbstub_uart_hdlr since it's static.
|
||||||
|
WRITE_PERI_REG(UART_INT_CLR(UART0), 0xffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@@ -1,5 +1,5 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
NeoPixel library helper functions for Esp8266.
|
NeoPixel library helper functions for Esp8266 UART hardware
|
||||||
|
|
||||||
Written by Michael C. Miller.
|
Written by Michael C. Miller.
|
||||||
|
|
||||||
@@ -27,64 +27,96 @@ License along with NeoPixel. If not, see
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
extern "C"
|
// NeoEsp8266Uart contains all the low level details that doesn't
|
||||||
|
// depend on the transmission speed, and therefore, it isn't a template
|
||||||
|
class NeoEsp8266Uart
|
||||||
{
|
{
|
||||||
#include "eagle_soc.h"
|
protected:
|
||||||
#include "uart_register.h"
|
NeoEsp8266Uart(uint8_t pin, uint16_t pixelCount, size_t elementSize);
|
||||||
}
|
|
||||||
|
|
||||||
// due to linker overriding ICACHE_RAM_ATTR for cpp files, this function was
|
~NeoEsp8266Uart();
|
||||||
// moved into a NeoPixelEsp8266.c file.
|
|
||||||
extern "C" void ICACHE_RAM_ATTR esp8266_uart1_send_pixels(uint8_t* pixels, uint8_t* end);
|
|
||||||
|
|
||||||
|
void InitializeUart(uint32_t uartBaud);
|
||||||
|
|
||||||
|
void UpdateUart();
|
||||||
|
|
||||||
|
static const uint8_t* ICACHE_RAM_ATTR FillUartFifo(const uint8_t* pixels, const uint8_t* end);
|
||||||
|
|
||||||
|
size_t _sizePixels; // Size of '_pixels' buffer below
|
||||||
|
uint8_t* _pixels; // Holds LED color values
|
||||||
|
uint32_t _startTime; // Microsecond count when last update started
|
||||||
|
};
|
||||||
|
|
||||||
|
// NeoEsp8266AsyncUart handles all transmission asynchronously using interrupts
|
||||||
|
//
|
||||||
|
// This UART controller uses two buffers that are swapped in every call to
|
||||||
|
// NeoPixelBus.Show(). One buffer contains the data that is being sent
|
||||||
|
// asynchronosly and another buffer contains the data that will be send
|
||||||
|
// in the next call to NeoPixelBus.Show().
|
||||||
|
//
|
||||||
|
// Therefore, the result of NeoPixelBus.Pixels() is invalidated after
|
||||||
|
// every call to NeoPixelBus.Show() and must not be cached.
|
||||||
|
class NeoEsp8266AsyncUart: public NeoEsp8266Uart
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
NeoEsp8266AsyncUart(uint8_t pin, uint16_t pixelCount, size_t elementSize);
|
||||||
|
|
||||||
|
~NeoEsp8266AsyncUart();
|
||||||
|
|
||||||
|
void InitializeUart(uint32_t uartBaud);
|
||||||
|
|
||||||
|
void UpdateUart();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void ICACHE_RAM_ATTR IntrHandler(void* param);
|
||||||
|
|
||||||
|
uint8_t* _asyncPixels; // Holds a copy of LED color values taken when UpdateUart began
|
||||||
|
};
|
||||||
|
|
||||||
|
// NeoEsp8266UartSpeed800Kbps contains the timing constant used to get NeoPixelBus running at 800Khz
|
||||||
class NeoEsp8266UartSpeed800Kbps
|
class NeoEsp8266UartSpeed800Kbps
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800mhz speed
|
static const uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed
|
||||||
static const uint32_t UartBaud = 3200000; // 800mhz, 4 serial bytes per NeoByte
|
static const uint32_t UartBaud = 3200000; // 800mhz, 4 serial bytes per NeoByte
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NeoEsp8266UartSpeed800Kbps contains the timing constant used to get NeoPixelBus running at 400Khz
|
||||||
class NeoEsp8266UartSpeed400Kbps
|
class NeoEsp8266UartSpeed400Kbps
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400mhz speed
|
static const uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed
|
||||||
static const uint32_t UartBaud = 1600000; // 400mhz, 4 serial bytes per NeoByte
|
static const uint32_t UartBaud = 1600000; // 400mhz, 4 serial bytes per NeoByte
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UART1 1
|
// NeoEsp8266UartMethodBase is a light shell arround NeoEsp8266Uart or NeoEsp8266AsyncUart that
|
||||||
#define UART1_INV_MASK (0x3f << 19)
|
// implements the methods needed to operate as a NeoPixelBus method.
|
||||||
|
template<typename T_SPEED, typename T_BASE>
|
||||||
template<typename T_SPEED> class NeoEsp8266UartMethodBase
|
class NeoEsp8266UartMethodBase: public T_BASE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NeoEsp8266UartMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize)
|
NeoEsp8266UartMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize)
|
||||||
|
: T_BASE(pin, pixelCount, elementSize)
|
||||||
{
|
{
|
||||||
_sizePixels = pixelCount * elementSize;
|
|
||||||
_pixels = (uint8_t*)malloc(_sizePixels);
|
|
||||||
memset(_pixels, 0x00, _sizePixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
~NeoEsp8266UartMethodBase()
|
|
||||||
{
|
|
||||||
free(_pixels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsReadyToUpdate() const
|
bool IsReadyToUpdate() const
|
||||||
{
|
{
|
||||||
uint32_t delta = micros() - _endTime;
|
uint32_t delta = micros() - this->_startTime;
|
||||||
|
return delta >= getPixelTime() + 50;
|
||||||
return (delta >= 50L && delta <= (4294967296L - getPixelTime()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialize()
|
void Initialize()
|
||||||
{
|
{
|
||||||
Serial1.begin(T_SPEED::UartBaud, SERIAL_6N1, SERIAL_TX_ONLY);
|
this->InitializeUart(T_SPEED::UartBaud);
|
||||||
|
|
||||||
CLEAR_PERI_REG_MASK(UART_CONF0(UART1), UART1_INV_MASK);
|
// Inverting logic levels can generate a phantom bit in the led strip bus
|
||||||
SET_PERI_REG_MASK(UART_CONF0(UART1), (BIT(22)));
|
// We need to delay 50+ microseconds the output stream to force a data
|
||||||
|
// latch and discard this bit. Otherwise, that bit would be prepended to
|
||||||
_endTime = micros();
|
// the first frame corrupting it.
|
||||||
|
this->_startTime = micros() - getPixelTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
@@ -95,43 +127,34 @@ public:
|
|||||||
// subsequent round of data until the latch time has elapsed. This
|
// subsequent round of data until the latch time has elapsed. This
|
||||||
// allows the mainline code to start generating the next frame of data
|
// allows the mainline code to start generating the next frame of data
|
||||||
// rather than stalling for the latch.
|
// rather than stalling for the latch.
|
||||||
|
while (!this->IsReadyToUpdate())
|
||||||
while (!IsReadyToUpdate())
|
|
||||||
{
|
{
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
this->UpdateUart();
|
||||||
// since uart is async buffer send, we have to calc the endtime that it will take
|
|
||||||
// to correctly manage the data latch in the above code
|
|
||||||
// add the calculated time to the current time
|
|
||||||
_endTime = micros() + getPixelTime();
|
|
||||||
|
|
||||||
// esp hardware uart sending of data
|
|
||||||
esp8266_uart1_send_pixels(_pixels, _pixels + _sizePixels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* getPixels() const
|
uint8_t* getPixels() const
|
||||||
{
|
{
|
||||||
return _pixels;
|
return this->_pixels;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t getPixelsSize() const
|
size_t getPixelsSize() const
|
||||||
{
|
{
|
||||||
return _sizePixels;
|
return this->_sizePixels;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t getPixelTime() const
|
uint32_t getPixelTime() const
|
||||||
{
|
{
|
||||||
return (T_SPEED::ByteSendTimeUs * _sizePixels);
|
return (T_SPEED::ByteSendTimeUs * this->_sizePixels);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t _sizePixels; // Size of '_pixels' buffer below
|
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart> NeoEsp8266Uart800KbpsMethod;
|
||||||
uint8_t* _pixels; // Holds LED color values
|
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart> NeoEsp8266Uart400KbpsMethod;
|
||||||
uint32_t _endTime; // Latch timing reference
|
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart> NeoEsp8266AsyncUart800KbpsMethod;
|
||||||
};
|
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart> NeoEsp8266AsyncUart400KbpsMethod;
|
||||||
|
|
||||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps> NeoEsp8266Uart800KbpsMethod;
|
|
||||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps> NeoEsp8266Uart400KbpsMethod;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -29,31 +29,6 @@ License along with NeoPixel. If not, see
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <eagle_soc.h>
|
#include <eagle_soc.h>
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR esp8266_uart1_send_pixels(uint8_t* pixels, uint8_t* end)
|
|
||||||
{
|
|
||||||
const uint8_t _uartData[4] = { 0b00110111, 0b00000111, 0b00110100, 0b00000100 };
|
|
||||||
const uint8_t _uartFifoTrigger = 124; // tx fifo should be 128 bytes. minus the four we need to send
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint8_t subpix = *pixels++;
|
|
||||||
uint8_t buf[4] = { _uartData[(subpix >> 6) & 3],
|
|
||||||
_uartData[(subpix >> 4) & 3],
|
|
||||||
_uartData[(subpix >> 2) & 3],
|
|
||||||
_uartData[subpix & 3] };
|
|
||||||
|
|
||||||
// now wait till this the FIFO buffer has room to send more
|
|
||||||
while (((U1S >> USTXC) & 0xff) > _uartFifoTrigger);
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
// directly write the byte to transfer into the UART1 FIFO register
|
|
||||||
U1F = buf[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (pixels < end);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t _getCycleCount()
|
inline uint32_t _getCycleCount()
|
||||||
{
|
{
|
||||||
uint32_t ccount;
|
uint32_t ccount;
|
||||||
|
Reference in New Issue
Block a user