Files
NeoPixelBus/src/internal/NeoEsp8266UartMethod.cpp
T

144 lines
4.4 KiB
C++
Raw Normal View History

/*-------------------------------------------------------------------------
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"
{
2018-12-23 14:30:01 -08:00
// #include <eagle_soc.h>
#include <ets_sys.h>
2018-12-23 14:30:01 -08:00
// #include <uart.h>
// #include <uart_register.h>
}
2018-12-23 14:30:01 -08:00
volatile NeoEsp8266UartInterruptContext* NeoEsp8266UartInterruptContext::s_uartInteruptContext[] = { nullptr, nullptr };
2018-12-23 14:30:01 -08:00
void NeoEsp8266UartInterruptContext::StartSending(uint8_t uartNum, uint8_t* start, uint8_t* end)
{
2018-12-23 14:30:01 -08:00
// send the pixels asynchronously
_asyncBuff = start;
_asyncBuffEnd = end;
// enable the transmit interrupt
USIE(uartNum) |= (1 << UIFE);
}
2018-12-23 14:30:01 -08:00
void NeoEsp8266UartInterruptContext::Attach(uint8_t uartNum)
{
// Disable all interrupts
ETS_UART_INTR_DISABLE();
// Clear the RX & TX FIFOS
2018-12-23 14:30:01 -08:00
const uint32_t fifoResetFlags = (1 << UCTXRST) | (1 << UCRXRST);
USC0(uartNum) |= fifoResetFlags;
USC0(uartNum) &= ~(fifoResetFlags);
2018-12-23 14:30:01 -08:00
// attach the ISR if needed
if (s_uartInteruptContext[0] == nullptr &&
s_uartInteruptContext[1] == nullptr)
{
ETS_UART_INTR_ATTACH(Isr, s_uartInteruptContext);
}
// attach the context
s_uartInteruptContext[uartNum] = this;
// Set tx fifo trigger. 80 bytes gives us 200 microsecs to refill the FIFO
2018-12-23 14:30:01 -08:00
USC1(uartNum) = (80 << UCFET);
2018-12-23 14:30:01 -08:00
// Disable RX & TX interrupts. It maybe still enabled by uart.c in the SDK
USIE(uartNum) &= ~((1 << UIFF) | (1 << UIFE));
// Clear all pending interrupts in UART1
2018-12-23 14:30:01 -08:00
USIC(uartNum) = 0xffff;
// Reenable interrupts
ETS_UART_INTR_ENABLE();
}
2018-12-23 14:30:01 -08:00
void NeoEsp8266UartInterruptContext::Detach(uint8_t uartNum)
{
2018-12-23 14:30:01 -08:00
// Disable interrupts
ETS_UART_INTR_DISABLE();
2018-12-23 14:30:01 -08:00
if (s_uartInteruptContext[uartNum] != nullptr)
{
2018-12-23 14:30:01 -08:00
// turn off uart
USC1(uartNum) = 0;
USIC(uartNum) = 0xffff;
USIE(uartNum) = 0;
s_uartInteruptContext[uartNum] = nullptr;
if (s_uartInteruptContext[0] == nullptr &&
s_uartInteruptContext[1] == nullptr)
{
2018-12-23 14:30:01 -08:00
// detach our ISR
ETS_UART_INTR_ATTACH(NULL, NULL);
// return so we don't enable interrupts since there is no ISR anymore
return;
}
}
2018-12-23 14:30:01 -08:00
// Reenable interrupts
ETS_UART_INTR_ENABLE();
}
void ICACHE_RAM_ATTR NeoEsp8266UartInterruptContext::Isr(void* param)
{
// make sure this is for us
if (param == s_uartInteruptContext)
{
2018-12-23 14:30:01 -08:00
// Interrupt handler is shared between UART0 & UART1
// so we need to test for both
for (uint8_t uartNum = 0; uartNum < 2; uartNum++)
{
if (USIS(uartNum) && s_uartInteruptContext[uartNum] != nullptr)
{
// Fill the FIFO with new data
s_uartInteruptContext[uartNum]->_asyncBuff = FillUartFifo(
uartNum,
s_uartInteruptContext[uartNum]->_asyncBuff,
s_uartInteruptContext[uartNum]->_asyncBuffEnd);
// Disable TX interrupt when done
if (s_uartInteruptContext[uartNum]->_asyncBuff == s_uartInteruptContext[uartNum]->_asyncBuffEnd)
{
// clear the TX FIFO Empty
USIE(uartNum) &= ~(1 << UIFE);
}
// Clear all interrupts flags (just in case)
USIC(uartNum) = 0xffff;
}
}
}
}
#endif