197 lines
4.8 KiB
C
197 lines
4.8 KiB
C
/*
|
|
* tlv320.c
|
|
*
|
|
* Created on: 2021. okt. 24.
|
|
* Author: epagris
|
|
*/
|
|
|
|
#include "tlv320.h"
|
|
#include <string.h>
|
|
|
|
static I2C_HandleTypeDef * sphI2C; // handle pointer for I2C peripheral TLV320 is connected to
|
|
static TLV320_State sState; // state
|
|
static uint8_t spBuf[2]; // transmit buffer
|
|
static bool sFullUpdate = false; // do a full update
|
|
|
|
#define TLV320_REGARR_SIZE (9) // register array size NOT INCLUDING activation and reset register
|
|
static uint16_t sRS[TLV320_REGARR_SIZE], sRS_prev[TLV320_REGARR_SIZE]; // register state and previous register state
|
|
|
|
|
|
static void TLV320_write(uint8_t addr, uint16_t value) {
|
|
spBuf[0] = (uint8_t)((addr << 1) | ((value >> 8) & 1));
|
|
spBuf[1] = (uint8_t)(value & 0xFF);
|
|
HAL_I2C_Master_Transmit(sphI2C, sState.i2c_addr, spBuf, 2, 1000);
|
|
}
|
|
|
|
void TLV320_init(I2C_HandleTypeDef * phI2C, uint8_t i2c_addr) {
|
|
sphI2C = phI2C;
|
|
sState.i2c_addr = i2c_addr;
|
|
|
|
TLV320_reset();
|
|
}
|
|
|
|
void TLV320_updateOptions(TLV320_Options * pOpt) {
|
|
// save previous state
|
|
memcpy(sRS_prev, sRS, TLV320_REGARR_SIZE * sizeof(uint16_t));
|
|
|
|
// fill in bitfields
|
|
/* LEFT LINE INPUT CHANNEL */
|
|
sRS[0] = (pOpt->LRS << 8) | (pOpt->LIM << 7) | (pOpt->LIV & 0b11111);
|
|
|
|
/* RIGHT LINE INPUT CHANNEL */
|
|
sRS[1] = (pOpt->RLS << 8) | (pOpt->RIM << 7) | (pOpt->RIV & 0b11111);
|
|
|
|
/* LEFT HEADPHONE CHANNEL */
|
|
sRS[2] = (pOpt->LRS_HP << 8) | (pOpt->LZC << 7) | (pOpt->LHV & 0b1111111);
|
|
|
|
/* RIGHT HEADPHONE CHANNEL */
|
|
sRS[3] = (pOpt->RLS_HP << 8) | (pOpt->RZC << 7) | (pOpt->RHV & 0b1111111);
|
|
|
|
/* ANALOG AUDIO PATH CONTROL */
|
|
sRS[4] = ((pOpt->STA_STE & 0b1111) << 5) | (pOpt->DAC_SEL << 4) | (pOpt->BYP << 3) | (pOpt->INSEL << 2) | (pOpt->MICM << 1) | (pOpt->MICB);
|
|
|
|
/* DIGITAL AUDIO PATH CONTROL */
|
|
sRS[5] = (pOpt->DACM << 3) | ((pOpt->DEEMP & 0b11) << 1) | (pOpt->ADCHP) | 0;
|
|
|
|
/* POWER DOWN CONTROL */
|
|
sRS[6] = (pOpt->PD_OFF << 7) | (pOpt->PD_CLK << 6) | (pOpt->PD_OSC << 5) |
|
|
(pOpt->PD_OUT << 4) | (pOpt->PD_DAC << 3) | (pOpt->PD_ADC << 2) |
|
|
(pOpt->PD_MIC << 1) | (pOpt->PD_LINE);
|
|
|
|
/* DIGITAL AUDIO INTERFACE FORMAT */
|
|
sRS[7] = (pOpt->MS << 6) | (pOpt->LRSWAP << 5) | (pOpt->LRP << 4) | ((pOpt->IWL & 0b11) << 2) | ((pOpt->FOR) & 0b11);
|
|
|
|
/* SAMPLE RATE CONTROL */
|
|
sRS[8] = (pOpt->CLKOUT << 7) | (pOpt->CLKIN << 6) | ((pOpt->SR & 0b1111) << 2) | (pOpt->BOSR << 1) | (pOpt->USB_Normal);
|
|
|
|
// compare old and new state
|
|
uint8_t i;
|
|
for (i = 0; i < TLV320_REGARR_SIZE; i++) {
|
|
if (sRS[i] != sRS_prev[i] || sFullUpdate) { // if register content has changed...
|
|
TLV320_write(i, sRS[i]); // ...then write to device
|
|
}
|
|
}
|
|
|
|
// save new settings
|
|
if (pOpt != &sState.options) {
|
|
sState.options = *pOpt;
|
|
}
|
|
|
|
// full update done
|
|
sFullUpdate = false;
|
|
}
|
|
|
|
void TLV320_reset() {
|
|
TLV320_Options * pOpt = &sState.options;
|
|
memcpy(sRS_prev, sRS, TLV320_REGARR_SIZE * sizeof(uint16_t));
|
|
|
|
// reset options
|
|
|
|
/* LEFT LINE INPUT */
|
|
pOpt->LRS = 0;
|
|
pOpt->LIM = 1;
|
|
pOpt->LIV = 0b10111;
|
|
|
|
/* RIGHT LINE INPUT */
|
|
pOpt->RLS = 0;
|
|
pOpt->RIM = 1;
|
|
pOpt->RIV = 0b10111;
|
|
|
|
/* LEFT HP CHANNEL */
|
|
pOpt->LRS_HP = 0;
|
|
pOpt->LZC = 1;
|
|
pOpt->LHV = 0b1111001;
|
|
|
|
/* RIGHT HP CHANNEL */
|
|
pOpt->RLS_HP = 0;
|
|
pOpt->RZC = 1;
|
|
pOpt->RHV = 0b1111001;
|
|
|
|
/* ANALOG AUDIO PATH */
|
|
pOpt->STA_STE = 0;
|
|
pOpt->DAC_SEL = 0;
|
|
pOpt->BYP = 1;
|
|
pOpt->INSEL = 0;
|
|
pOpt->MICM = 1;
|
|
pOpt->MICB = 0;
|
|
|
|
/* DIGITAL AUDIO PATH */
|
|
pOpt->DACM = 1;
|
|
pOpt->DEEMP = 0;
|
|
pOpt->ADCHP = 0;
|
|
|
|
/* POWER DOWN CONTROL */
|
|
pOpt->PD_OFF = 0;
|
|
pOpt->PD_CLK = 0;
|
|
pOpt->PD_OSC = 0;
|
|
pOpt->PD_OUT = 0;
|
|
pOpt->PD_DAC = 0;
|
|
pOpt->PD_ADC = 1;
|
|
pOpt->PD_MIC = 1;
|
|
pOpt->PD_LINE = 1;
|
|
|
|
/* DIGITAL AUDIO INTERFACE FORMAT */
|
|
pOpt->MS = 0;
|
|
pOpt->LRSWAP = 0;
|
|
pOpt->LRP = 0;
|
|
pOpt->IWL = 0;
|
|
pOpt->FOR = 1;
|
|
|
|
/* SAMPLE RATE CONTROL */
|
|
pOpt->CLKIN = 0;
|
|
pOpt->CLKOUT = 0;
|
|
pOpt->SR = 8;
|
|
pOpt->BOSR = 0;
|
|
pOpt->USB_Normal = 0;
|
|
|
|
|
|
// digital interface activation
|
|
//TLV320_write(0x09, 1);
|
|
|
|
// reset device
|
|
TLV320_write(0x0F, 0);
|
|
|
|
// digital interface activation
|
|
//TLV320_write(0x09, 1);
|
|
}
|
|
|
|
void TLV320_getOptions(TLV320_Options *pOpt) {
|
|
*pOpt = sState.options;
|
|
}
|
|
|
|
void TLV320_activate() {
|
|
TLV320_write(0x09, 1);
|
|
}
|
|
|
|
void TLV320_fullUpdate(TLV320_Options *pOpt) {
|
|
sFullUpdate = true;
|
|
TLV320_updateOptions(pOpt);
|
|
}
|
|
|
|
#define _MAX(x,y) ((x > y) ? (x) : (y))
|
|
#define _MIN(x,y) ((x < y) ? (x) : (y))
|
|
#define _LIMIT(x,l,h) _MIN(_MAX(x,l),h)
|
|
|
|
#define TLV320_GAIN_MIN_CB (-345)
|
|
#define TLV320_GAIN_MAX_CB (120)
|
|
#define TLV320_GAIN_MIN_VAL (0)
|
|
#define TLV320_GAIN_MAX_VAL (31)
|
|
#define TLV320_GAIN_QUANTUM_CB (15)
|
|
#define TLV320_GAIN_UNITY_VAL (23)
|
|
|
|
void TLV320_setLineInGain(double dB) {
|
|
int cB = dB * 10; // deciBel -> centiBel
|
|
|
|
// calculate register value
|
|
uint8_t val = cB / TLV320_GAIN_QUANTUM_CB + TLV320_GAIN_UNITY_VAL;
|
|
|
|
// limit clipping
|
|
val = _LIMIT(val, TLV320_GAIN_MIN_VAL, TLV320_GAIN_MAX_VAL);
|
|
|
|
// push new volume value
|
|
sState.options.RIV = sState.options.LIV = val;
|
|
|
|
// update options
|
|
TLV320_updateOptions(&sState.options);
|
|
}
|