More readable TLV320 Lib
Revision 0:808bb0b9cf45, committed 2014-10-22
- Comitter:
- hollegha
- Date:
- Wed Oct 22 09:23:47 2014 +0000
- Commit message:
- More readable TLV320-Lib
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/I2SSlaveHL.cpp Wed Oct 22 09:23:47 2014 +0000 @@ -0,0 +1,247 @@ + +#include "I2SSlaveHL.h" + +FunctionPointer akjnh3489v8ncv; + +extern "C" void I2S_IRQHandler(void) { + akjnh3489v8ncv.call(); +} + +#undef MBV +#define MBV(num) (1<<num) + +I2SSlave::I2SSlave(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws) +{ + storePins_(tx_sda, tx_ws, clk, rx_sda, rx_ws); + format(16, STEREO); +} + +void I2SSlave::format(int bit, bool mode) +{ + bit_ = bit; + mode_ = mode; + initialize_(tx_sda_, tx_ws_, clk_, rx_sda_, rx_ws_); +} + + +void I2SSlave::Write(int32_t aLeft, int32_t aRight) +{ + int32_t lr = (aRight << 16) + aLeft; + LPC_I2S->I2STXFIFO = lr; +} + +void I2SSlave::Read(int32_t* aLeft, int32_t* aRight) +{ + int32_t v32 = LPC_I2S->I2SRXFIFO; + *aLeft = (int16_t)v32; + *aRight = (int16_t)(v32 >> 16); +} + + + +void I2SSlave::start(int mode) +{ + switch(mode){ + case(0): + LPC_I2S->I2SIRQ |= (0 << 0); //disable receive interrupt + LPC_I2S->I2SIRQ |= (0 << 1); //disable transmit interrupt + break; + case(1): + LPC_I2S->I2SIRQ |= (0 << 0); //disable receive interrupt + LPC_I2S->I2SIRQ |= (1 << 1); //enable transmit interrupt + LPC_I2S->I2SIRQ |= (0 << 16); //set I2STXFIFO depth to 0 words + break; + case(2): + LPC_I2S->I2SIRQ |= (1 << 0); //enable receive interrupt + LPC_I2S->I2SIRQ |= (0 << 1); //disable transmit interrupt + LPC_I2S->I2SIRQ |= (4 << 8); //set I2SRXFIFO depth to 4 words + break; + case(3): + LPC_I2S->I2SIRQ |= (1 << 0); //enable receive interrupt + LPC_I2S->I2SIRQ |= (4 << 8); //set I2SRXFIFO depth to 4 words + LPC_I2S->I2SIRQ |= (1 << 1); //enable transmit interrupt + LPC_I2S->I2SIRQ |= (0 << 16); //set I2STXFIFO depth to 0 words + break; + default: + break; + } + NVIC_SetPriority(I2S_IRQn, 0); + NVIC_EnableIRQ(I2S_IRQn); //enable I2S interrupt in the NVIC +} + +void I2SSlave::Start() +{ + LPC_I2S->I2SIRQ = 0; + LPC_I2S->I2SIRQ |= MBV(0); // ena RecvIRQ + // LPC_I2S->I2SIRQ |= MBV(8); // Rx-Level=1 + LPC_I2S->I2SIRQ |= MBV(11); // Rx-Level=8 + NVIC_SetPriority(I2S_IRQn, 0); + NVIC_EnableIRQ(I2S_IRQn); +} + +void I2SSlave::Stop() +{ + NVIC_DisableIRQ(I2S_IRQn); +} + +int I2SSlave::status(void) +{ + return LPC_I2S->I2SSTATE; +} + +int I2SSlave::GetRxLevel() +{ + int val = LPC_I2S->I2SSTATE >> 8; + return (0x0000000F & val); +} + +int I2SSlave::GetTxLevel() +{ + int val = LPC_I2S->I2SSTATE >> 16; + return (0x0000000F & val); +} + + +int I2SSlave::initialize_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws) +{ + setPins_(tx_sda, tx_ws, clk, rx_sda, rx_ws); // designate pins + LPC_SC->PCONP |= (1 << 27); + //configure input/output register + format_(bit_, mode_); + //set mbed as SLAVE + LPC_I2S->I2SDAO |= (1 << 5); + LPC_I2S->I2SDAI |= (1 << 5); + //clock mode + setClocks_(4); + //set slave mode + modeConfig_(); + //set receiver mode + LPC_I2S->I2SRXMODE |= (1 << 1); + //slave mode + LPC_I2S->I2STXRATE = 0; + LPC_I2S->I2SRXRATE = 0; + //Start + LPC_I2S->I2SDAO |= (0 << 3); + LPC_I2S->I2SDAI |= (0 << 3); + LPC_I2S->I2SDAO |= (0 << 4); + LPC_I2S->I2SDAI |= (0 << 4); + LPC_I2S->I2SDAO |= (0 << 15); + return 0; +} + +// Set the division setting on the internal clocks +void I2SSlave::setClocks_(int divideBy) +{ + switch(divideBy){ + case 1: + LPC_SC->PCLKSEL1 |= (1 << 22); + LPC_SC->PCLKSEL1 |= (0 << 23); + break; + case 2: + LPC_SC->PCLKSEL1 |= (0 << 22); + LPC_SC->PCLKSEL1 |= (1 << 23); + break; + case 4: + LPC_SC->PCLKSEL1 |= (0 << 22); + LPC_SC->PCLKSEL1 |= (0 << 23); + break; + case 8: + LPC_SC->PCLKSEL1 |= (1 << 22); + LPC_SC->PCLKSEL1 |= (1 << 23); + break; + default: + break; + } +} + +void I2SSlave::setPins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws) +{ + if(rx_ws == p29){ + LPC_PINCON->PINSEL0 |= (1 << 10); //set p29 as receive word select line + } else { + LPC_PINCON->PINSEL1 |= (2 << 16); //set p16 as receive word select line + } + if(rx_sda == p8){ + LPC_PINCON->PINSEL0 |= (1 << 12); //set p8 as receive serial data line + } else { + LPC_PINCON->PINSEL1 |= (2 << 18); //set p17 as receive serial data line + } + LPC_PINCON->PINSEL0 |= (1 << 14); //set p7 as transmit clock line (only one of these) + LPC_PINCON->PINSEL0 |= (1 << 16); //set p6 as word select line (only one of these) + LPC_PINCON->PINSEL0 |= (1 << 18); //set p5 as transmit serial data line (only one of these) + LPC_PINCON->PINSEL0 |= (0 << 8); //clear rx_clk +} + + +void I2SSlave::format_(int bit, bool mode) +{ + uint32_t bps= ((bit+1)*8)-1; + LPC_I2S->I2SDAO &= (0x00 << 6); + LPC_I2S->I2SDAO |= (bps << 6); + //set bit length + switch(bit){ + case 8: + LPC_I2S->I2SDAO &= 0xfffffffc; + break; + case 16: + LPC_I2S->I2SDAO &= (0 << 1); + LPC_I2S->I2SDAO |= (1 << 0); + break; + case 32: + LPC_I2S->I2SDAO &= (0 << 1); + LPC_I2S->I2SDAO |= (3 << 0); + break; + default: + break; + } + //set audio mode + if(mode == STEREO){ + LPC_I2S->I2SDAO |= (0 << 2); + } else { + LPC_I2S->I2SDAO |= (1 << 2); + } + //set transmitter and receiver setting to be the same + LPC_I2S->I2SDAI &= (0x00 << 6); + LPC_I2S->I2SDAI |= (bps << 6); + //set bit length + switch(bit){ + case 8: + LPC_I2S->I2SDAI &= 0xfffffffc; + break; + case 16: + LPC_I2S->I2SDAI &= (0 << 1); + LPC_I2S->I2SDAI |= (1 << 0); + break; + case 32: + LPC_I2S->I2SDAI &= (0 << 1); + LPC_I2S->I2SDAI |= (3 << 0); + break; + default: + break; + } + //set audio mode + if(mode == STEREO){ + LPC_I2S->I2SDAI |= (0 << 2); + } else { + LPC_I2S->I2SDAI |= (1 << 2); + } +} + + +void I2SSlave::modeConfig_(void) +{ + LPC_I2S->I2STXMODE |= (0x0 << 0); + LPC_I2S->I2SRXMODE |= (0x0 << 0); +} + + +void I2SSlave::storePins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws) +{ + tx_sda_ = tx_sda; + tx_ws_ = tx_ws; + clk_ = clk; + rx_sda_ = rx_sda; + rx_ws_ = rx_ws; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/I2SSlaveHL.h Wed Oct 22 09:23:47 2014 +0000 @@ -0,0 +1,126 @@ + +#include "mbed.h" +#include "math.h" + +#ifndef __MBED_I2SSLAVE_H__ +#define __MBED_I2SSLAVE_H__ + +extern FunctionPointer akjnh3489v8ncv; + + +class I2SSlave{ + public: + /* @param tx_sda Transmitter serial data line + * @param tx_ws Transmitter word select line + * @param clk Shared transmitter/receiver clock line + * @param rx_sda Receiver serial data line + * @param rx_ws Receiver word select line */ + I2SSlave(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws); + + // bit Set the number of bits per write + // STEREO (0) or MONO (1) mode + void format(int bit, bool mode); + + void Write(int32_t aLeft, int32_t aRight); + + void Read(int32_t* aLeft, int32_t* aRight); + + // Mode to enable - NONE, TRANSMIT only, RECEIVE only, BOTH + // Enables tx/rx interrupts + void start(int mode); + + void Start(); + void Stop(); + + void attach(void(*fptr)(void)){ + akjnh3489v8ncv.attach(fptr); + } + + template<typename T> + void attach(T *tptr, void(T::*mptr)(void)){ + akjnh3489v8ncv.attach(tptr, mptr); + } + + // bit0: receive/transmit interrupt active + // bit1: receive/transmit DMA request 1 + // bit2: receive/transmit DMA request 2 + // bit[11:8]: receive FIFO level + // bit[19:16]: transmit FIFO level + int status(); + + int GetRxLevel(); + int GetTxLevel(); + + //defines + #define STEREO 0 + #define MONO 1 + + #define I2SFIFO_EMPTY 0 + #define I2SFIFO_FULL 8 + + #define RAM_LENGTH 1024 + #define RAM_LIMIT (RAM_LENGTH - 1) + #define PTR_MAX ((RAM_LENGTH / 8) - 1) + + #define NONE 0 + #define TRANSMIT 1 + #define RECEIVE 2 + #define BOTH 3 + + private: + /** I2S intitalize function + * + * @param tx_sda Transmitter serial data line + * @param tx_ws Transmitter word select line + * @param clk Shared transmitter/receiver clock line + * @param rx_sda Receiver serial data line + * @param rx_ws Receiver word select line + * @return Returns 0 for successful initialisation, -1 for an error + */ + int initialize_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws); + /** Set internal clock divide by rate + * + * @param divideBy Divide by 1, 2, 4 or 8 + */ + void setClocks_(int divideBy); + /** Set up the pins on the processor itself + * + * @param tx_sda Transmitter serial data line + * @param tx_ws Transmitter word select line + * @param clk Shared transmitter/receiver clock line + * @param rx_sda Receiver serial data line + * @param rx_ws Receiver word select line + */ + void setPins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws); + /** Set the data transmission format + * + * @param bit Set the number of bits per write + * @param mode Set STEREO (0) or MONO (1) mode + */ + void format_(int bit, bool mode); + + // Set slave mode + void modeConfig_(void); + + /** Store PinName values + * + * @param tx_sda Transmitter serial data line + * @param tx_ws Transmitter word select line + * @param clk Shared transmitter/receiver clock line + * @param rx_sda Receiver serial data line + * @param rx_ws Receiver word select line + */ + void storePins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws); + //variables + int bit_; + bool mode_; + PinName tx_sda_; + PinName tx_ws_; + PinName clk_; + PinName rx_sda_; + PinName rx_ws_; +}; + +#endif /*__MBED_I2S_H__*/ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TLV320HL.cpp Wed Oct 22 09:23:47 2014 +0000 @@ -0,0 +1,230 @@ + +#include "mbed.h" +#include "TLV320HL.h" + + +TLV320::TLV320(PinName sda, PinName scl, int addr, I2SSlave* aI2S) +: mAddr(addr), mI2c_(sda, scl) +{ + mI2S = aI2S; +} + +void TLV320::Init(int aFrequ) +{ + mI2c_.frequency(100000); + reset(); //TLV resets + wait_ms(100); + power(true); + // power(0x07); Power Up the TLV320, but not the MIC, ADC and LINE + format(16, STEREO); //16Bit I2S protocol format, STEREO + frequency(aFrequ); //Default sample frequency is 44.1kHz + bypass(false); //Do not bypass device + mute(false); //Not muted + activateDigitalInterface_(); //The digital part of the chip is active + // outputVolume(0.7, 0.7); //Headphone volume to the default state + inputVolume(1,1); + outputVolume(0.92,0.92); +} + + +// Returns: int 0 (success), -1 (value out of range) +int TLV320::inputVolume(float leftVolumeIn, float rightVolumeIn) +{ + //check values are in range + if((leftVolumeIn < 0.0)||leftVolumeIn > 1.0) return -1; + if((rightVolumeIn < 0.0)||rightVolumeIn > 1.0) return -1; + //convert float to encoded char + char left = (char)31*leftVolumeIn; + char right = (char)31*rightVolumeIn; + //Left Channel + cmd[1] = left | (0 << 7); //set volume + cmd[0] = LEFT_LINE_INPUT_CHANNEL_VOLUME_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send + //Right Channel + cmd[1] = right | (0 << 7); //set volume + cmd[0] = RIGHT_LINE_INPUT_CHANNEL_VOLUME_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send + return 0; +} + + +// Description: Set headphone (line out) volume for left an right channels +// Returns: int 0 (success), -1 (value out of range) +int TLV320::outputVolume(float leftVolumeOut, float rightVolumeOut) +{ + //check values are in range + if((leftVolumeOut < 0.0)||leftVolumeOut > 1.0) return -1; + if((rightVolumeOut < 0.0)||rightVolumeOut > 1.0) return -1; + //convert float to encoded char + char left = (char)(79*leftVolumeOut)+0x30; + char right = (char)(79*rightVolumeOut)+0x30; + //Left Channel + cmd[1] = left | (1 << 7); //set volume + cmd[0] = LEFT_CHANNEL_HEADPHONE_VOLUME_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send + //Right Channel + cmd[1] = right | (1 << 7); //set volume + cmd[0] = RIGHT_CHANNEL_HEADPHONE_VOLUME_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send + return 0; +} + + +// Description: Send TLV320 into bypass mode, i.e. connect input to output +void TLV320::bypass(bool bypassVar) +{ + if(bypassVar == true) + cmd[1] = (1 << 3) | (0 << 4) | (0 << 5);//bypass enabled, DAC disabled, sidetone insertion disabled + else + cmd[1] = (0 << 3) | (1 << 4); //bypass disabled, DAC enabled + cmd[1] |= (0 << 2); + cmd[0] = ANALOG_AUDIO_PATH_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send +} + + +// Send TLV320 into mute mode +void TLV320::mute(bool softMute) +{ + if(softMute == true) cmd[1] = 0x08; //set instruction to mute + else cmd[1] = 0x00; //set instruction to NOT mute + cmd[0] = DIGITAL_AUDIO_PATH_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send +} + + +// Switch TLV320 on/off +void TLV320::power(bool powerUp) +{ + if(powerUp == true) cmd[1] = 0x00; //everything on + else cmd[1] = 0xFF; //everything off + cmd[0] = POWER_DOWN_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send +} + + +// Switch on individual devices on TLV320 +void TLV320::power(int device) +{ + cmd[1] = (char)device; //set user defined commands + cmd[0] = POWER_DOWN_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send +} + + +void TLV320::format(char length, bool mode) +{ + char modeSet = (1 << 6); + modeSet |= (1 << 5); //swap left and right channels + switch (length) //input data into instruction byte + { + case 16: + cmd[1] = modeSet | 0x02; + break; + case 20: + cmd[1] = modeSet | 0x06; + break; + case 24: + cmd[1] = modeSet | 0x0A; + break; + case 32: + cmd[1] = modeSet | 0x0E; + break; + default: + break; + } + mI2S->format(length, mode); + cmd[0] = DIGITAL_AUDIO_INTERFACE_FORMAT; //set address + mI2c_.write(mAddr, cmd, 2); //send +} + + +int TLV320::frequency(int hz) +{ + char rate; + switch(hz){ + case 8000: + rate = 0x03; + break; + case 8021: + rate = 0x0B; + break; + case 32000: + rate = 0x06; + break; + case 44100: + rate = 0x08; + break; + case 48000: + rate = 0x00; + break; + case 88200: + rate = 0x0F; + break; + case 96000: + rate = 0x07; + break; + default: + return -1; + } + char clockInChar = (0 << 6); + // char clockModeChar = (1 << 0); + char clockModeChar = (0 << 0); // Kogler + + cmd[1] = (rate << 2) | clockInChar | clockModeChar; //input data into instruciton byte + cmd[0] = SAMPLE_RATE_CONTROL; //set address + mI2c_.write(mAddr, cmd, 2); //send + return 0; +} + + +void TLV320::reset(void) +{ + cmd[0] = RESET_REGISTER; //set address + cmd[1] = 0x00; //this resets the entire device + mI2c_.write(mAddr, cmd, 2); +} + +void TLV320::setSampleRate_(char rate, bool clockIn, bool clockMode, bool bOSR) +{ + char clockInChar; + char clockModeChar; + char baseOverSamplingRate; + if(bOSR){ + baseOverSamplingRate = (1 << 0); + } else { + baseOverSamplingRate = (0 << 0); + } + if(clockIn){ + clockInChar = (1 << 6); + } else { + clockInChar = (0 << 6); + } + if(clockMode){ + clockModeChar = 0x01; + } else { + clockModeChar = 0x00; + } + cmd[1] = (rate << 2) | clockInChar | clockModeChar | baseOverSamplingRate; //input data into instruciton byte + cmd[0] = SAMPLE_RATE_CONTROL; // set address + mI2c_.write(mAddr, cmd, 2); // send +} + + +void TLV320::activateDigitalInterface_(void) +{ + cmd[1] = 0x01; //Activate + cmd[0] = DIGITAL_INTERFACE_ACTIVATION; //set address + mI2c_.write(mAddr, cmd, 2); //send +} + +void TLV320::deactivateDigitalInterface_(void) +{ + cmd[1] = 0x00; //Deactivate + cmd[0] = DIGITAL_INTERFACE_ACTIVATION; //set address + mI2c_.write(mAddr, cmd, 2); //send +} + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TLV320HL.h Wed Oct 22 09:23:47 2014 +0000 @@ -0,0 +1,105 @@ + +#ifndef MBED_TLV320_H +#define MBED_TLV320_H + +#include "mbed.h" +#include "I2SSlaveHL.h" + +class TLV320 { + public: + // sda Serial data pin (p9 or p28) + // scl Serial clock pin (p10 or p27) + // addr Object address + TLV320(PinName sda, PinName scl, int addr, I2SSlave* aI2S); + + void Init(int aFrequ); + + // 0 = power down, 1 = power up + void power(bool powerUp); + + /** Overloaded power() function default = 0x07, record requires 0x02 + * @param device Call individual devices to power up/down + * Device power 0x00 = On 0x80 = Off + * Clock 0x00 = On 0x40 = Off + * Oscillator 0x00 = On 0x20 = Off + * Outputs 0x00 = On 0x10 = Off + * DAC 0x00 = On 0x08 = Off + * ADC 0x00 = On 0x04 = Off + * Microphone input 0x00 = On 0x02 = Off + * Line input 0x00 = On 0x01 = Off */ + void power(int device); + + /** Set I2S interface bit length and mode + * @param length Set bit length to 16, 20, 24 or 32 bits + * @param mode Set STEREO (0), MONO (1) */ + void format(char length, bool mode); + + // Returns an integer 0 = success, -1 = unrecognnised frequency + // The TLV320 supports the following frequencies: 8kHz, 8.021kHz, 32kHz, 44.1kHz, 48kHz, 88.2kHz, 96kHz + // Default is 44.1kHz + int frequency(int hz); + + // Reset TLV320 + void reset(void); + + /** Line in volume control i.e. record volume + * @return Returns 0 for success, -1 if parameters are out of range + * Parameters accept a value, where 0.0 < parameter < 1.0 and where 0.0 maps to -34.5dB + * and 1.0 maps to +12dB (0.74 = 0 dB default). */ + int inputVolume(float leftVolumeIn, float rightVolumeIn); + + /** Headphone out volume control + * @return Returns 0 for success, -1 if parameters are out of range + * Parameters accept a value, where 0.0 < parameter < 1.0 and where 0.0 maps to -73dB (mute) + * and 1.0 maps to +6dB (0.5 = default) */ + int outputVolume(float leftVolumeOut, float rightVolumeOut); + + // Analog audio path control + // @param bypassVar Route analogue audio direct from line in to headphone out + void bypass(bool bypassVar); + + // Digital audio path control + // @param softMute Mute output + void mute(bool softMute); + + protected: + char cmd[2]; //the address and command for TLV320 internal registers + int mAddr; //register write address + private: + I2C mI2c_; + I2SSlave* mI2S; + + /** Sample rate control + * @param rate Set the sampling rate as per datasheet section 3.3.2 + * @param clockIn Set the clock in divider MCLK, MCLK_DIV2 + * @param clockMode Set clock mode CLOCK_NORMAL, CLOCK_USB */ + void setSampleRate_(char rate, bool clockIn, bool mode, bool bOSR); + + // Digital interface activation + void activateDigitalInterface_(void); + + // Digital interface deactivation + void deactivateDigitalInterface_(void); + + //TLV320AIC23B register addresses as defined in the TLV320AIC23B datasheet + #define LEFT_LINE_INPUT_CHANNEL_VOLUME_CONTROL (0x00 << 1) + #define RIGHT_LINE_INPUT_CHANNEL_VOLUME_CONTROL (0x01 << 1) + #define LEFT_CHANNEL_HEADPHONE_VOLUME_CONTROL (0x02 << 1) + #define RIGHT_CHANNEL_HEADPHONE_VOLUME_CONTROL (0x03 << 1) + #define ANALOG_AUDIO_PATH_CONTROL (0x04 << 1) + #define DIGITAL_AUDIO_PATH_CONTROL (0x05 << 1) + #define POWER_DOWN_CONTROL (0x06 << 1) + #define DIGITAL_AUDIO_INTERFACE_FORMAT (0x07 << 1) + #define SAMPLE_RATE_CONTROL (0x08 << 1) + #define DIGITAL_INTERFACE_ACTIVATION (0x09 << 1) + #define RESET_REGISTER (0x0F << 1) + + #define CLOCK_NORMAL 0 + #define CLOCK_USB 1 + #define MCLK 0 + #define MCLK_DIV2 1 +}; + +#endif + +