diff --git a/libraries/CurieAudio/examples/tone_generator/tone_generator.ino b/libraries/CurieAudio/examples/tone_generator/tone_generator.ino new file mode 100755 index 00000000..9aa1a870 --- /dev/null +++ b/libraries/CurieAudio/examples/tone_generator/tone_generator.ino @@ -0,0 +1,232 @@ +// Arduino Zero / Feather M0 I2S audio tone generation example. +// Author: Tony DiCola +// +// Connect an I2S DAC or amp (like the MAX98357) to the Arduino Zero +// and play back simple sine, sawtooth, triangle, and square waves. +// Makes your Zero sound like a NES! +// +// NOTE: The I2S signal generated by the Zero does NOT have a MCLK / +// master clock signal. You must use an I2S receiver that can operate +// without a MCLK signal (like the MAX98357). +// +// For an Arduino Zero / Feather M0 connect it to you I2S hardware as follows: +// - Digital 0 -> I2S LRCLK / FS (left/right / frame select clock) +// - Digital 1 -> I2S BCLK / SCLK (bit / serial clock) +// - Digital 9 -> I2S DIN / SD (data output) +// - Ground +// +// Depends on the Adafruit_ASFcore library from: +// https://github.com/adafruit/adafruit_asfcore +// +// Released under a MIT license: https://opensource.org/licenses/MIT + + +#ifdef ARDUINO_ARCH_ARC32 +#include +#else +#include "Adafruit_ASFcore.h" +#include "Adafruit_ZeroI2S.h" +#endif + + +#ifdef ARDUINO_ARCH_ARC32 +#define SAMPLE_RATE I2S_22KHZ +#endif + +#define SAMPLERATE_HZ 22000 // The sample rate of the audio. Higher sample rates have better fidelity, + // but these tones are so simple it won't make a difference. 44.1khz is + // standard CD quality sound. + +#define AMPLITUDE 10000000 // Set the amplitude of generated waveforms. This controls how loud + // the signals are, and can be any value from 0 to 65535. Start with + // a low value like 5000 or less to prevent damaging speakers! + +#define WAV_SIZE 256 // The size of each generated waveform. The larger the size the higher + // quality the signal. A size of 256 is more than enough for these simple + // waveforms. + + +// Define the frequency of music notes (from http://www.phy.mtu.edu/~suits/notefreqs.html): +#define C4_HZ 261.63 +#define D4_HZ 293.66 +#define E4_HZ 329.63 +#define F4_HZ 349.23 +#define G4_HZ 392.00 +#define A4_HZ 440.00 +#define B4_HZ 493.88 + +// Define a C-major scale to play all the notes up and down. +float scale[] = { C4_HZ, D4_HZ, E4_HZ, F4_HZ, G4_HZ, A4_HZ, B4_HZ, A4_HZ, G4_HZ, F4_HZ, E4_HZ, D4_HZ, C4_HZ }; + +// Store basic waveforms in memory. +int32_t sine[WAV_SIZE] = {0}; +int32_t sawtooth[WAV_SIZE] = {0}; +int32_t triangle[WAV_SIZE] = {0}; +int32_t square[WAV_SIZE] = {0}; + +#ifndef ARDUINO_ARCH_ARC32 +/*********************** +// Create I2S audio transmitter object. +Adafruit_ZeroI2S_TX i2s = Adafruit_ZeroI2S_TX(); +***********************/ +//// I2S audio transmitter object has been defined in the CurieI2S file + +// Little define to make the native USB port on the Arduino Zero / Zero feather +// the default for serial output. +#define Serial SerialUSB +#endif + + +void generateSine(int32_t amplitude, int32_t* buffer, uint16_t length) { + // Generate a sine wave signal with the provided amplitude and store it in + // the provided buffer of size length. + for (int i=0; i=1.6.3) diff --git a/libraries/CurieAudio/src/I2SController.cpp b/libraries/CurieAudio/src/I2SController.cpp new file mode 100644 index 00000000..60d0945e --- /dev/null +++ b/libraries/CurieAudio/src/I2SController.cpp @@ -0,0 +1,80 @@ +//*************************************************************** +// +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// +// 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 Street, Fifth Floor, Boston, MA 02110-1301 USA +// +//*************************************************************** + +#include "I2SController.h" +#include "variant.h" + +uint16_t sampleRateLookupTable[MAX_I2S_SIZE][MAX_I2S_RATE] = { + // 8K 12k 22k 24k 44k 48k + { 125, 83, 45, 42, 23, 21}, // I2S_16bit + { 83, 56, 30, 28, 15, 14}, // I2S_24bit + { 63, 42, 23, 21, 11, 10} // I2S_32bit +}; + +uint8_t sampleSizeLookupTable[MAX_I2S_SIZE] = {16, 24, 32}; + + +I2SController::I2SController() +{ + sampleRateMap = (uint16_t *)sampleRateLookupTable; + sampleSizeMap = sampleSizeLookupTable; +} + + +void I2SController::muxTX(bool enable) +{ + int mux_mode = GPIO_MUX_MODE; + if(enable) + { + mux_mode = I2S_MUX_MODE; + } + + /* Set SoC pin mux configuration */ + SET_PIN_MODE(g_APinDescription[I2S_TXD].ulSocPin, mux_mode); + SET_PIN_MODE(g_APinDescription[I2S_TWS].ulSocPin, mux_mode); + SET_PIN_MODE(g_APinDescription[I2S_TSCK].ulSocPin, mux_mode); + + // g_APinDescription is residing in ROM now, no update to the structure + // g_APinDescription[I2S_TXD].ulPinMode = mux_mode; + // g_APinDescription[I2S_TWS].ulPinMode = mux_mode; + // g_APinDescription[I2S_TSCK].ulPinMode = mux_mode; +} + + +void I2SController::muxRX(bool enable) +{ + int mux_mode = GPIO_MUX_MODE; + if(enable) + { + mux_mode = I2S_MUX_MODE; + } + + /* Set SoC pin mux configuration */ + SET_PIN_MODE(49, mux_mode); //I2S_RXD + SET_PIN_MODE(51, mux_mode); //I2S_RWS + SET_PIN_MODE(50, mux_mode); //I2S_RSCK + + // g_APinDescription is residing in ROM now, no update to the structure + // g_APinDescription[I2S_RXD].ulPinMode = mux_mode; + // g_APinDescription[I2S_RWS].ulPinMode = mux_mode; + // g_APinDescription[I2S_RSCK].ulPinMode = mux_mode; +} + + diff --git a/libraries/CurieAudio/src/I2SController.h b/libraries/CurieAudio/src/I2SController.h new file mode 100644 index 00000000..4deb45ad --- /dev/null +++ b/libraries/CurieAudio/src/I2SController.h @@ -0,0 +1,109 @@ +//*************************************************************** +// +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// +// 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 Street, Fifth Floor, Boston, MA 02110-1301 USA +// +//*************************************************************** + +#ifndef _I2S_CONTROLLER_H_ +#define _I2S_CONTROLLER_H_ + +#include + +// The following Arduino 101 pins are used for I2S Transmit (Tx) interface. +#define I2S_TXD 7 // Data +#define I2S_TWS 4 // Word Select +#define I2S_TSCK 2 // Clock + +// The following Arduino 101 pins are used for I2S Receive (Rx) interface. +#define I2S_RXD 5 +#define I2S_RWS 3 +#define I2S_RSCK 8 + +// These modes are suppported by the Curie I2S: I2S_MODE_PHILLIPS, +// I2S_MODE_RJ (right justified), I2S_MODE_LJ (left jst), I2S_MODE_DSP. +#define I2S_MODE_SCK_POL (0x01) +#define I2S_MODE_WS_POL (0x02) +#define I2S_MODE_LR_ALIGN (0x08) +#define I2S_MODE_SAMPLE_DEL (0x10) +#define I2S_MODE_WS_DSP (0x20) + +typedef enum { + I2S_MODE_PHILLIPS = (I2S_MODE_LR_ALIGN), + I2S_MODE_RJ = (I2S_MODE_WS_POL | I2S_MODE_SAMPLE_DEL), + I2S_MODE_LJ = (I2S_MODE_WS_POL | I2S_MODE_LR_ALIGN | I2S_MODE_SAMPLE_DEL), + I2S_MODE_DSP = (I2S_MODE_LR_ALIGN | I2S_MODE_WS_DSP) +} curieI2sMode; + +// These are the supported sampling rate for the Curie I2s interface. +typedef enum { + I2S_8KHZ = 0, + I2S_12KHZ, + I2S_22KHZ, + I2S_24KHZ, + I2S_44KHZ, + I2S_48KHZ, + MAX_I2S_RATE +} curieI2sSampleRate; + +// These are the supported sample size for the Curie I2S interface, +typedef enum { + I2S_16bit = 0, + I2S_24bit, + I2S_32bit, + MAX_I2S_SIZE +} curieI2sSampleSize; + +// This is a list of return error code. +typedef enum { + SUCCESS = 0, + I2S_INIT_FAIL, // I2S controller initialization failure. + I2S_WRITE_BUSY, // Previous operation not completed when I2S write is called. + I2S_WRITE_DRIVER_FAIL, // I2S driver write operation failure. + I2S_WRITE_FAIL, // I2S controller failure, check Tx error count. + I2S_READ_BUSY, // Previous operation not completed when I2S read is called. + I2S_READ_FAIL, // I2S controller read operation failure. + I2S_MISC_ERROR +} i2sErrorCode; + + +class I2SController +{ + public: + I2SController(); + + // + virtual i2sErrorCode begin(curieI2sSampleRate sample_rate, + curieI2sSampleSize resolution, + curieI2sMode mode, + uint8_t master) = 0; + + // + virtual void end() = 0; + + protected: + // mux/demux the i2s rx pins into i2s mode + void muxRX(bool enable); + + // mux/demux the i2s tx pins into i2s mode + void muxTX(bool enable); + + uint16_t *sampleRateMap; + uint8_t *sampleSizeMap; +}; + + +#endif diff --git a/libraries/CurieAudio/src/I2SInput.cpp b/libraries/CurieAudio/src/I2SInput.cpp new file mode 100644 index 00000000..fe03aad8 --- /dev/null +++ b/libraries/CurieAudio/src/I2SInput.cpp @@ -0,0 +1,112 @@ +//*************************************************************** +// +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// +// 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 Street, Fifth Floor, Boston, MA 02110-1301 USA +// +//*************************************************************** + +#include "I2SInput.h" +#include "soc_i2s.h" +#include "soc_dma.h" +#include "variant.h" +#include + +I2SInputClass I2SInput; + + +void rxi2s_done(void* x) +{ + I2SInput.rxdone_flag = 1; + if (I2SInput.userCB) + I2SInput.userCB(); +} + +void rxi2s_err(void* x) +{ + I2SInput.rxerror_flag = 1; +} + + +I2SInputClass::I2SInputClass() +{ + rxdone_flag = 1; + rxerror_flag = 0; + userCB = NULL; +} + + +i2sErrorCode I2SInputClass::begin(curieI2sSampleRate sampleRate, + curieI2sSampleSize resolution, + curieI2sMode mode, + uint8_t master) +{ + struct soc_i2s_cfg rxcfg ; + + sampleSize = resolution; + muxRX(1); + soc_i2s_init(I2S_CHANNEL_RX); + soc_dma_init(); + + rxcfg.clk_divider = sampleRateMap[(resolution * MAX_I2S_RATE) + sampleRate]; + rxcfg.resolution = sampleSizeMap[resolution]; + rxcfg.mode = (uint8_t)mode; + rxcfg.master = master; + + rxcfg.cb_done = rxi2s_done; + rxcfg.cb_err = rxi2s_err; + + if (soc_i2s_config(I2S_CHANNEL_RX, &rxcfg) != DRV_RC_OK) + return I2S_INIT_FAIL; + + return SUCCESS; +} + + +void I2SInputClass::end() +{ + soc_i2s_stop_listen(); + muxRX(0); +} + + +i2sErrorCode I2SInputClass::read(uint8_t buffer[], uint32_t length, uint32_t blocking) +{ + if (rxdone_flag != 0) return I2S_READ_BUSY; + + rxdone_flag = 0; + rxerror_flag = 0; + + uint32_t byteAlignment = (sampleSize > I2S_16bit) ? 4 : 2; + + if (soc_i2s_listen((void *)buffer, length, byteAlignment, 0) != DRV_RC_OK) + { + rxdone_flag = 1; + return I2S_READ_FAIL; + } + + if (blocking == 0) return SUCCESS; + + while (1) // use a count to bail. + { + if (rxerror_flag == 1) break; + + if (rxdone_flag == 1) return SUCCESS; + } + + rxdone_flag = 1; + return I2S_READ_FAIL; +} + diff --git a/libraries/CurieAudio/src/I2SInput.h b/libraries/CurieAudio/src/I2SInput.h new file mode 100644 index 00000000..8b10c053 --- /dev/null +++ b/libraries/CurieAudio/src/I2SInput.h @@ -0,0 +1,55 @@ +/* + I2S Input API + Copyright (c) 2016 Arduino LLC. All right reserved. + + 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 +*/ + +#ifndef ARDUINO_I2S_INPUT +#define ARDUINO_I2S_INPUT + +#include + +class I2SInputClass : public I2SController +{ + friend void rxi2s_done(void* x); + friend void rxi2s_err(void* x); + + public: + I2SInputClass(); + + i2sErrorCode begin(curieI2sSampleRate sample_rate, + curieI2sSampleSize resolution, + curieI2sMode mode, + uint8_t master = 1); + void end(); + + i2sErrorCode read(uint8_t buffer[], uint32_t length, uint32_t blocking = 1); + + void attachInterrupt(void (*userCallBack)(void)) + { + userCB = userCallBack; + }; + + private: + curieI2sSampleSize sampleSize; + uint8_t rxdone_flag; + uint8_t rxerror_flag; + void (*userCB)(void); +}; + +extern I2SInputClass I2SInput; + +#endif diff --git a/libraries/CurieAudio/src/I2SOutput.cpp b/libraries/CurieAudio/src/I2SOutput.cpp new file mode 100644 index 00000000..083a8780 --- /dev/null +++ b/libraries/CurieAudio/src/I2SOutput.cpp @@ -0,0 +1,213 @@ +//*************************************************************** +// +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// +// 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 Street, Fifth Floor, Boston, MA 02110-1301 USA +// +//*************************************************************** + +#include "I2SOutput.h" +#include "soc_i2s.h" +#include "soc_dma.h" +#include "variant.h" +#include + +const int numPpBuffer = 2; +const int NUMBER_OF_SAMPLES = 256; + +static struct pingpongstruct { + int32_t buf[NUMBER_OF_SAMPLES]; // Left and right samples + uint16_t empty; +} ppBuffer[numPpBuffer]; + +static int i2sRunning = 0; +static int sendIndex = 0; +static int fillIndex = 0; + +I2SOutputClass I2SOutput; + + +void i2sTxDoneCB(void *x) +{ + I2SOutput.txdone_flag = 1; + i2sRunning = 0; +} + +void i2sPingPongTxCB(void *x) +{ + ppBuffer[sendIndex].empty = 1; + sendIndex = (sendIndex + 1) & 0x01; + + if (ppBuffer[sendIndex].empty) { + I2SOutput.txdone_flag = 1; + soc_i2s_stop_transmit(); + i2sRunning = 0; + } +} + +void i2sTxErrorCB(void *x) +{ + I2SOutput.txErrorCount++; + I2SOutput.txerror_flag = 1; + i2sRunning = 0; +} + + +I2SOutputClass::I2SOutputClass() +{ + txdone_flag = 1; + txErrorCount = 0; + + for (int i=0; i= numPpBuffer) + j = 0; + } + + if (soc_i2s_transmit_loop(bufPtrArray, numPpBuffer, sizeof(ppBuffer[0].buf), + sizeof(int32_t)) != DRV_RC_OK) { + return I2S_WRITE_DRIVER_FAIL; + } + i2sRunning = 1; + return SUCCESS; +} + + +i2sErrorCode I2SOutputClass::write(int32_t leftSample, int32_t rightSample, + uint16_t flush) +{ + static int bufIndex = 0; + int16_t nextBuffer; + i2sErrorCode result = SUCCESS; + + ppBuffer[fillIndex].buf[bufIndex++] = leftSample; + ppBuffer[fillIndex].buf[bufIndex++] = rightSample; + + if (flush) { + while (bufIndex < NUMBER_OF_SAMPLES) + ppBuffer[fillIndex].buf[bufIndex++] = 0; + } + + if (bufIndex >= NUMBER_OF_SAMPLES) { + // Buffer is filled + ppBuffer[fillIndex].empty = 0; + nextBuffer = (fillIndex + 1) & 0x01; + + while (bufIndex >= NUMBER_OF_SAMPLES) { + if (!i2sRunning) { + if ((result = kickOff()) != SUCCESS) + break; + } + + if (ppBuffer[nextBuffer].empty == 1) { + fillIndex = nextBuffer; + bufIndex = 0; + } + } + } + return result; +} + + +i2sErrorCode I2SOutputClass::write(int32_t buffer[], int bufferLength, + uint32_t blocking) +{ + // int count = 0; + + if (txdone_flag == 0) return I2S_WRITE_BUSY; + + txerror_flag = txdone_flag = 0; + + if (soc_i2s_write((void *)buffer, bufferLength, sizeof(int32_t)) != DRV_RC_OK) { + txdone_flag = 1; + return I2S_WRITE_DRIVER_FAIL; + } + + if (blocking == 0) return SUCCESS; + + while (1) // (count++ < 100000) Need to bail sometime + { + if (txerror_flag == 1) return I2S_WRITE_FAIL; + + if (txdone_flag == 1) return SUCCESS; + } +} + + +int I2SOutputClass::txError(void) +{ + int tmp = txErrorCount; + txErrorCount = 0; + return tmp; +} + + + + diff --git a/libraries/CurieAudio/src/I2SOutput.h b/libraries/CurieAudio/src/I2SOutput.h new file mode 100644 index 00000000..98821db0 --- /dev/null +++ b/libraries/CurieAudio/src/I2SOutput.h @@ -0,0 +1,65 @@ +/* + I2S Output API + Copyright (c) 2016 Arduino LLC. All right reserved. + + 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 +*/ + +#ifndef ARDUINO_I2S_OUTPUT +#define ARDUINO_I2S_OUTPUT + +#include "I2SController.h" + +class I2SOutputClass : public I2SController +{ + friend void i2sTxDoneCB(void *x); + friend void i2sPingPongTxCB(void *x); + friend void i2sTxErrorCB(void *x); + + public: + I2SOutputClass(); + + i2sErrorCode begin(curieI2sSampleRate sample_rate, + curieI2sSampleSize resolution, + curieI2sMode mode, + uint8_t master = 1); + void end(); + + // Write one audio sample for each channel. Samples are temporarily stored in a buffer + // until it is full, it will be dumped to the I2S output. Setting the flush flag + // will fill the unused space in the temperary buffer with 0 (mute) and cause it to + // be dumped to I2S output. + i2sErrorCode write(int32_t leftSample, int32_t rightSample, + uint16_t flush = 0); + + // This is an one time dumping of a buffer to the I2S output. The I2S bus is halted + // upon completion. + i2sErrorCode write(int32_t buffer[], int bufferLength, + uint32_t blocking = 1); + + inline uint8_t txDone(void) { return txdone_flag; } + + int txError(void); + + private: + curieI2sSampleSize sampleSize; + uint8_t txdone_flag; + uint8_t txerror_flag; + int txErrorCount; +}; + +extern I2SOutputClass I2SOutput; + +#endif diff --git a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino deleted file mode 100644 index ed099fa1..00000000 --- a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation. All rights reserved. - * See the bottom of this file for the license terms. - */ - -/** - * A simple sketch to test the rx channel of the i2s interface. - * A callback function is used to fill up a buffer whenever data is received - * - * To test this sketch you will need a second Arduino/Genuino 101 board with the I2SDMA_TxCallback sketch uploaded - * - * Connection: - * I2S_RSCK(pin 8) -> I2S_TSCK(pin 2) - * I2S_RWS (pin 3) -> I2S_TWS (pin 4) - * I2S_RXD (pin 5) -> I2S_TXD (pin 7) - * Ground (GND) -> Ground (GND) - * Notes: - * Transmission is sensitive to noise. To reduce noise: - * - Power both boards with an external power supply. Usb power is not always clean. - * - Insure that both boards are sharing the same ground. - * - Use short wires to connect between the board or use shielded wire. -**/ -#include - -#define BUFF_SIZE 128 -#define OFFSET 2 -uint32_t dataBuff[BUFF_SIZE+OFFSET]; // extra 2 buffers are for the padding zero - -/** - * the received data: the higher 16 bits should be equal to loop_count and the lower 16 bits should be (0x01~0x80) - * loop_count should increase by 1 in evry loop() - * for example: if first time the received data is 0x00010001~0x00010080, then next time the data should be 0x00020001~0x00020080 -**/ -uint8_t start_flag = 0; -uint8_t done_flag = 0; // when done_flag is 1, the received data are correct -uint32_t loop_count = 0; // record the higher 16 bits of received data -uint32_t shift_count = 0; // the position of first non-zero -void setup() -{ - Serial.begin(115200); // initialize Serial communication - while(!Serial) ; // wait for serial port to connect. - Serial.println("CurieI2SDMA Rx Callback"); - - CurieI2SDMA.iniRX(); - /* - * CurieI2SDMA.beginTX(sample_rate, resolution, master,mode) - * mode 1 : PHILIPS_MODE - * 2 : RIGHT_JST_MODE - * 3 : LEFT_JST_MODE - * 4 : DSP_MODE - */ - CurieI2SDMA.beginRX(44100, 32,0,1); - -} - -void loop() -{ - int status = CurieI2SDMA.transRX(dataBuff,sizeof(dataBuff),sizeof(uint32_t)); - if(status) - return; - - // find out first non-zero - shift_count = 0; - for(uint32_t i = 0;i <= OFFSET;++i) - { - if(dataBuff[i] == 0) - shift_count++; - else - break; - } - if(shift_count > OFFSET) - return; - - // record the higher 16 bits of received data - if(start_flag) - { - if((dataBuff[shift_count]>>16) != loop_count+1) - Serial.println("+++ loop_count jump +++"); - } - else - { - start_flag = 1; - } - loop_count = (dataBuff[shift_count] >> 16); - - // check data serial: the higher 16 bits should be equal to loop_count and the lower 16 bits should be (0x01~0x80) - done_flag = 1; - for(uint32_t i = 0 ;i < BUFF_SIZE;++i) - { - //Serial.println(dataBuff[i+shift_count],HEX); - if ((dataBuff[i+shift_count] & 0XFFFF0000) == (loop_count <<16) - && (dataBuff[i+shift_count] & 0XFFFF) == (i+1)) - ; - else - { - done_flag = 0; - Serial.println(dataBuff[i+shift_count],HEX); - Serial.println("ERROR"); - break; - } - } - - if(done_flag) - Serial.println("RX done"); - delay(100); -} - -/* - Copyright (c) 2016 Intel Corporation. All rights reserved. - 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 Street, Fifth Floor, Boston, MA 02110- - 1301 USA -*/ diff --git a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino deleted file mode 100644 index 9ce55501..00000000 --- a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation. All rights reserved. - * See the bottom of this file for the license terms. - */ - -//I2S_TX -> Pin 7 -//I2S_TSK -> Pin 4 -//I2S_TSCK -> pin 2 - -#include - -#define BUFF_SIZE 128 -boolean blinkState = true; // state of the LED -uint32_t dataBuff[BUFF_SIZE]; -uint32_t loop_count = 0; -void setup() -{ - Serial.begin(115200); // initialize Serial communication - while(!Serial) ; // wait for serial port to connect. - Serial.println("CurieI2SDMA Tx Callback"); - - CurieI2SDMA.iniTX(); - /* - * CurieI2SDMA.beginTX(sample_rate, resolution, master,mode) - * mode 1 : PHILIPS_MODE - * 2 : RIGHT_JST_MODE - * 3 : LEFT_JST_MODE - * 4 : DSP_MODE - */ - CurieI2SDMA.beginTX(44100, 32,1, 1); - digitalWrite(13, blinkState); -} - -void loop() -{ - for(uint32_t i = 0; i I2S LRCLK / FS (left/right / frame select clock) +// - Digital 1 -> I2S BCLK / SCLK (bit / serial clock) +// - Digital 9 -> I2S DIN / SD (data output) +// - Ground +// +// Depends on the Adafruit_ASFcore library from: +// https://github.com/adafruit/adafruit_asfcore +// +// Released under a MIT license: https://opensource.org/licenses/MIT +#ifdef ARDUINO_ARCH_ARC32 +#include +#else +#include "Adafruit_ASFcore.h" +#include "Adafruit_ZeroI2S.h" +#endif + + +#define SAMPLERATE_HZ 22000 // The sample rate of the audio. Higher sample rates have better fidelity, + // but these tones are so simple it won't make a difference. 44.1khz is + // standard CD quality sound. + +#define AMPLITUDE 100 // Set the amplitude of generated waveforms. This controls how loud + // the signals are, and can be any value from 0 to 65535. Start with + // a low value like 5000 or less to prevent damaging speakers! + +#define WAV_SIZE 256 // The size of each generated waveform. The larger the size the higher + // quality the signal. A size of 256 is more than enough for these simple + // waveforms. + + +// Define the frequency of music notes (from http://www.phy.mtu.edu/~suits/notefreqs.html): +#define C4_HZ 261.63 +#define D4_HZ 293.66 +#define E4_HZ 329.63 +#define F4_HZ 349.23 +#define G4_HZ 392.00 +#define A4_HZ 440.00 +#define B4_HZ 493.88 + +// Define a C-major scale to play all the notes up and down. +float scale[] = { C4_HZ, D4_HZ, E4_HZ, F4_HZ, G4_HZ, A4_HZ, B4_HZ, A4_HZ, G4_HZ, F4_HZ, E4_HZ, D4_HZ, C4_HZ }; + +// Store basic waveforms in memory. +int32_t sine[WAV_SIZE] = {0}; +int32_t sawtooth[WAV_SIZE] = {0}; +int32_t triangle[WAV_SIZE] = {0}; +int32_t square[WAV_SIZE] = {0}; + +#ifndef ARDUINO_ARCH_ARC32 +// Create I2S audio transmitter object. +Adafruit_ZeroI2S_TX i2s = Adafruit_ZeroI2S_TX(); + +// Little define to make the native USB port on the Arduino Zero / Zero feather +// the default for serial output. +#define Serial SerialUSB +#endif + + +void generateSine(int32_t amplitude, int32_t* buffer, int32_t length) { + // Generate a sine wave signal with the provided amplitude and store it in + // the provided buffer of size length. + for (int i=0; ihead +1) % I2S_BUFFER_SIZE; - uint32_t data = *I2S_DATA_REG; + int32_t data = *I2S_DATA_REG; if(index != _i2s_Rx_BufferPtr->tail) { _i2s_Rx_BufferPtr->data[_i2s_Rx_BufferPtr->head] = data; @@ -541,7 +541,7 @@ void Curie_I2S::enableInterrupts() interrupt_enable(IRQ_I2S_INTR); } -int Curie_I2S::pushData(uint32_t data) +int Curie_I2S::pushData(int32_t data) { //disable TFIFO_AEMPTY interrupts *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFDFFFFFF; @@ -563,22 +563,22 @@ int Curie_I2S::pushData(uint32_t data) } } -void Curie_I2S::fastPushData(uint32_t data) +void Curie_I2S::fastPushData(int32_t data) { *I2S_DATA_REG = data; } -uint32_t Curie_I2S::pullData() +int32_t Curie_I2S::pullData() { - uint32_t data = *I2S_DATA_REG; + int32_t data = *I2S_DATA_REG; return data; } -uint32_t Curie_I2S::requestdword() +int32_t Curie_I2S::requestdword() { if(_i2s_Rx_BufferPtr->head != _i2s_Rx_BufferPtr->tail) { - uint32_t data = _i2s_Rx_BufferPtr->data[_i2s_Rx_BufferPtr->tail]; + int32_t data = _i2s_Rx_BufferPtr->data[_i2s_Rx_BufferPtr->tail]; _i2s_Rx_BufferPtr->tail = (_i2s_Rx_BufferPtr->tail + 1)%I2S_BUFFER_SIZE; return data; } @@ -588,7 +588,7 @@ uint32_t Curie_I2S::requestdword() if(*I2S_RFIFO_STAT & 0x0000000F) { int index = (uint32_t)(_i2s_Rx_BufferPtr->head +1) % I2S_BUFFER_SIZE; - uint32_t data = *I2S_DATA_REG; + int32_t data = *I2S_DATA_REG; if(index != _i2s_Rx_BufferPtr->tail) { _i2s_Rx_BufferPtr->data[_i2s_Rx_BufferPtr->head] = data; diff --git a/libraries/CurieI2S/src/CurieI2S.h b/libraries/CurieI2S/src/CurieI2S.h index e7eb8894..42258260 100644 --- a/libraries/CurieI2S/src/CurieI2S.h +++ b/libraries/CurieI2S/src/CurieI2S.h @@ -32,12 +32,21 @@ #define DSP_MODE 0b101000101000 //Sample Rate I2S_SRR Values -#define I2S_48K 0x000A000A -#define I2S_44K 0x000F000F -#define I2S_24K 0x001C001C -#define I2S_22K 0x001E001E -#define I2S_12K 0x00530053 -#define I2S_8K 0x007D007D +#define I2S_48K_32bit 0x000A000A +#define I2S_44K_32bit 0x000B000B +#define I2S_24K_32bit 0x00150015 +#define I2S_22K_32bit 0x00170017 +#define I2S_12K_32bit 0x002A002A + +#define I2S_48K_24bit 0x000A000A +#define I2S_44K_24bit 0x000F000F +#define I2S_24K_24bit 0x001C001C +#define I2S_22K_24bit 0x001E001E + +#define I2S_44K_16bit 0x00170017 +#define I2S_22K_16bit 0x002D002D +#define I2S_12K_16bit 0x00530053 +#define I2S_8K_16bit 0x007D007D //Resolution I2S_SRR Values #define I2S_32bit 0xF800F800 @@ -47,14 +56,14 @@ //Registers #define I2S_CTRL (uint32_t *)0xB0003800 //I2S Control Register #define I2S_STAT (volatile uint32_t *)0xB0003804 //I2S Status Register -#define I2S_SRR (uint32_t *)0xB0003808 //I2S Channels Sample Rate & Resolution Configuration Register +#define I2S_SRR (volatile uint32_t *)0xB0003808 //I2S Channels Sample Rate & Resolution Configuration Register #define I2S_CID_CTRL (uint32_t *)0xB000380C //Clock, Interrupt and DMA Control Register #define I2S_TFIFO_STAT (volatile uint32_t *)0xB0003810 //Transmit FIFO Status Register #define I2S_RFIFO_STAT (volatile uint32_t *)0xB0003814 //Receive FIFO Status Register #define I2S_TFIFO_CTRL (uint32_t *)0xB0003818 //Transmit FIFO Control Register #define I2S_RFIFO_CTRL (uint32_t *)0xB000381C //Receive FIFO Control Register #define I2S_DEV_CONF (uint32_t *)0xB0003820 //Device Configuration Register -#define I2S_DATA_REG (volatile uint32_t *)0xB0003850 //Data Register +#define I2S_DATA_REG (volatile int32_t *)0xB0003850 //Data Register #define I2S_MASK_INT (uint32_t *)0xB0800468 //Host Processor Interrupt Routing Mask 7 #define CLK_GATE_CTL (uint32_t *)0xB0800018 //CLK_GATE_CTL register @@ -86,7 +95,7 @@ struct i2s_ring_buffer { - volatile uint32_t data[I2S_BUFFER_SIZE]; + volatile int32_t data[I2S_BUFFER_SIZE]; volatile int head = 0; volatile int tail= 0; volatile bool lock = false; @@ -179,21 +188,21 @@ class Curie_I2S void end(); // Pushes a dword into the TX buffer - int pushData(uint32_t data); + int pushData(int32_t data); // Pushes a dword into the TX FIFO - void fastPushData(uint32_t data); + void fastPushData(int32_t data); void write(); // Pulls a dword directly from the RX FIFO - uint32_t pullData(); + int32_t pullData(); // Pulls a dword from the tail of the rx buffer - uint32_t read() {return requestdword(); }; + int32_t read() {return requestdword(); }; // Pulls a dword from the tail of the rx buffer - uint32_t requestdword(); + int32_t requestdword(); // Returns number of dword avaialable in the rx buffer uint16_t available(); diff --git a/libraries/CurieI2S/src/CurieI2SDMA.cpp b/libraries/CurieI2S/src/CurieI2SDMA.cpp deleted file mode 100644 index 3840ecde..00000000 --- a/libraries/CurieI2S/src/CurieI2SDMA.cpp +++ /dev/null @@ -1,316 +0,0 @@ -//*************************************************************** -// -// Copyright (c) 2016 Intel Corporation. All rights reserved. -// -// 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 Street, Fifth Floor, Boston, MA 02110-1301 USA -// -//*************************************************************** - -//CurieI2SDMA.cpp - -#include "CurieI2SDMA.h" -#include "soc_i2s.h" -#include "soc_dma.h" -#include "variant.h" -#include - -static void txi2s_done(void* x); -static void rxi2s_done(void* x); -static void txi2s_err(void* x); -static void rxi2s_err(void* x); - -volatile uint8_t txdone_flag = 0; -volatile uint8_t txerror_flag = 0; - -volatile uint8_t rxdone_flag = 0; -volatile uint8_t rxerror_flag = 0; -uint8_t frameDelay = 0; - -static void txi2s_done(void* x) -{ - CurieI2SDMA.lastFrameDelay(); - txdone_flag = 1; - - return; -} - -static void rxi2s_done(void* x) -{ - rxdone_flag = 1; - - return; -} - -static void txi2s_err(void* x) -{ - txerror_flag = 1; - - return; -} - -static void rxi2s_err(void* x) -{ - rxerror_flag = 1; - - return; -} - -struct soc_i2s_cfg txcfg ; - -struct soc_i2s_cfg rxcfg ; - -Curie_I2SDMA CurieI2SDMA; - -Curie_I2SDMA::Curie_I2SDMA() -{ -} - -void Curie_I2SDMA::lastFrameDelay() -{ - delay(frameDelay); -} - -int Curie_I2SDMA::iniTX() -{ - muxTX(1); - soc_i2s_init(); - soc_dma_init(); - return I2S_DMA_OK; -} - -int Curie_I2SDMA::iniRX() -{ - muxRX(1); - soc_i2s_init(); - soc_dma_init(); - return I2S_DMA_OK; -} - -void Curie_I2SDMA::muxTX(bool enable) -{ - int mux_mode = GPIO_MUX_MODE; - if(enable) - { - mux_mode = I2S_MUX_MODE; - } - - /* Set SoC pin mux configuration */ - SET_PIN_MODE(g_APinDescription[I2S_TXD].ulSocPin, mux_mode); - SET_PIN_MODE(g_APinDescription[I2S_TWS].ulSocPin, mux_mode); - SET_PIN_MODE(g_APinDescription[I2S_TSCK].ulSocPin, mux_mode); -} - -void Curie_I2SDMA::muxRX(bool enable) -{ - int mux_mode = GPIO_MUX_MODE; - if(enable) - { - mux_mode = I2S_MUX_MODE; - } - - /* Set SoC pin mux configuration */ - SET_PIN_MODE(49, mux_mode); //I2S_RXD - SET_PIN_MODE(51, mux_mode); //I2S_RWS - SET_PIN_MODE(50, mux_mode); //I2S_RSCK -} - -int Curie_I2SDMA::beginTX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode) -{ - switch(mode) - { - case 1: - mode = I2S_MODE_PHILLIPS ; - break; - case 2: - mode = I2S_MODE_RJ; - break; - case 3: - mode = I2S_MODE_LJ; - break; - case 4: - mode = I2S_MODE_DSP; - break; - default: - break; - } - - txcfg.sample_rate = sample_rate; - txcfg.resolution = resolution; - txcfg.mode = mode; - txcfg.master = master; - txcfg.cb_done = txi2s_done; - txcfg.cb_err = txi2s_err; - txdone_flag = 0; - txerror_flag = 0; - frameDelay = 5; - soc_i2s_config(I2S_CHANNEL_TX, &txcfg); - return I2S_DMA_OK; -} - -int Curie_I2SDMA::beginRX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode) -{ - switch(mode) - { - case 1: - mode = I2S_MODE_PHILLIPS ; - break; - case 2: - mode = I2S_MODE_RJ; - break; - case 3: - mode = I2S_MODE_LJ; - break; - case 4: - mode = I2S_MODE_DSP; - break; - default: - break; - } - - rxcfg.sample_rate = sample_rate; - rxcfg.resolution = resolution; - rxcfg.mode = mode; - rxcfg.master = master; - - rxcfg.cb_done = rxi2s_done; - rxcfg.cb_err = rxi2s_err; - - rxdone_flag = 0; - rxerror_flag = 0; - - soc_i2s_config(I2S_CHANNEL_RX, &rxcfg); - - return I2S_DMA_OK; -} - -int Curie_I2SDMA::transTX(void* buf_TX,uint32_t len,uint32_t len_per_data) -{ - int status = soc_i2s_stream(buf_TX, len,len_per_data,0); - if(status) - return I2S_DMA_FAIL; - while (1) - { - // check the DMA and I2S status - if(txdone_flag && !txerror_flag) - { - txdone_flag = 0; - txerror_flag = 0; - return I2S_DMA_OK; - } - if(txerror_flag) - { - return I2S_DMA_FAIL; - } - } -} - -int Curie_I2SDMA::transRX(void* buf_RX,uint32_t len,uint32_t len_per_data) -{ - int status = soc_i2s_listen(buf_RX, len ,len_per_data,0); - if(status) - return I2S_DMA_FAIL; - - while (1) - { - // check the DMA and I2S status - if(rxdone_flag && !rxerror_flag) - { - rxdone_flag = 0; - rxerror_flag = 0; - return I2S_DMA_OK; - } - if(rxerror_flag) - { - return I2S_DMA_FAIL; - } - } - return I2S_DMA_OK; -} - -void Curie_I2SDMA::stopTX() -{ - soc_i2s_stop_stream(); - muxTX(0); -} - -void Curie_I2SDMA::stopRX() -{ - soc_i2s_stop_listen(); - muxRX(0); -} - -int Curie_I2SDMA::mergeData(void* buf_left,void* buf_right,void* buf_TX,uint32_t length_TX,uint32_t len_per_data) -{ - if(len_per_data == 1) - { - for(uint32_t i = 0; i < length_TX/2;++i) - { - *((uint8_t *)buf_TX+2*i) = *((uint8_t *)buf_left+i); - *((uint8_t *)buf_TX+2*i+1) = *((uint8_t *)buf_right+i); - } - } - else if(len_per_data == 2) - { - for(uint32_t i = 0; i < length_TX/2;++i) - { - *((uint16_t *)buf_TX+2*i) = *((uint16_t *)buf_left+i); - *((uint16_t *)buf_TX+2*i+1) = *((uint16_t *)buf_right+i); - } - } - else if(len_per_data == 4) - { - for(uint32_t i = 0; i < length_TX/2;++i) - { - *((uint32_t *)buf_TX+2*i) = *((uint32_t *)buf_left+i); - *((uint32_t *)buf_TX+2*i+1) = *((uint32_t *)buf_right+i); - } - } - else - return I2S_DMA_FAIL; - - return I2S_DMA_OK; -} - -int Curie_I2SDMA::separateData(void* buf_left,void* buf_right,void* buf_RX,uint32_t length_RX,uint32_t len_per_data) -{ - if(len_per_data == 1) - { - for(uint32_t i = 0; i < length_RX/2;++i) - { - *((uint8_t *)buf_left+i) = *((uint8_t *)buf_RX+2*i); - *((uint8_t *)buf_right+i) = *((uint8_t *)buf_RX+2*i+1); - } - } - else if(len_per_data == 2) - { - for(uint32_t i = 0; i < length_RX/2;++i) - { - *((uint16_t *)buf_left+i) = *((uint16_t *)buf_RX+2*i); - *((uint16_t *)buf_right+i) = *((uint16_t *)buf_RX+2*i+1); - } - } - else if(len_per_data == 4) - { - for(uint32_t i = 0; i < length_RX/2;++i) - { - *((uint32_t *)buf_left+i) = *((uint32_t *)buf_RX+2*i); - *((uint32_t *)buf_right+i) = *((uint32_t *)buf_RX+2*i+1); - } - } - else - return I2S_DMA_FAIL; - - return I2S_DMA_OK; -} diff --git a/libraries/CurieI2S/src/CurieI2SDMA.h b/libraries/CurieI2S/src/CurieI2SDMA.h deleted file mode 100644 index 271d6ac4..00000000 --- a/libraries/CurieI2S/src/CurieI2SDMA.h +++ /dev/null @@ -1,83 +0,0 @@ -//*************************************************************** -// -// Copyright (c) 2016 Intel Corporation. All rights reserved. -// -// 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 Street, Fifth Floor, Boston, MA 02110-1301 USA -// -//*************************************************************** - -//CurieI2SDMA.h - -#ifndef _CURIEI2SDMA_H_ -#define _CURIEI2SDMA_H_ - -#include - -//I2S Arduino Pins -#define I2S_TXD 7 -#define I2S_TWS 4 -#define I2S_TSCK 2 -#define I2S_RXD 5 -#define I2S_RWS 3 -#define I2S_RSCK 8 - -#define I2S_DMA_OK 0 -#define I2S_DMA_FAIL 1 -class Curie_I2SDMA -{ - private: - // mux/demux the i2s rx pins into i2s mode - void muxRX(bool enable); - - // mux/demux the i2s tx pins into i2s mode - void muxTX(bool enable); - - public: - Curie_I2SDMA(); - - void lastFrameDelay(); - - // - int beginTX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode); - // - int beginRX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode); - - // initializes i2s interface - int iniTX(); - //void transTX(); - int iniRX(); - - // starts transmission of data to the tx channel - int transTX(void* buf_TX,uint32_t len,uint32_t len_per_data); - - // starts listening to the rx channel - int transRX(void* buf_RX,uint32_t len,uint32_t len_per_data); - - // merge data of left and right channel into one buffer - int mergeData(void* buf_left,void* buf_right,void* buf_TX,uint32_t length_TX,uint32_t len_per_data); - - // seperate the data to left and right channl - int separateData(void* buf_left,void* buf_right,void* buf_RX,uint32_t length_RX,uint32_t len_per_data); - - // - void stopTX(); - // - void stopRX(); - -}; - -extern Curie_I2SDMA CurieI2SDMA; - -#endif diff --git a/system/libarc32_arduino101/drivers/soc_dma.c b/system/libarc32_arduino101/drivers/soc_dma.c index f0b0120c..189842ed 100644 --- a/system/libarc32_arduino101/drivers/soc_dma.c +++ b/system/libarc32_arduino101/drivers/soc_dma.c @@ -70,6 +70,7 @@ DRIVER_API_RC soc_dma_start_transfer(struct soc_dma_channel *channel); DRIVER_API_RC soc_dma_stop_transfer(struct soc_dma_channel *channel); DRIVER_API_RC soc_dma_alloc_list_item(struct soc_dma_xfer_item **ret, struct soc_dma_xfer_item *base); DRIVER_API_RC soc_dma_free_list(struct soc_dma_cfg *cfg); +DRIVER_API_RC dma_update_ll(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg); DRIVER_API_RC dma_init(); DECLARE_INTERRUPT_HANDLER static void dma_ch0_interrupt_handler() @@ -114,7 +115,8 @@ struct soc_dma_info g_dma_info = { NULL }, .err_mask = INT_DMA_ERROR_MASK, - .err_vector = SOC_DMA_ERR_INTERRUPT + .err_vector = SOC_DMA_ERR_INTERRUPT, + .hw_configured = 0 }; static struct soc_dma_info* dma_info = &g_dma_info; @@ -280,6 +282,39 @@ static struct dma_lli *dma_find_ll_end(struct dma_lli *head) return t; } +DRIVER_API_RC dma_update_ll(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg) +{ + struct dma_lli *lli; + struct soc_dma_xfer_item *xfer; + struct soc_dma_xfer_item *last_xfer; + uint8_t list_done; + + if (channel->ll == NULL) + { + return DRV_RC_FAIL; + } + + lli = (struct dma_lli *)(channel->ll); + xfer = &(cfg->xfer); + last_xfer = dma_find_list_end(xfer); + + list_done = 0; + + while (!list_done) + { + lli->sar = (uint32_t)(xfer->src.addr); + if ((xfer->next) == last_xfer) + list_done = 1; + else + { + xfer = xfer->next; + lli = (struct dma_lli *)lli->llp; + } + } + + return DRV_RC_OK; +} + static DRIVER_API_RC dma_create_ll(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg) { OS_ERR_TYPE err; @@ -543,6 +578,15 @@ DRIVER_API_RC soc_dma_config(struct soc_dma_channel *channel, struct soc_dma_cfg SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), SOC_DMA_CFG_U_SRC_PER, SOC_DMA_CFG_U_SRC_PER_LEN, cfg->src_interface); + // Per I2S controller specification. + if ((cfg->src_interface == SOC_DMA_INTERFACE_I2S_RX) || + (cfg->dest_interface == SOC_DMA_INTERFACE_I2S_TX)) { + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_L), + SOC_DMA_CTL_L_SRC_MSIZE, SOC_DMA_CTL_L_SRC_MSIZE_LEN, 1); + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_L), + SOC_DMA_CTL_L_DEST_MSIZE, SOC_DMA_CTL_L_DEST_MSIZE_LEN, 1); + } + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), SOC_DMA_CFG_U_SS_UPD_EN); CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), SOC_DMA_CFG_U_DS_UPD_EN); @@ -763,6 +807,9 @@ DRIVER_API_RC soc_dma_init() { struct soc_dma_channel ch; + if (dma_info->hw_configured) + return DRV_RC_OK; + dma_info->active = 0; // Enable global clock @@ -788,6 +835,7 @@ DRIVER_API_RC soc_dma_init() dma_info->channel[i] = NULL; } + dma_info->hw_configured = 1; return DRV_RC_OK; } diff --git a/system/libarc32_arduino101/drivers/soc_dma.h b/system/libarc32_arduino101/drivers/soc_dma.h index e81d071b..0f0acc06 100644 --- a/system/libarc32_arduino101/drivers/soc_dma.h +++ b/system/libarc32_arduino101/drivers/soc_dma.h @@ -133,6 +133,7 @@ struct soc_dma_info { struct soc_dma_channel* channel[SOC_DMA_NUM_CHANNELS]; uint32_t active; + uint32_t hw_configured; }; @@ -229,8 +230,26 @@ DRIVER_API_RC soc_dma_alloc_list_item(struct soc_dma_xfer_item **ret, struct soc * - DRV_RC_OK on success */ DRIVER_API_RC soc_dma_free_list(struct soc_dma_cfg *cfg); - +/** + * Function to initialize the DMA: + * + * @param none + * + * @return + * - DRV_RC_OK on success + */ DRIVER_API_RC soc_dma_init(); +/** + * Function to update the source/distination adress for DMAtransfer + * + * @param channel : pointer to channel object + * + * @param cfg : pointer to configuration object + * + * @return + * - DRV_RC_OK on success + */ +DRIVER_API_RC dma_update_ll(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg); #ifdef __cplusplus } diff --git a/system/libarc32_arduino101/drivers/soc_i2s.c b/system/libarc32_arduino101/drivers/soc_i2s.c index 114ce764..ba7a1ab0 100644 --- a/system/libarc32_arduino101/drivers/soc_i2s.c +++ b/system/libarc32_arduino101/drivers/soc_i2s.c @@ -46,7 +46,8 @@ struct soc_i2s_info g_i2s_info = { { .clk_gate_register = PERIPH_CLK_GATE_CTRL, .bits_mask = I2S_CLK_GATE_MASK, - } + }, + .hw_initialized = 0 }; struct soc_i2s_info* i2s_info = &g_i2s_info; @@ -60,10 +61,11 @@ DRIVER_API_RC soc_i2s_deconfig(uint8_t channel); DRIVER_API_RC soc_i2s_read(void *buf, uint32_t len, uint32_t len_per_data); DRIVER_API_RC soc_i2s_listen(void *buf, uint32_t len, uint32_t len_per_data, uint8_t num_bufs); DRIVER_API_RC soc_i2s_stop_listen(void); -DRIVER_API_RC soc_i2s_write(void *buf, uint32_t len, uint32_t len_per_data); -DRIVER_API_RC soc_i2s_stream(void *buf, uint32_t len, uint32_t len_per_data, uint32_t num_bufs); -DRIVER_API_RC soc_i2s_stop_stream(void); -DRIVER_API_RC soc_i2s_init(); +DRIVER_API_RC soc_i2s_write(void *buf, int bufSize, int dataSize); +DRIVER_API_RC soc_i2s_transmit_loop(void *bufPtrArray[], int numBuf, int bufSize, + int dataSize); +DRIVER_API_RC soc_i2s_stop_transmit(void); +DRIVER_API_RC soc_i2s_init(uint8_t channel); /* Internal functions */ static void i2s_enable(uint8_t channel) @@ -115,7 +117,7 @@ static void i2s_disable(uint8_t channel) num_active++; } } - + // Disable channel and hold parts in reset reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl); reg &= ~(1 << (i2s_reg_map[channel].ctrl_fifo_rst)); @@ -192,16 +194,7 @@ static void i2s_dma_cb_err(void *num) static void i2s_dma_cb_done(void *num) { uint8_t channel = (uint32_t)num; - uint32_t reg; - - if(channel == I2S_CHANNEL_TX) - { - do - { - reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].fifo_stat); - } while(reg & 0x000000FF); - } - + if (i2s_info->cfg[channel].cb_done) { i2s_info->cfg[channel].cb_done(i2s_info->cfg[channel].cb_done_arg); @@ -228,7 +221,7 @@ static void i2s_dma_cb_block(void *num) DRIVER_API_RC soc_i2s_config(uint8_t channel, struct soc_i2s_cfg *cfg) { uint32_t reg; - uint16_t sample_rate; + // uint16_t sample_rate; // Check channel no in use if (channel >= I2S_NUM_CHANNELS) @@ -247,12 +240,13 @@ DRIVER_API_RC soc_i2s_config(uint8_t channel, struct soc_i2s_cfg *cfg) MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl) = reg; // Calculate sample_rate divider (note, acts as if resolution is always 32) - sample_rate = i2s_info->clk_speed / (cfg->sample_rate * cfg->resolution * 2); + // sample_rate = i2s_info->clk_speed / (cfg->sample_rate * cfg->resolution * 2); + // Instead of calculating here, user provides clock divider for sample rate. // Setup resolution and sampling rate reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].srr); reg &= ~(i2s_reg_map[channel].srr_mask); - reg |= (sample_rate & 0x7FF) << i2s_reg_map[channel].srr_sample_rate; + reg |= (cfg->clk_divider & 0x7FF) << i2s_reg_map[channel].srr_sample_rate; reg |= ((cfg->resolution - 1) & 0x1F) << i2s_reg_map[channel].srr_resolution; MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].srr) = reg; @@ -452,219 +446,176 @@ DRIVER_API_RC soc_i2s_stop_listen(void) return DRV_RC_OK; } -DRIVER_API_RC soc_i2s_write(void *buf, uint32_t len, uint32_t len_per_data) +DRIVER_API_RC soc_i2s_write(void *buf, int bufSize, int dataSize) { - // Calling stream with 0 buffers is the same as a onetime write of the whole buffer - return soc_i2s_stream(buf, len, len_per_data, 0); + void *bufArray[1]; + + // Calling stream with 0 buffers is the same as a onetime write of the whole buffer + bufArray[0] = buf; + return soc_i2s_transmit_loop(bufArray, 1, bufSize, dataSize); } -DRIVER_API_RC soc_i2s_stream(void *buf, uint32_t len, uint32_t len_per_data, uint32_t num_bufs) +DRIVER_API_RC soc_i2s_transmit_loop(void *bufPtrArray[], int numBuf, int bufSize, + int dataSize) { - DRIVER_API_RC ret; - uint8_t channel = I2S_CHANNEL_TX; - uint32_t reg; - uint32_t len_per_buf; - int i; - struct soc_dma_xfer_item *dma_list; + uint32_t reg; + int i, length; + struct soc_dma_xfer_item *dma_list; - // Check channel no in use and configured - if (channel >= I2S_NUM_CHANNELS) - { - return DRV_RC_FAIL; - } - else if (i2s_info->en[channel] || !(i2s_info->cfgd[channel])) - { - return DRV_RC_FAIL; - } - // Get a DMA channel - ret = soc_dma_acquire(&(i2s_info->dma_ch[channel])); + if ((bufPtrArray == NULL) || (numBuf == 0) || (bufSize < dataSize)) + return DRV_RC_FAIL; - if (ret != DRV_RC_OK) - { - return DRV_RC_FAIL; - } + // Check channel no in use and configured + if (i2s_info->en[I2S_CHANNEL_TX] || !(i2s_info->cfgd[I2S_CHANNEL_TX])) + return DRV_RC_FAIL; - // Enable the channel - i2s_enable(channel); + // Get a DMA channel + if (soc_dma_acquire(&(i2s_info->dma_ch[I2S_CHANNEL_TX])) != DRV_RC_OK) + return DRV_RC_FAIL; - // Determine the length of a single buffer - if (num_bufs == 0) - { - len_per_buf = len; - } - else - { - len_per_buf = len / num_bufs; - } - - // Prep some configuration - i2s_info->dma_cfg[channel].type = SOC_DMA_TYPE_MEM2PER; - i2s_info->dma_cfg[channel].dest_interface = SOC_DMA_INTERFACE_I2S_TX; - i2s_info->dma_cfg[channel].dest_step_count = 0; - i2s_info->dma_cfg[channel].src_step_count = 0; - - i2s_info->dma_cfg[channel].xfer.dest.delta = SOC_DMA_DELTA_NONE; - i2s_info->dma_cfg[channel].xfer.dest.addr = (void *)(SOC_I2S_BASE + SOC_I2S_DATA_REG); - i2s_info->dma_cfg[channel].xfer.src.delta = SOC_DMA_DELTA_INCR; - - if(len_per_data == 1) - { - i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_8; - i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_8; - } - else if(len_per_data == 2) - { - i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_16; - i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_16; - } - else if(len_per_data == 4) - { - i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_32; - i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_32; - } - else - return DRV_RC_FAIL;; + // Enable the channel + i2s_enable(I2S_CHANNEL_TX); - if (num_bufs == 0) - { - i2s_info->dma_cfg[channel].cb_done = i2s_dma_cb_done; - i2s_info->dma_cfg[channel].cb_done_arg = (void *)((uint32_t)channel); - } - else - { - i2s_info->dma_cfg[channel].cb_block = i2s_dma_cb_block; - i2s_info->dma_cfg[channel].cb_block_arg = (void *)((uint32_t)channel); - } - - i2s_info->dma_cfg[channel].cb_err = i2s_dma_cb_err; - i2s_info->dma_cfg[channel].cb_err_arg = (void *)((uint32_t)channel); - - // Setup the linked list - for (i = 0; i < ((num_bufs == 0) ? 1 : num_bufs); i++) - { - if (i == 0) - { - dma_list = &(i2s_info->dma_cfg[channel].xfer); - } - else - { - ret = soc_dma_alloc_list_item(&dma_list, dma_list); - - if (ret != DRV_RC_OK) - { - goto fail; - } - } - - dma_list->src.addr = (void *)(uint8_t *)(buf+i * len_per_buf ); - dma_list->size = len_per_buf / len_per_data; - } - - // Create a circular list if we are doing circular buffering - if (num_bufs != 0) - { - dma_list->next = &(i2s_info->dma_cfg[channel].xfer); - } - - // Setup and start the DMA engine - ret = soc_dma_config(&(i2s_info->dma_ch[channel]), &(i2s_info->dma_cfg[channel])); - - if (ret != DRV_RC_OK) - { - goto fail; - } - - ret = soc_dma_start_transfer(&(i2s_info->dma_ch[channel])); - - if (ret != DRV_RC_OK) - { - goto fail; - } - - // Enable the channel and let it go! - reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl); - reg |= (1 << (i2s_reg_map[channel].ctrl_en)); - reg |= (1 << (i2s_reg_map[channel].ctrl_sync_rst)); - MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl) = reg; - - return DRV_RC_OK; + // Prep some configuration + i2s_info->dma_cfg[I2S_CHANNEL_TX].type = SOC_DMA_TYPE_MEM2PER; + i2s_info->dma_cfg[I2S_CHANNEL_TX].dest_interface = SOC_DMA_INTERFACE_I2S_TX; + i2s_info->dma_cfg[I2S_CHANNEL_TX].dest_step_count = 0; + i2s_info->dma_cfg[I2S_CHANNEL_TX].src_step_count = 0; + + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.dest.delta = SOC_DMA_DELTA_NONE; + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.dest.addr = (void *)(SOC_I2S_BASE + SOC_I2S_DATA_REG); + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.src.delta = SOC_DMA_DELTA_INCR; + + switch (dataSize) + { + case 1: + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.dest.width = SOC_DMA_WIDTH_8; + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.src.width = SOC_DMA_WIDTH_8; + break; + + case 2: + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.dest.width = SOC_DMA_WIDTH_16; + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.src.width = SOC_DMA_WIDTH_16; + break; + + default: + dataSize = 4; // default is 32 bit. + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.dest.width = SOC_DMA_WIDTH_32; + i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer.src.width = SOC_DMA_WIDTH_32; + break; + } + + if (numBuf == 1) { + i2s_info->dma_cfg[I2S_CHANNEL_TX].cb_done = i2s_dma_cb_done; + i2s_info->dma_cfg[I2S_CHANNEL_TX].cb_done_arg = (void *)(I2S_CHANNEL_TX); + } + else { + i2s_info->dma_cfg[I2S_CHANNEL_TX].cb_block = i2s_dma_cb_block; + i2s_info->dma_cfg[I2S_CHANNEL_TX].cb_block_arg = (void *)(I2S_CHANNEL_TX); + } + + i2s_info->dma_cfg[I2S_CHANNEL_TX].cb_err = i2s_dma_cb_err; + i2s_info->dma_cfg[I2S_CHANNEL_TX].cb_err_arg = (void *)(I2S_CHANNEL_TX); + + // Setup the linked list + for (i=0, length=(bufSize / dataSize); i < numBuf; i++) { + if (i == 0) + dma_list = &(i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer); + else { + if (soc_dma_alloc_list_item(&dma_list, dma_list) != DRV_RC_OK) + goto fail; + } + dma_list->src.addr = bufPtrArray[i]; + dma_list->size = length; + } + + // Create a circular list if we are doing circular buffering + if (numBuf > 1) + dma_list->next = &(i2s_info->dma_cfg[I2S_CHANNEL_TX].xfer); + + // Setup and start the DMA engine + if (soc_dma_config(&(i2s_info->dma_ch[I2S_CHANNEL_TX]), &(i2s_info->dma_cfg[I2S_CHANNEL_TX])) != + DRV_RC_OK) + goto fail; + + if (soc_dma_start_transfer(&(i2s_info->dma_ch[I2S_CHANNEL_TX])) != DRV_RC_OK) + goto fail; + + // Enable the channel and let it go! + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[I2S_CHANNEL_TX].ctrl); + reg |= (1 << (i2s_reg_map[I2S_CHANNEL_TX].ctrl_en)); + reg |= (1 << (i2s_reg_map[I2S_CHANNEL_TX].ctrl_sync_rst)); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[I2S_CHANNEL_TX].ctrl) = reg; + + return DRV_RC_OK; fail: - i2s_disable(channel); - soc_dma_release(&(i2s_info->dma_ch[channel])); - return DRV_RC_FAIL; + i2s_disable(I2S_CHANNEL_TX); + soc_dma_release(&(i2s_info->dma_ch[I2S_CHANNEL_TX])); + return DRV_RC_FAIL; } -DRIVER_API_RC soc_i2s_stop_stream(void) +DRIVER_API_RC soc_i2s_stop_transmit(void) { - uint8_t channel = I2S_CHANNEL_TX; - uint32_t save; + uint32_t save; - if (channel >= I2S_NUM_CHANNELS) - { - return DRV_RC_FAIL; - } - else if (!(i2s_info->en[channel])) - { - return DRV_RC_FAIL; - } + if (!(i2s_info->en[I2S_CHANNEL_TX])) + return DRV_RC_FAIL; - save = interrupt_lock(); - i2s_disable(channel); - interrupt_unlock(save); - - return DRV_RC_OK; + save = interrupt_lock(); + i2s_disable(I2S_CHANNEL_TX); + interrupt_unlock(save); + + return DRV_RC_OK; } /* Driver API */ -DRIVER_API_RC soc_i2s_init() +DRIVER_API_RC soc_i2s_init(uint8_t channel) { - int i; - uint32_t reg; + uint32_t reg; - // Prep info struct - for (i = 0; i < I2S_NUM_CHANNELS; i++) - { - i2s_info->en[i] = 0; - i2s_info->cfgd[i] = 0; - i2s_info->cfg[i].cb_done = NULL; - i2s_info->cfg[i].cb_err = NULL; - } + // Prep the channel info struct + i2s_info->en[channel] = 0; + i2s_info->cfgd[channel] = 0; + i2s_info->cfg[channel].cb_done = NULL; + i2s_info->cfg[channel].cb_err = NULL; - // Enable global clock, use local clock gating per channel instead - set_clock_gate(i2s_info->clk_gate_info, CLK_GATE_ON); + if (i2s_info->hw_initialized == 0) + { + // Enable global clock, use local clock gating per channel instead + set_clock_gate(i2s_info->clk_gate_info, CLK_GATE_ON); - // Setup ISR (and enable) - SET_INTERRUPT_HANDLER(i2s_info->int_vector, i2s_interrupt_handler); - SOC_UNMASK_INTERRUPTS(i2s_info->int_mask); + // Setup ISR (and enable) + SET_INTERRUPT_HANDLER(i2s_info->int_vector, i2s_interrupt_handler); + SOC_UNMASK_INTERRUPTS(i2s_info->int_mask); - // Set up control register - reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL); - reg |= (1 << SOC_I2S_CTRL_TR_CFG_0); - reg &= ~(1 << SOC_I2S_CTRL_TSYNC_LOOP_BACK); - reg &= ~(1 << SOC_I2S_CTRL_RSYNC_LOOP_BACK); - MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL) = reg; + // Set up control register + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL); + reg |= (1 << SOC_I2S_CTRL_TR_CFG_0); + reg &= ~(1 << SOC_I2S_CTRL_TSYNC_LOOP_BACK); + reg &= ~(1 << SOC_I2S_CTRL_RSYNC_LOOP_BACK); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL) = reg; - // Set the watermark levels - MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_TFIFO_CTRL) &= 0xFFFCFFFF; - MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_TFIFO_CTRL) |= (I2S_TFIFO_THR << SOC_I2S_TFIFO_CTRL_TAFULL_THRS); + // Set the watermark levels + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_TFIFO_CTRL) &= 0xFFFCFFFF; + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_TFIFO_CTRL) |= (I2S_TFIFO_THR << SOC_I2S_TFIFO_CTRL_TAFULL_THRS); - MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_RFIFO_CTRL) &= 0xFFFCFFFF; - MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_RFIFO_CTRL) |= (I2S_RFIFO_THR << SOC_I2S_RFIFO_CTRL_RAFULL_THRS); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_RFIFO_CTRL) &= 0xFFFCFFFF; + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_RFIFO_CTRL) |= (I2S_RFIFO_THR << SOC_I2S_RFIFO_CTRL_RAFULL_THRS); - // Enable global interrupt mask - reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CID_CTRL); - reg |= (1 << SOC_I2S_CID_CTRL_INTREQ_MASK); - MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CID_CTRL) = reg; + // Enable global interrupt mask + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CID_CTRL); + reg |= (1 << SOC_I2S_CID_CTRL_INTREQ_MASK); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CID_CTRL) = reg; - // Initially, have all channels disabled - for (i = 0; i < I2S_NUM_CHANNELS; i++) - { - i2s_disable(i); - } + i2s_info->hw_initialized = 1; + } - return DRV_RC_OK; + // Initially, have all channels disabled + i2s_disable(channel); + + return DRV_RC_OK; } diff --git a/system/libarc32_arduino101/drivers/soc_i2s.h b/system/libarc32_arduino101/drivers/soc_i2s.h index 61692103..13c637e6 100644 --- a/system/libarc32_arduino101/drivers/soc_i2s.h +++ b/system/libarc32_arduino101/drivers/soc_i2s.h @@ -52,28 +52,13 @@ extern "C" { */ // I2S channels -#define I2S_CHANNEL_TX 0 -#define I2S_CHANNEL_RX 1 +#define I2S_CHANNEL_TX 0 // This is also the DMA channel +#define I2S_CHANNEL_RX 1 // This is also the DMA channel #define I2S_NUM_CHANNELS 2 -// I2S modes -#define I2S_MODE_SCK_POL (0x01) -#define I2S_MODE_WS_POL (0x02) -#define I2S_MODE_LR_ALIGN (0x08) -#define I2S_MODE_SAMPLE_DEL (0x10) -#define I2S_MODE_WS_DSP (0x20) - -#define I2S_MODE_PHILLIPS (I2S_MODE_SCK_POL | I2S_MODE_LR_ALIGN) -#define I2S_MODE_RJ (I2S_MODE_SCK_POL | I2S_MODE_WS_POL | \ - I2S_MODE_SAMPLE_DEL) -#define I2S_MODE_LJ (I2S_MODE_SCK_POL | I2S_MODE_WS_POL | \ - I2S_MODE_LR_ALIGN | I2S_MODE_SAMPLE_DEL) -#define I2S_MODE_DSP (I2S_MODE_SCK_POL | I2S_MODE_LR_ALIGN | \ - I2S_MODE_WS_DSP) - // I2S configuration object struct soc_i2s_cfg { - uint16_t sample_rate; // in Hz + uint16_t clk_divider; // 32 MHz /(sample x 2 x rate) uint8_t resolution; uint8_t mode; uint8_t master; @@ -101,6 +86,8 @@ struct soc_i2s_info { struct soc_dma_channel dma_ch[I2S_NUM_CHANNELS]; struct clk_gate_info_s *clk_gate_info; + + uint32_t hw_initialized; }; extern struct driver soc_i2s_driver; @@ -143,21 +130,22 @@ DRIVER_API_RC soc_i2s_deconfig(uint8_t channel); * - DRV_RC_OK on success * - DRV_RC_FAIL otherwise */ -DRIVER_API_RC soc_i2s_write(void *buf, uint32_t len, uint32_t len_per_data); +DRIVER_API_RC soc_i2s_write(void *buf, int bufSize, int dataSize); /** - * Function to continuously transmit blocks of audio data + * Function to continuously transmit blocks of audio data in round a robin fashion * - * @param buf : pointer to buffer to read data from - * @param len : length of buffer (in bytes) - * @param num_bufs : number of parts into which to split the buffer; calling the callback - * after each is sent + * @param bufPtrArray : an array of buffer pointers (addresses) + * @param numBuf : number of buffers for transmission (in bufPtrArray) + * @param bufSize : length of buffer (in bytes) + * @param dataSize : data size - 8, 16, 32 bits (in bytes) * * @return * - DRV_RC_OK on success * - DRV_RC_FAIL otherwise */ -DRIVER_API_RC soc_i2s_stream(void *buf, uint32_t len, uint32_t len_per_data, uint32_t num_bufs); +DRIVER_API_RC soc_i2s_transmit_loop(void *bufPtrArray[], int numBuf, int bufSize, + int dataSize); /** * Function to stop a continuous audio data write @@ -166,7 +154,7 @@ DRIVER_API_RC soc_i2s_stream(void *buf, uint32_t len, uint32_t len_per_data, uin * - DRV_RC_OK on success * - DRV_RC_FAIL otherwise */ -DRIVER_API_RC soc_i2s_stop_stream(void); +DRIVER_API_RC soc_i2s_stop_transmit(void); /** * Function to receive a block of audio data @@ -203,7 +191,7 @@ DRIVER_API_RC soc_i2s_listen(void *buf, uint32_t len, uint32_t len_per_data, ui */ DRIVER_API_RC soc_i2s_stop_listen(void); -DRIVER_API_RC soc_i2s_init(); +DRIVER_API_RC soc_i2s_init(uint8_t channel); /** @} */ diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index e0cb6b8e..1eabd669 100644 Binary files a/variants/arduino_101/libarc32drv_arduino101.a and b/variants/arduino_101/libarc32drv_arduino101.a differ