working audio
This commit is contained in:
577
FW/leo_muziekdoos_sam51/lib/I2S/I2S.cpp
Normal file
577
FW/leo_muziekdoos_sam51/lib/I2S/I2S.cpp
Normal file
@@ -0,0 +1,577 @@
|
||||
/*!
|
||||
* @file Adafruit_ZeroI2S.cpp
|
||||
*
|
||||
* @mainpage Adafruit I2S peripheral driver for SAMD21 and SAMD51 chips
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
* I2S peripheral driver for SAMD21 and SAMD51 chips
|
||||
*
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Dean Miller for Adafruit Industries.
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* BSD license, all text here must be included in any redistribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "I2S.h"
|
||||
#include "wiring_private.h"
|
||||
|
||||
#ifndef DEBUG_PRINTLN
|
||||
#define DEBUG_PRINTLN Serial.println ///< where to print the debug output
|
||||
#endif
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Class Constructor
|
||||
@param FS_PIN frame sync pin
|
||||
@param SCK_PIN bit clock pin
|
||||
@param TX_PIN data output pin
|
||||
@param RX_PIN data input pin
|
||||
*/
|
||||
/**************************************************************************/
|
||||
I2S_class::I2S_class(uint8_t FS_PIN, uint8_t SCK_PIN,
|
||||
uint8_t TX_PIN, uint8_t RX_PIN)
|
||||
: _fs(FS_PIN), _sck(SCK_PIN), _tx(TX_PIN), _rx(RX_PIN) {}
|
||||
|
||||
#if defined(PIN_I2S_SDI) && defined(PIN_I2S_SDO)
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Class Constructor with defaults
|
||||
*/
|
||||
/**************************************************************************/
|
||||
I2S_class::I2S_class()
|
||||
: _fs(PIN_I2S_FS), _sck(PIN_I2S_SCK), _tx(PIN_I2S_SDO), _rx(PIN_I2S_SDI) {}
|
||||
#else
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Class Constructor with defaults
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_ZeroI2S::Adafruit_ZeroI2S()
|
||||
: _fs(PIN_I2S_FS), _sck(PIN_I2S_SCK), _tx(PIN_I2S_SD) {
|
||||
_rx = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief start up the I2S peripheral
|
||||
@param width the width of each I2S frame
|
||||
@param fs_freq the frame sync frequency (a.k.a. sample rate)
|
||||
@param mck_mult master clock output will be fs_freq * mck_mult for chips
|
||||
that have a mclk.
|
||||
@returns true on success, false on any error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool I2S_class::begin(I2SSlotSize width, int fs_freq, int mck_mult) {
|
||||
#if defined(__SAMD51__)
|
||||
|
||||
pinPeripheral(_fs, PIO_I2S);
|
||||
pinPeripheral(_sck, PIO_I2S);
|
||||
pinPeripheral(_rx, PIO_I2S);
|
||||
pinPeripheral(_tx, PIO_I2S);
|
||||
|
||||
I2S->CTRLA.bit.ENABLE = 0;
|
||||
|
||||
// initialize clock control
|
||||
MCLK->APBDMASK.reg |= MCLK_APBDMASK_I2S;
|
||||
|
||||
uint32_t mckFreq = (fs_freq * mck_mult);
|
||||
uint32_t sckFreq = fs_freq * I2S_NUM_SLOTS * ((width + 1) << 3);
|
||||
|
||||
uint32_t gclkval = GCLK_PCHCTRL_GEN_GCLK1_Val;
|
||||
uint32_t gclkFreq = VARIANT_GCLK1_FREQ;
|
||||
uint8_t mckoutdiv = min((gclkFreq / mckFreq) - 1U, 63U);
|
||||
uint8_t mckdiv = min((gclkFreq / sckFreq) - 1U, 63U);
|
||||
|
||||
if (((VARIANT_GCLK1_FREQ / mckFreq) - 1) > 63) {
|
||||
gclkval = GCLK_PCHCTRL_GEN_GCLK4_Val;
|
||||
gclkFreq = 12000000;
|
||||
}
|
||||
|
||||
GCLK->PCHCTRL[I2S_GCLK_ID_0].reg = gclkval | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
GCLK->PCHCTRL[I2S_GCLK_ID_1].reg = gclkval | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||
|
||||
// software reset
|
||||
I2S->CTRLA.bit.SWRST = 1;
|
||||
while (I2S->SYNCBUSY.bit.SWRST || I2S->SYNCBUSY.bit.ENABLE)
|
||||
; // wait for sync
|
||||
|
||||
// CLKCTRL[0] is used for the tx channel
|
||||
I2S->CLKCTRL[0].reg =
|
||||
I2S_CLKCTRL_MCKSEL_GCLK | I2S_CLKCTRL_MCKOUTDIV(mckoutdiv) |
|
||||
I2S_CLKCTRL_MCKDIV(mckdiv) | I2S_CLKCTRL_SCKSEL_MCKDIV |
|
||||
I2S_CLKCTRL_MCKEN | I2S_CLKCTRL_FSSEL_SCKDIV | I2S_CLKCTRL_BITDELAY_I2S |
|
||||
I2S_CLKCTRL_FSWIDTH_HALF | I2S_CLKCTRL_NBSLOTS(I2S_NUM_SLOTS - 1) |
|
||||
I2S_CLKCTRL_SLOTSIZE(width);
|
||||
|
||||
uint8_t wordSize=0;
|
||||
|
||||
switch (width) {
|
||||
case I2S_8_BIT:
|
||||
wordSize = I2S_TXCTRL_DATASIZE_8_Val;
|
||||
break;
|
||||
case I2S_16_BIT:
|
||||
wordSize = I2S_TXCTRL_DATASIZE_16_Val;
|
||||
break;
|
||||
case I2S_24_BIT:
|
||||
wordSize = I2S_TXCTRL_DATASIZE_24_Val;
|
||||
break;
|
||||
case I2S_32_BIT:
|
||||
wordSize = I2S_TXCTRL_DATASIZE_32_Val;
|
||||
break;
|
||||
}
|
||||
|
||||
I2S->TXCTRL.reg = I2S_TXCTRL_DMA_SINGLE | I2S_TXCTRL_MONO_STEREO |
|
||||
I2S_TXCTRL_BITREV_MSBIT | I2S_TXCTRL_EXTEND_ZERO |
|
||||
I2S_TXCTRL_WORDADJ_RIGHT | I2S_TXCTRL_DATASIZE(wordSize) |
|
||||
I2S_TXCTRL_TXSAME_ZERO | I2S_TXCTRL_TXDEFAULT_ZERO;
|
||||
|
||||
I2S->RXCTRL.reg = I2S_RXCTRL_DMA_SINGLE | I2S_RXCTRL_MONO_STEREO |
|
||||
I2S_RXCTRL_BITREV_MSBIT | I2S_RXCTRL_EXTEND_ZERO |
|
||||
I2S_RXCTRL_WORDADJ_RIGHT | I2S_RXCTRL_DATASIZE(wordSize) |
|
||||
I2S_RXCTRL_SLOTADJ_RIGHT | I2S_RXCTRL_CLKSEL_CLK0 |
|
||||
I2S_RXCTRL_SERMODE_RX;
|
||||
|
||||
while (I2S->SYNCBUSY.bit.ENABLE)
|
||||
; // wait for sync
|
||||
I2S->CTRLA.bit.ENABLE = 1;
|
||||
|
||||
return true;
|
||||
|
||||
#else // SAMD21
|
||||
_i2sserializer = -1;
|
||||
_i2sclock = -1;
|
||||
uint32_t _clk_pin, _clk_mux, _data_pin, _data_mux, _fs_pin, _fs_mux;
|
||||
|
||||
// Clock pin, can only be one of 3 options
|
||||
uint32_t clockport = g_APinDescription[_sck].ulPort;
|
||||
uint32_t clockpin = g_APinDescription[_sck].ulPin;
|
||||
if ((clockport == 0) && (clockpin == 10)) {
|
||||
// PA10
|
||||
_i2sclock = 0;
|
||||
_clk_pin = PIN_PA10G_I2S_SCK0;
|
||||
_clk_mux = MUX_PA10G_I2S_SCK0;
|
||||
#if defined(PIN_PB11G_I2S_SCK1)
|
||||
} else if ((clockport == 1) && (clockpin == 11)) {
|
||||
// PB11
|
||||
_i2sclock = 1;
|
||||
_clk_pin = PIN_PB11G_I2S_SCK1;
|
||||
_clk_mux = MUX_PB11G_I2S_SCK1;
|
||||
#endif
|
||||
#if defined(PIN_PA20G_I2S_SCK0)
|
||||
} else if ((clockport == 0) && (clockpin == 20)) {
|
||||
// PA20
|
||||
_i2sclock = 0;
|
||||
_clk_pin = PIN_PA20G_I2S_SCK0;
|
||||
_clk_mux = MUX_PA20G_I2S_SCK0;
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_PRINTLN("Clock isnt on a valid pin");
|
||||
return false;
|
||||
}
|
||||
pinPeripheral(_sck, (EPioType)_clk_mux);
|
||||
|
||||
// FS pin, can only be one of 2 options
|
||||
uint32_t fsport = g_APinDescription[_fs].ulPort;
|
||||
uint32_t fspin = g_APinDescription[_fs].ulPin;
|
||||
if ((fsport == 0) && (fspin == 11)) {
|
||||
// PA11
|
||||
_fs_pin = PIN_PA11G_I2S_FS0;
|
||||
_fs_mux = MUX_PA11G_I2S_FS0;
|
||||
#if defined(PIN_PA21G_I2S_FS0)
|
||||
} else if ((fsport == 0) && (fspin == 21)) {
|
||||
// PA21
|
||||
_fs_pin = PIN_PA21G_I2S_FS0;
|
||||
_fs_mux = MUX_PA21G_I2S_FS0;
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_PRINTLN("FS isnt on a valid pin");
|
||||
return false;
|
||||
}
|
||||
pinPeripheral(_fs, (EPioType)_fs_mux);
|
||||
|
||||
uint32_t i2sGCLK;
|
||||
if (_i2sclock == 0)
|
||||
i2sGCLK = I2S_GCLK_ID_0;
|
||||
else
|
||||
i2sGCLK = I2S_GCLK_ID_1;
|
||||
|
||||
uint32_t divider = fs_freq * 2 * (width + 1) * 8;
|
||||
// configure the clock divider
|
||||
while (GCLK->STATUS.bit.SYNCBUSY)
|
||||
;
|
||||
GCLK->GENDIV.bit.ID = I2S_CLOCK_GENERATOR;
|
||||
GCLK->GENDIV.bit.DIV = SystemCoreClock / divider;
|
||||
|
||||
// use the DFLL as the source
|
||||
while (GCLK->STATUS.bit.SYNCBUSY)
|
||||
;
|
||||
GCLK->GENCTRL.bit.ID = I2S_CLOCK_GENERATOR;
|
||||
GCLK->GENCTRL.bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val;
|
||||
GCLK->GENCTRL.bit.IDC = 1;
|
||||
GCLK->GENCTRL.bit.GENEN = 1;
|
||||
|
||||
// enable
|
||||
while (GCLK->STATUS.bit.SYNCBUSY)
|
||||
;
|
||||
GCLK->CLKCTRL.bit.ID = i2sGCLK;
|
||||
GCLK->CLKCTRL.bit.GEN = I2S_CLOCK_GENERATOR;
|
||||
GCLK->CLKCTRL.bit.CLKEN = 1;
|
||||
|
||||
while (GCLK->STATUS.bit.SYNCBUSY)
|
||||
;
|
||||
|
||||
// Data pin, can only be one of 3 options
|
||||
uint32_t datapin = g_APinDescription[_tx].ulPin;
|
||||
uint32_t dataport = g_APinDescription[_tx].ulPort;
|
||||
if ((dataport == 0) && (datapin == 7)) {
|
||||
// PA07
|
||||
_i2sserializer = 0;
|
||||
_data_pin = PIN_PA07G_I2S_SD0;
|
||||
_data_mux = MUX_PA07G_I2S_SD0;
|
||||
} else if ((dataport == 0) && (datapin == 8)) {
|
||||
// PA08
|
||||
_i2sserializer = 1;
|
||||
_data_pin = PIN_PA08G_I2S_SD1;
|
||||
_data_mux = MUX_PA08G_I2S_SD1;
|
||||
} else if ((dataport == 0) && (datapin == 19)) {
|
||||
// PA19
|
||||
_i2sserializer = 0;
|
||||
_data_pin = PIN_PA19G_I2S_SD0;
|
||||
_data_mux = MUX_PA19G_I2S_SD0;
|
||||
} else {
|
||||
DEBUG_PRINTLN("Data isnt on a valid pin");
|
||||
return false;
|
||||
}
|
||||
pinPeripheral(_tx, (EPioType)_data_mux);
|
||||
|
||||
PM->APBCMASK.reg |= PM_APBCMASK_I2S;
|
||||
|
||||
I2S->CTRLA.bit.ENABLE = 0;
|
||||
while (I2S->SYNCBUSY.bit.ENABLE)
|
||||
;
|
||||
|
||||
if (_i2sclock == 0)
|
||||
I2S->CTRLA.bit.CKEN0 = 0;
|
||||
else
|
||||
I2S->CTRLA.bit.CKEN1 = 0;
|
||||
while (I2S->SYNCBUSY.bit.CKEN0 || I2S->SYNCBUSY.bit.CKEN1)
|
||||
;
|
||||
|
||||
I2S->CLKCTRL[_i2sclock].reg =
|
||||
I2S_CLKCTRL_MCKSEL_GCLK | I2S_CLKCTRL_SCKSEL_MCKDIV |
|
||||
I2S_CLKCTRL_FSSEL_SCKDIV | I2S_CLKCTRL_BITDELAY_I2S |
|
||||
I2S_CLKCTRL_NBSLOTS(I2S_NUM_SLOTS - 1) | I2S_CLKCTRL_SLOTSIZE(width);
|
||||
|
||||
uint8_t wordSize;
|
||||
switch (width) {
|
||||
case I2S_8_BIT:
|
||||
wordSize = I2S_SERCTRL_DATASIZE_8_Val;
|
||||
break;
|
||||
case I2S_16_BIT:
|
||||
wordSize = I2S_SERCTRL_DATASIZE_16_Val;
|
||||
break;
|
||||
case I2S_24_BIT:
|
||||
wordSize = I2S_SERCTRL_DATASIZE_24_Val;
|
||||
break;
|
||||
case I2S_32_BIT:
|
||||
wordSize = I2S_SERCTRL_DATASIZE_32_Val;
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTLN("invalid width!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_i2sserializer == 0)
|
||||
I2S->CTRLA.bit.SEREN0 = 0;
|
||||
else
|
||||
I2S->CTRLA.bit.SEREN1 = 0;
|
||||
while (I2S->SYNCBUSY.bit.SEREN0 || I2S->SYNCBUSY.bit.SEREN1)
|
||||
;
|
||||
|
||||
I2S->SERCTRL[_i2sserializer].reg =
|
||||
I2S_SERCTRL_DMA_SINGLE | I2S_SERCTRL_MONO_STEREO |
|
||||
I2S_SERCTRL_BITREV_MSBIT | I2S_SERCTRL_EXTEND_ZERO |
|
||||
I2S_SERCTRL_WORDADJ_RIGHT | I2S_SERCTRL_DATASIZE(wordSize) |
|
||||
I2S_SERCTRL_SLOTADJ_RIGHT |
|
||||
((uint32_t)_i2sclock << I2S_SERCTRL_CLKSEL_Pos);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief enable data output. Note that on SAMD21 chips either rx or tx can be
|
||||
enabled on an Adafruit_ZeroI2S instance, while on SAMD51 the same
|
||||
Adafruit_ZeroI2S instance can have both rx and tx channels enabled.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void I2S_class::enableTx() {
|
||||
#if defined(__SAMD51__)
|
||||
I2S->CTRLA.bit.CKEN0 = 1;
|
||||
while (I2S->SYNCBUSY.bit.CKEN0)
|
||||
;
|
||||
|
||||
I2S->CTRLA.bit.TXEN = 1;
|
||||
while (I2S->SYNCBUSY.bit.TXEN)
|
||||
;
|
||||
#else
|
||||
if (_i2sserializer > -1 && _i2sclock > -1) {
|
||||
I2S->CTRLA.bit.ENABLE = 0;
|
||||
while (I2S->SYNCBUSY.bit.ENABLE)
|
||||
;
|
||||
|
||||
I2S->SERCTRL[_i2sserializer].bit.SERMODE = I2S_SERCTRL_SERMODE_TX;
|
||||
|
||||
if (_i2sserializer == 0)
|
||||
I2S->CTRLA.bit.SEREN0 = 1;
|
||||
else
|
||||
I2S->CTRLA.bit.SEREN1 = 1;
|
||||
|
||||
if (_i2sclock == 0)
|
||||
I2S->CTRLA.bit.CKEN0 = 1;
|
||||
else
|
||||
I2S->CTRLA.bit.CKEN1 = 1;
|
||||
|
||||
I2S->CTRLA.bit.ENABLE = 1;
|
||||
while (I2S->SYNCBUSY.bit.ENABLE || I2S->SYNCBUSY.bit.CKEN0 ||
|
||||
I2S->SYNCBUSY.bit.CKEN1 || I2S->SYNCBUSY.bit.SEREN0 ||
|
||||
I2S->SYNCBUSY.bit.SEREN1)
|
||||
;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief disable data output
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void I2S_class::disableTx() {
|
||||
#if defined(__SAMD51__)
|
||||
I2S->CTRLA.bit.TXEN = 0;
|
||||
while (I2S->SYNCBUSY.bit.TXEN)
|
||||
;
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief enable data input. Note that on SAMD21 chips either rx or tx can be
|
||||
enabled on an Adafruit_ZeroI2S instance, while on SAMD51 the same
|
||||
Adafruit_ZeroI2S instance can have both rx and tx channels enabled.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void I2S_class::enableRx() {
|
||||
#if defined(__SAMD51__)
|
||||
I2S->CTRLA.bit.CKEN0 = 1;
|
||||
while (I2S->SYNCBUSY.bit.CKEN0)
|
||||
;
|
||||
|
||||
I2S->CTRLA.bit.RXEN = 1;
|
||||
while (I2S->SYNCBUSY.bit.RXEN)
|
||||
;
|
||||
#else
|
||||
if (_i2sserializer > -1 && _i2sclock > -1) {
|
||||
I2S->CTRLA.bit.ENABLE = 0;
|
||||
while (I2S->SYNCBUSY.bit.ENABLE)
|
||||
;
|
||||
|
||||
I2S->SERCTRL[_i2sserializer].bit.SERMODE = I2S_SERCTRL_SERMODE_RX;
|
||||
|
||||
if (_i2sserializer == 0)
|
||||
I2S->CTRLA.bit.SEREN0 = 1;
|
||||
else
|
||||
I2S->CTRLA.bit.SEREN1 = 1;
|
||||
|
||||
if (_i2sclock == 0)
|
||||
I2S->CTRLA.bit.CKEN0 = 1;
|
||||
else
|
||||
I2S->CTRLA.bit.CKEN1 = 1;
|
||||
|
||||
I2S->CTRLA.bit.ENABLE = 1;
|
||||
while (I2S->SYNCBUSY.bit.ENABLE || I2S->SYNCBUSY.bit.CKEN0 ||
|
||||
I2S->SYNCBUSY.bit.CKEN1 || I2S->SYNCBUSY.bit.SEREN0 ||
|
||||
I2S->SYNCBUSY.bit.SEREN1)
|
||||
;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief disable data input
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void I2S_class::disableRx() {
|
||||
#if defined(__SAMD51__)
|
||||
I2S->CTRLA.bit.RXEN = 0;
|
||||
while (I2S->SYNCBUSY.bit.RXEN)
|
||||
;
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief enable master clock output on devices that have a master clock
|
||||
output.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void I2S_class::enableMCLK() {
|
||||
#ifdef PIN_I2S_MCK
|
||||
pinPeripheral(PIN_I2S_MCK, PIO_I2S);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief disable master clock output on devices that have a master clock
|
||||
output.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void I2S_class::disableMCLK() {
|
||||
#ifdef PIN_I2S_MCK
|
||||
pinMode(PIN_I2S_MCK, INPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief check if data can be written to the TX data register
|
||||
@returns true if data can be written, false otherwise
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool I2S_class::txReady() {
|
||||
#if defined(__SAMD51__)
|
||||
return !((!I2S->INTFLAG.bit.TXRDY0) || I2S->SYNCBUSY.bit.TXDATA);
|
||||
#else
|
||||
if (_i2sserializer > -1) {
|
||||
if (_i2sserializer == 0) {
|
||||
return !((!I2S->INTFLAG.bit.TXRDY0) || I2S->SYNCBUSY.bit.DATA0);
|
||||
} else {
|
||||
return !((!I2S->INTFLAG.bit.TXRDY1) || I2S->SYNCBUSY.bit.DATA1);
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief check if data is available to be read from the RX data register
|
||||
@returns true if data is available, false otherwise
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool I2S_class::rxReady() {
|
||||
#if defined(__SAMD51__)
|
||||
return !((!I2S->INTFLAG.bit.RXRDY0) || I2S->SYNCBUSY.bit.RXDATA);
|
||||
#else
|
||||
if (_i2sserializer > -1) {
|
||||
if (_i2sserializer == 0) {
|
||||
return !((!I2S->INTFLAG.bit.RXRDY0) || I2S->SYNCBUSY.bit.DATA0);
|
||||
} else {
|
||||
return !((!I2S->INTFLAG.bit.RXRDY1) || I2S->SYNCBUSY.bit.DATA1);
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief perform a blocking write to the I2S peripheral. This function will
|
||||
only return once all data has been sent.
|
||||
@param left the left channel data
|
||||
@param right the right channel data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void I2S_class::write(int32_t left, int32_t right) {
|
||||
#if defined(__SAMD51__)
|
||||
while ((!I2S->INTFLAG.bit.TXRDY0) || I2S->SYNCBUSY.bit.TXDATA)
|
||||
;
|
||||
I2S->INTFLAG.bit.TXUR0 = 1;
|
||||
I2S->TXDATA.reg = left;
|
||||
|
||||
while ((!I2S->INTFLAG.bit.TXRDY0) || I2S->SYNCBUSY.bit.TXDATA)
|
||||
;
|
||||
I2S->INTFLAG.bit.TXUR0 = 1;
|
||||
I2S->TXDATA.reg = right;
|
||||
#else
|
||||
if (_i2sserializer > -1) {
|
||||
if (_i2sserializer == 0) {
|
||||
while ((!I2S->INTFLAG.bit.TXRDY0) || I2S->SYNCBUSY.bit.DATA0)
|
||||
;
|
||||
I2S->INTFLAG.bit.TXUR0 = 1;
|
||||
I2S->DATA[0].reg = left;
|
||||
|
||||
while ((!I2S->INTFLAG.bit.TXRDY0) || I2S->SYNCBUSY.bit.DATA0)
|
||||
;
|
||||
I2S->INTFLAG.bit.TXUR0 = 1;
|
||||
I2S->DATA[0].reg = right;
|
||||
} else {
|
||||
while ((!I2S->INTFLAG.bit.TXRDY1) || I2S->SYNCBUSY.bit.DATA1)
|
||||
;
|
||||
I2S->INTFLAG.bit.TXUR1 = 1;
|
||||
I2S->DATA[1].reg = left;
|
||||
|
||||
while ((!I2S->INTFLAG.bit.TXRDY1) || I2S->SYNCBUSY.bit.DATA1)
|
||||
;
|
||||
I2S->INTFLAG.bit.TXUR1 = 1;
|
||||
I2S->DATA[1].reg = right;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief perform a blocking read to the I2S peripheral. This function will
|
||||
only return once all data has been read.
|
||||
@param left pointer to where the left channel data will be written
|
||||
@param right pointer to where the right channel data will be written
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void I2S_class::read(int32_t *left, int32_t *right) {
|
||||
#if defined(__SAMD51__)
|
||||
while ((!I2S->INTFLAG.bit.RXRDY0) || I2S->SYNCBUSY.bit.RXDATA)
|
||||
;
|
||||
*left = I2S->RXDATA.reg;
|
||||
|
||||
while ((!I2S->INTFLAG.bit.RXRDY0) || I2S->SYNCBUSY.bit.RXDATA)
|
||||
;
|
||||
*right = I2S->RXDATA.reg;
|
||||
#else
|
||||
if (_i2sserializer > -1) {
|
||||
if (_i2sserializer == 0) {
|
||||
while ((!I2S->INTFLAG.bit.RXRDY0) || I2S->SYNCBUSY.bit.DATA0)
|
||||
;
|
||||
*left = I2S->DATA[0].reg;
|
||||
|
||||
while ((!I2S->INTFLAG.bit.RXRDY0) || I2S->SYNCBUSY.bit.DATA0)
|
||||
;
|
||||
*right = I2S->DATA[0].reg;
|
||||
} else {
|
||||
while ((!I2S->INTFLAG.bit.RXRDY1) || I2S->SYNCBUSY.bit.DATA1)
|
||||
;
|
||||
*left = I2S->DATA[1].reg;
|
||||
|
||||
while ((!I2S->INTFLAG.bit.RXRDY1) || I2S->SYNCBUSY.bit.DATA1)
|
||||
;
|
||||
*right = I2S->DATA[1].reg;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
75
FW/leo_muziekdoos_sam51/lib/I2S/I2S.h
Normal file
75
FW/leo_muziekdoos_sam51/lib/I2S/I2S.h
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
/*!
|
||||
* @file Adafruit_ZeroI2S.h
|
||||
*
|
||||
* This is a library for the I2S peripheral on SAMD21 and SAMD51 devices
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* Written by Dean Miller for Adafruit Industries.
|
||||
*
|
||||
* BSD license, all text here must be included in any redistribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ADAFRUIT_ZEROI2S_H
|
||||
#define ADAFRUIT_ZEROI2S_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief available I2S slot sizes
|
||||
*/
|
||||
/**************************************************************************/
|
||||
typedef enum _I2SSlotSize {
|
||||
I2S_8_BIT = 0,
|
||||
I2S_16_BIT,
|
||||
I2S_24_BIT,
|
||||
I2S_32_BIT
|
||||
} I2SSlotSize;
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief number of I2S slots to use (stereo)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#define I2S_NUM_SLOTS 2
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Class that stores state and functions for interacting with I2S
|
||||
peripheral on SAMD21 and SAMD51 devices
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class I2S_class {
|
||||
public:
|
||||
I2S_class(uint8_t FS_PIN, uint8_t SCK_PIN, uint8_t TX_PIN,
|
||||
uint8_t RX_PIN);
|
||||
I2S_class();
|
||||
~I2S_class() {}
|
||||
|
||||
bool begin(I2SSlotSize width, int fs_freq, int mck_mult = 256);
|
||||
|
||||
void enableTx();
|
||||
void disableTx();
|
||||
void enableRx();
|
||||
void disableRx();
|
||||
void enableMCLK();
|
||||
void disableMCLK();
|
||||
|
||||
bool txReady();
|
||||
bool rxReady();
|
||||
void write(int32_t left, int32_t right);
|
||||
void read(int32_t *left, int32_t *right);
|
||||
|
||||
private:
|
||||
int8_t _fs, _sck, _tx, _rx;
|
||||
#ifndef __SAMD51__
|
||||
int8_t _i2sserializer, _i2sclock;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user