Tasmota/lib/lib_audio/ESP8266Audio/src/driver/SinglePinI2SDriver.h
2020-10-26 12:51:06 +00:00

86 lines
2.5 KiB
C++

/*
SinglePinI2SDriver
ESP8266Audio I2S Minimal driver
Copyright (C) 2020 Ivan Kostoski
This 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 2.1 of the License, or (at your option) any later version.
This library 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#if defined(ESP8266)
#include <Arduino.h>
#include "osapi.h"
#include "ets_sys.h"
#include "i2s_reg.h"
struct SLCDecriptor {
uint32_t blocksize : 12;
uint32_t datalen : 12;
uint32_t unused : 5;
uint32_t sub_sof : 1;
uint32_t eof : 1;
volatile uint32_t owner : 1;
uint32_t* buf_ptr;
SLCDecriptor* next_link_ptr;
};
class SinglePinI2SDriver
{
public:
enum : uint8_t { I2SO_DATA = 3 }; // GPIO3/RX0
SinglePinI2SDriver(): descriptors(NULL), bufCount(0), bufSize(0) {};
~SinglePinI2SDriver();
bool begin(uint8_t bufCount, uint16_t bufSize);
void stop();
void setRate(const uint32_t rateHz);
float getActualRate();
bool write(uint32_t sample);
bool writeInterleaved(uint32_t samples[4]);
int getUnderflowCount();
protected:
bool allocateBuffers();
void freeBuffers(int allocated);
void zeroBuffers();
void advanceHead(const SLCDecriptor *finished);
void configureSLC();
void stopSLC();
void setDividers(uint8_t div1, uint8_t div2);
void startI2S();
void stopI2S();
SLCDecriptor *descriptors;
uint16_t bufCount;
uint16_t bufSize;
SLCDecriptor *head;
uint32_t headPos;
uint32_t currentRate;
int underflowCount;
// (Re)Start transmission ("TX" DMA always needed to be enabled)
static inline void startSLC() { SLCTXL |= SLCTXLS; SLCRXL |= SLCRXLS; }
static inline uint32_t isSLCRunning() { return (SLCRXS & SLCRXF); };
static inline uint32_t isSLCStopped() { return (SLCRXS & SLCRXE); };
static inline SLCDecriptor *lastSentDescriptor() { return (SLCDecriptor*)SLCRXEDA; }
};
// Global instance
extern SinglePinI2SDriver I2SDriver;
#endif // defined(ESP8266)