Управление DSP

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

Здравствуйте. Может кто подсказать как управлять STA309A, или TAS5508 с arduino? Управление идет по i2C, а вот какие данные отправлять не совсем понятно. Например, для STA309A нужно отправить массив значений только на эквалайзер

Speaker_EQ_Table_48000[] = {
	{0x00,0x000000},{0x01,0x000000},{0x02,0x000000},{0x03,0x000000},{0x04,0x400000},    // 48KFs, Biquad1, Address: 0x00~0x04 (stability: 0.0000)
	{0x05,0x000000},{0x06,0x000000},{0x07,0x000000},{0x08,0x000000},{0x09,0x400000},    // 48KFs, Biquad2, Address: 0x05~0x09 (stability: 0.0000)
	{0x0A,0x000000},{0x0B,0x000000},{0x0C,0x000000},{0x0D,0x000000},{0x0E,0x400000},    // 48KFs, Biquad3, Address: 0x0A~0x0E (stability: 0.0000)
	{0x0F,0x000000},{0x10,0x000000},{0x11,0x000000},{0x12,0x000000},{0x13,0x400000},    // 48KFs, Biquad4, Address: 0x0F~0x13 (stability: 0.0000)
	{0x14,0x000000},{0x15,0x000000},{0x16,0x000000},{0x17,0x000000},{0x18,0x400000},    // 48KFs, Biquad5, Address: 0x14~0x18 (stability: 0.0000)
	{0x19,0x000000},{0x1A,0x000000},{0x1B,0x000000},{0x1C,0x000000},{0x1D,0x400000},    // 48KFs, Biquad6, Address: 0x19~0x1D (stability: 0.0000)
	{0x1E,0x000000},{0x1F,0x000000},{0x20,0x000000},{0x21,0x000000},{0x22,0x400000},    // 48KFs, Biquad7, Address: 0x1E~0x22 (stability: 0.0000)
	{0x23,0x000000},{0x24,0x000000},{0x25,0x000000},{0x26,0x000000},{0x27,0x400000},    // 48KFs, Biquad8, Address: 0x23~0x27 (stability: 0.0000)
	{0x28,0x000000},{0x29,0x000000},{0x2A,0x000000},{0x2B,0x000000},{0x2C,0x400000},    // 48KFs, Biquad9, Address: 0x28~0x2C (stability: 0.0000)
	{0x2D,0x000000},{0x2E,0x000000},{0x2F,0x000000},{0x30,0x000000},{0x31,0x400000}     // 48KFs, Biquad10, Address: 0x2D~0x31 (stability: 0.0000)
};

А там параметров намного больше.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

А Вы дэйташит на него внимательно изучали?

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

Даташиты не очень умею читать в части управления, многого не понимаю. Просто есть программа для конфигурирования этих чипов, это из нее.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Так что Вы хотите, чтобы кто-то внимательно изучил дэйташит и пересказал Вам?

Но если Вы не понимаете сам дэйташит, то почему думаете, что сможете понять пересказ?

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

Не так. Просто я не понимаю, мне все эти массивы слать туда, или как-то проще можно сделать. 

Volume control
0x09 MMUTE Reserved MMUTE
0x0A MVOL MV7 MV6 MV5 MV4 MV3 MV2 MV1 MV0
0x0B C1VOL C1V7 C1V6 C1V5 C1V4 C1V3 C1V2 C1V1 C1V0
0x0C C2VOL C2V7 C2V6 C2V5 C2V4 C2V3 C2V2 C2V1 C2V0
0x0D C3VOL C3V7 C3V6 C3V5 C3V4 C3V3 C3V2 C3V1 C3V0
0x0E C4VOL C4V7 C4V6 C4V5 C4V4 C4V3 C4V2 C4V1 C4V0
0x0F C5VOL C5V7 C5V6 C5V5 C5V4 C5V3 C5V2 C5V1 C5V0
0x10 C6VOL C6V7 C6V6 C6V5 C6V4 C6V3 C6V2 C6V1 C6V0
0x11 C7VOL C7V7 C7V6 C7V5 C7V4 C7V3 C7V2 C7V1 C7V0
0x12 C8VOL C8V7 C8V6 C8V5 C8V4 C8V3 C8V2 C8V1 C8V0

Это из даташита громкость, с программной конфигурацией совсем не похожи. Как это понять?

slider
Offline
Зарегистрирован: 17.06.2014

kimmel.dima , как разберетесь, черкните сюда. У меня вопрос какая минимильная инициализация является необходимой для запуска. 

 У самого мастер кит BA2070 валяется  на TAS5504A (+ PL1705 + 2 PCM1808 ) и усилители BA2071 http://lib.chipdip.ru/269/DOC000269591.pdf .  Кончилась atmega8 (греется, кз на пине было) , она с кнопок громкости управляла ей.  TAS5504A была куплена новая и заменена. Техподдержки на мастер кит нет, прошивки сказали нет (секрет), покупайте новую линейку усилителей. // А зачем , раз такая низкая надёжность и не ремонтопригодность при потраченных 8т.р. ? 

 Так что единственный вариант починить через arduino .

Схема  BA2070 ( BM2070) на  TAS5504 к BM2071  http://masterkit.ru/zip/bm2070.pdf  

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

Ок. Примерно представляю, что надо слать, а что конкретно - не знаю.

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

Подскажите пожалуйста, по таблице из даташита:

Addr   Name     D7    D6  D5   D4  D3  D2   D1   D0

0x00 CONFA     COS1 COS0 DSPB IR1 IR0 MCS2 MCS1 MCS0

0x00             1    0   0     0    0  0    1   1

Правильная посылка получается?

Wire.beginTransmission(0x40); 

  Wire.write(byte(0x00));   

  Wire.write(10000011);
  Wire.endTransmission();

 

kimmel.dima
Offline
Зарегистрирован: 20.02.2014
slider, в этом коде полное управление таской.

// TAS5518 and CS8416 User int32_terface for CrossOver / Volume / EQ control
// KOON3876
// 2006.12.23
// For Atmel ATMega128
#include <inttypes.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
//#include <avr/io.h>
//#include <compat/twi.h>

#include "lcd.h"
#include "i2cmaster.h"


//I2C device address of  CS8416
#define CS8416_ADDRESS 0x20
//AD0 = 0
//AD1 = 0
//AD2 = 0
//BASE = 0010xxx

#define TAS5508_ADDRESS 0x36

// 1/3Oct Equalizer Frequencies
const uint16_t EQFreqs[32] = {0,20,25,32,40,50,63,80,
                        100,125,160,200,250,315,400,500,
                        630,800,1000,1250,1600,2000,2500,3150,
                        4000,5000,6300,8000,10000,12500,16000,20000};

// Strings to show
const char EQFreqStr[32][8] = {"None","20Hz","25Hz","32Hz",
                              "40Hz","50Hz","63Hz","80Hz",
                              "100Hz","125Hz","160Hz","200Hz",
                              "250Hz","315Hz","400Hz","500Hz",
                              "630Hz","800Hz","1.0kHz","1.25kHz",
                              "1.6kHz","2.0kHz","2.5kHz","3.15kHz",
                              "4.0kHz","5.0kHz","6.3kHz","8.0kHz",
                              "10kHz","12.5kHz","16kHz","20kHz"};

//string for Q each index (actual Q = Q^2/100)
const char EQQStr[32][8] = {"0.000","0.010","0.040","0.090",
							"0.160","0.250","0.360","0.490",
							"0.640","0.810","1.000","1.210",
							"1.440","1.690","1.960","2.250",
							"2.560","2.890","3.240","3.610",
							"4.000","4.410","4.840","5.290",
							"5.760","6.250","6.760","7.290",
							"7.840","8.410","9.000","9.610"};

const char EQTypeStr[4][12] = {"None","LowShelf","HighShelf","Peaking"};

// Crossover Filter Point32_ts
const uint16_t FilterFreqs[32] =
                     {0,50,65,80,100,120,150,180,220,260,300,350,
                      400,500,650,800,1000,1200,1500,1800,2200,2600,3000,
                      3500,4000,5000,6500,8000,10000,12000,15000,18000};

const char FilterFreqStr[32][8] =
				{"None","50Hz","65Hz","80Hz",
				 "100Hz","120Hz","150Hz","180Hz",
				 "220Hz","260Hz","300Hz","350Hz",
				 "400Hz","500Hz","650Hz","800Hz",
				 "1kHz","1.2kHz","1.5kHz","1.8kHz",
				 "2.2kHz","2.6kHz","3.0kHz","3.5kHz",
				 "4.0kHz","5.0kHz","6.5kHz","8.0kHz",
				 "10kHz","12kHz","15kHz","18kHz"};

// CS8416 SPDIF Frequencies
const uint32_t SPDIFFreqs[4] = {44100,48000,88200,96000};
const char currentfsstr[4][8] = {"44.1kHz","48kHz","88.2kHz","96kHz"};

// Global Values
uint8_t currentfs;			//Fs (44.1/48/88.2/96) current state
uint8_t currentFilterMenu;	//Filter Menu Number
uint8_t FilterChanged;		//1: There were data change

uint8_t currentEQMenu;	//EQ Menu Number
uint8_t EQChanged;		//1: there were data change

uint8_t	KeyMode;	//0:none, 1: First Key, 2: Repeat Key
uint8_t PrevKey;	//remember previous key state
uint8_t	NewKey;		//get new key entry

// Parameters to store Flash
struct EQParam {
   uint8_t   EQType;   //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
   uint8_t   EQFreq;   //0 - 31
   uint8_t   EQQ;            //0 - 31
   int8_t   EQGain;   //-15,... 0,... 15
   };	//4 bytes

struct FilterParam {
   uint8_t LPF;   // 0:No LPF
   uint8_t HPF;   //0:No HPF
   int8_t OFFSET; //0:mid
   uint8_t MUTE;  //0:normal, 1:mute
   };	//4 bytes

struct Params {
   int16_t currentvol;
   int8_t currentch;
   int8_t currentwin;

   struct FilterParam FilterParams[4];   //CH12,34,56,78

   struct EQParam EQParams[4][3];   // CH12,34,56,78 - EQ5,6,7

} ;
struct Params DevParam;	//4 + 16 + 48 = 68 bytes
struct Params DevParam_EEPROM __attribute__((section(".eeprom")));


//Utility Functions

void msDelay(uint16_t delay)
{
	while (delay--) 
	{
	_delay_ms(1);
	} 
}

//Read Flash
void readDevParam()
{
	eeprom_busy_wait();
	eeprom_read_block(&DevParam, &DevParam_EEPROM,sizeof(DevParam_EEPROM));		

}

//Write Flash
void writeDevParam(int mode)
{
	eeprom_busy_wait();
	switch (mode)
		{
		case 0:	//Write All
			eeprom_write_block(&DevParam, &DevParam_EEPROM, sizeof(DevParam_EEPROM));
			break;
		case 1:	//Volume Only
			eeprom_write_word(&(DevParam_EEPROM.currentvol), DevParam.currentvol);
			break;
		case 2:	//Channel Only
			eeprom_write_byte(&(DevParam_EEPROM.currentch), DevParam.currentch);
			break;
		default:
			eeprom_write_block(&DevParam, &DevParam_EEPROM, sizeof(DevParam_EEPROM));
			break;
		}
	eeprom_busy_wait();
}

//LCD Functions

//LCD Function, String 0 terminated SendStr, Line is Upper(1) Lower(2)
void SendString(char * SendStr, uint8_t Line)
{
   int StrLen;
   unsigned char Packet[32];
   int i;

	lcd_gotoxy(0,0);
	msDelay(1);

	if (Line == 2)
	{
		lcd_gotoxy(0,1);
	}
	msDelay(1);

   StrLen = strlen(SendStr);
   memset(Packet, 0, sizeof(Packet));
   strncpy(Packet, SendStr, 16);
   for (i = StrLen; i <= 18; i++)
   {
      Packet[i] = 0x20;
   }

    lcd_puts(Packet);
	lcd_gotoxy(0,0);
}

//LCD Function
void ClearLCD()
{
	lcd_clrscr();
}

//LCD Function
uint8_t PollKey()
{

	if ( bit_is_clear(PINA, PINA0))
		return 3;

	if ( bit_is_clear(PINA, PINA4))
		return 4;

	if ( bit_is_clear(PINA, PINA1))
		return 5;

	if ( bit_is_clear(PINA, PINA3))
		return 6;

	if ( bit_is_clear(PINA, PINA2))
		return 1;
/*
         return 1;   //ENTER
         return 2;   //cancel
         return 3;   //up
         return 4;   //Down
         return 5;   //Left
         return 6;   //right
*/
   return 0;
}

//I2C Function
/* I2CWrite
write data to slave.
Sends START, slave address, index and then data, STOP
Waits for slave to respond. 
PARAM1: uint8_t address - slave device address
PARAM2: uint8_t index - subaddress of register/memory to write 
PARAM3: char * writestring - write data buffer
PARAM4: uint8_t len  - length of data to write   
RETURN: 0 or negative error code (see code)
*/  
int8_t I2CWrite(uint8_t address, uint8_t subaddress, char * writestring, uint8_t len)
{
	uint8_t  cnt;
	int8_t err;
	
	i2c_start(address + I2C_WRITE);

	err = i2c_write(subaddress);
	if (err == 1)
	{
		i2c_stop();
		return -20; // write failed
	}
	for (cnt = 0; cnt < len; cnt++)
	{
		i2c_write(writestring[cnt]);
    }
    i2c_stop();
	return 0;
}


/* I2CRead 
PARAM1: uint8_taddress - slave address
PARAM2: uint8_t subaddress - subaddress in in EEPROM to read from 
PARAM3: char *retstring          - buffer for data
PARAM4: uint8_t len   - size of data buffer 
          
RETURN: 0 or error code*/  
int8_t I2CRead(uint8_t address, uint8_t subaddress, char * retstring, uint8_t len)
{
	uint8_t cnt;
	int8_t err;

	i2c_start(address + I2C_WRITE);

	err = i2c_write(subaddress);
	if (err == 1)
	{
		i2c_stop();
		return -20; // access failed
	}

	i2c_rep_start(address + I2C_READ); 

	for (cnt = 0; cnt < len; cnt++)
	{
		if (cnt==(len-1))
		{
			retstring[cnt] = i2c_readNak();	//nak
		}
		else
        {
			retstring[cnt] = i2c_readAck();
		}
	}
	i2c_stop();
	return 0;
	
}

//I2C Functions
uint8_t I2C_GetFs()
{
   //returns data rate.
   //  0 : Error
   //  1 : invalid
   //  2 : 32 kHz
   //  3 : 38 kHz
   //  4 : 44.1kHz
   //  5 : 48 kHz
   //  6 : 88.2 kHz
   //  7 : 96 kHz
   //  8 : 176.4kHz
   //  9 : 192 kHz
   char Clk_Mode;
   uint8_t return_code;
   return_code = I2CRead(TAS5508_ADDRESS, 0x00, &Clk_Mode, 1);
   if (return_code != 0) {      return 0;   }
   //if ( (Clk_Mode & 0x01) == 0){  return 1; }
   //upper 3 bit shows mode
   return ( ((Clk_Mode & 0xE0) >> 5) + 2  );
}

// TAS5518 and PSVC Volume control
// PSVC is 4 bit programmable, 16dB
void I2C_SetVolume()
{
   char test_string[4];
   uint8_t return_code;
   int16_t TAS5508Volume;
   uint8_t PortAVolume;
   if (DevParam.currentvol < 0x48)   //+x.xx dB
   {
      TAS5508Volume = DevParam.currentvol;
      PortAVolume = 0x0F;
   }
   else
   {
      if (DevParam.currentvol < 0x89)  //0 - -15dB
      {
         TAS5508Volume = 0x48;
         PortAVolume = 16 - (uint8_t)(((DevParam.currentvol - 0x48)) / 4);
      }
      else
      {
         TAS5508Volume = DevParam.currentvol - 0x48;
         PortAVolume = 0;
      }
   }

   //set volume
   test_string[0] = 0;
   test_string[1] = 0;
   test_string[2] = 0;
   test_string[3] = TAS5508Volume & 0xff;
   return_code = I2CWrite(TAS5508_ADDRESS, 0xD9, test_string, 4);
   //WrPortI(PADR, &PADRShadow, PortAVolume);

	//Output Volume to Control
	PORTB = (PortAVolume)<<4;
}

// CS8416 Rx Selector
void I2C_SetCH()
{
   uint8_t WriteData;
   WriteData = 0x80 + DevParam.currentch * 8 + DevParam.currentch;
   I2CWrite(CS8416_ADDRESS, 0x04, &WriteData, 1);
}

//Make biquad Filter parameter
void MakeEQ(int32_t Fs, int32_t f0, int32_t mode, double Q, int32_t gain,  uint8_t * EQ)
{
   double w0;
   double cosw0;
   double sinw0;
   double alpha;
   double A;
   double sqrtA;
   double twosqrtAalpha;
   double b0;
   double b1;
   double b2;
   double a0;
   double a1;
   double a2;
   int32_t Qb0;
   int32_t Qb1;
   int32_t Qb2;
   int32_t Qa1;
   int32_t Qa2;

   b0 = 0.0;
   b1 = 1.0;
   b2 = 0.0;
   a0 = 1.0;
   a1 = 0.0;
   a2 = 0.0;

   w0 = 2.000 * 3.141516 * f0 / Fs;
   cosw0 = cos(w0);
   sinw0 = sin(w0);

   alpha = sinw0 / (2.00 * Q);
   A =  pow( ((double)(gain)) /40.0 , 10);
   sqrtA = sqrt(A);
   twosqrtAalpha = 2*sqrtA*alpha;

   if ( mode == 0) //HPF
   {
      a0 = 1.0 + alpha;
      b1 = -1.0 * (1.0 + cosw0) / a0 ;
      b0 = -1.0 * b1 / 2.00;
      b2 = b0;
      a1 = -2.0 * cosw0 / a0 ;
      a2 = (1.0 - alpha) / a0;
   }
   if ( mode == 1) //LPF
   {
      a0 = 1.0 + alpha;
      b1 = (1.0 - cosw0) / a0 ;
      b0 = b1 / 2.00;
      b2 = b0;
      a1 = -2.0 * cosw0 / a0 ;
      a2 = (1.0 - alpha) / a0;
   }
   if ( mode == 2) //LowShelf
   {
      a0 = (A+1)+(A-1)*cosw0+twosqrtAalpha;
      b0 = A*((A+1) - (A-1)*cosw0 + twosqrtAalpha);
      b1 = 2*A*((A-1) - (A+1)*cosw0) ;
      b2 = A*((A+1)-(A-1)*cosw0-twosqrtAalpha);
      a1 = -2.0*((A-1)+(A+1)*cosw0) ;
      a2 = (A+1)+(A-1)*cosw0-twosqrtAalpha;
   }
   if ( mode == 3) //HighShelf
   {
      a0 = (A+1)-(A-1)*cosw0+twosqrtAalpha;
      b0 = A*((A+1) + (A-1)*cosw0 + twosqrtAalpha);
      b1 = -2*A*((A-1) + (A+1)*cosw0) ;
      b2 = A*((A+1)+(A-1)*cosw0-twosqrtAalpha);
      a1 = 2.0*((A-1)-(A+1)*cosw0) ;
      a2 = (A+1)-(A-1)*cosw0-twosqrtAalpha;
   }
   if ( mode == 4) //Peaking
   {
      a0 = 1.0 + alpha / A;
      b0 = 1.0 + alpha * A;
      b1 = -2.0 * cosw0 ;
      b2 = 1.0 - alpha * A;
      a1 = -2.0 * cosw0 ;
      a2 = 1.0 - alpha / A;
   }
   if ( mode > 1)
   {
      b0 = b0 / a0;
      b1 = b1 / a0;
      b2 = b2 / a0;
      a1 = a1 / a0;
      a2 = a2 / a0;
   }
   //quantize
   Qb0 = (int32_t)(b0 *  8388608L);
   Qb1 = (int32_t)(b1 *  8388608L);
   Qb2 = (int32_t)(b2 *  8388608L);
   Qa1 = (int32_t)(a1 * -8388608L);
   Qa2 = (int32_t)(a2 * -8388608L);

   //Modify sign bit
   if (Qb0 < 0) Qb0 = Qb0 + 268435456L;
   if (Qb1 < 0) Qb1 = Qb1 + 268435456L;
   if (Qb2 < 0) Qb2 = Qb2 + 268435456L;
   if (Qa1 < 0) Qa1 = Qa1 + 268435456L;
   if (Qa2 < 0) Qa2 = Qa2 + 268435456L;

   //get each byte
   *(EQ   ) = (uint8_t)((Qb0>>24) & 0xFF);
   *(EQ+1 ) = (uint8_t)((Qb0>>16) & 0xFF);
   *(EQ+2 ) = (uint8_t)((Qb0>>8)  & 0xFF);
   *(EQ+3 ) = (uint8_t)( Qb0      & 0xFF);
   *(EQ+4 ) = (uint8_t)((Qb1>>24) & 0xFF);
   *(EQ+5 ) = (uint8_t)((Qb1>>16) & 0xFF);
   *(EQ+6 ) = (uint8_t)((Qb1>>8)  & 0xFF);
   *(EQ+7 ) = (uint8_t)( Qb1      & 0xFF);
   *(EQ+8 ) = (uint8_t)((Qb2>>24) & 0xFF);
   *(EQ+9 ) = (uint8_t)((Qb2>>16) & 0xFF);
   *(EQ+10) = (uint8_t)((Qb2>>8)  & 0xFF);
   *(EQ+11) = (uint8_t)( Qb2      & 0xFF);
   *(EQ+12) = (uint8_t)((Qa1>>24) & 0xFF);
   *(EQ+13) = (uint8_t)((Qa1>>16) & 0xFF);
   *(EQ+14) = (uint8_t)((Qa1>>8)  & 0xFF);
   *(EQ+15) = (uint8_t)( Qa1      & 0xFF);
   *(EQ+16) = (uint8_t)((Qa2>>24) & 0xFF);
   *(EQ+17) = (uint8_t)((Qa2>>16) & 0xFF);
   *(EQ+18) = (uint8_t)((Qa2>>8)  & 0xFF);
   *(EQ+19) = (uint8_t)( Qa2      & 0xFF);
}

void ClearEQ(uint8_t * EQ)
{
   //get each byte
   memset(EQ, 0,20);
   *(EQ+1 ) = 0x80;
}

// convert Q value to string
double EQQNumToValue(int32_t EQQ)
{
   double retVal;
   if ((EQQ < 0) || (EQQ > 31))
   {
      retVal = 0;
   }
   else
   {
      retVal = (EQQ * EQQ) / 100.00 ;
   }
   return retVal;
}

// convert EQ frequency value to string
int32_t FreqFromEQSetting(int32_t EQSetting)
{
   if ((EQSetting < 0) || (EQSetting > 31))
      return 0;

   return EQFreqs[EQSetting];
}

// convert Filter frequency value to string
int32_t FreqFromFilterSetting(int32_t FilterSetting)
{
   if ((FilterSetting < 0) || (FilterSetting > 31))
      return 0;

   return FilterFreqs[FilterSetting];
}

// Calculate Equalizers and apply
void applyEQ(int32_t FS)
{
   uint8_t EQ[20];
   int32_t return_code;
   int32_t Freq;
   double Q;

   int32_t i;
   int32_t j;

   //Loop for CH12,34,56,78
   for (j = 0; j <= 3; j++)
   {
      //Loop for EQ5,6,7 in each CH
      for (i = 0; i <= 2; i++)
      {
         Freq = FreqFromEQSetting(DevParam.EQParams[j][i].EQFreq);
         if ((Freq > 0) && (DevParam.EQParams[j][i].EQType > 0))
         {
            Q = EQQNumToValue(DevParam.EQParams[j][i].EQQ);
            MakeEQ(FS, Freq, DevParam.EQParams[j][i].EQType + 1, Q ,
             DevParam.EQParams[j][i].EQGain, EQ);
         }
         else
         {
            ClearEQ(EQ);
         }
         return_code = I2CWrite(TAS5508_ADDRESS, 0x55 + i + j*7*2,EQ,20);
         return_code = I2CWrite(TAS5508_ADDRESS, 0x5C + i + j*7*2,EQ,20);
      }
   }
}

// Calculate Filter and apply
void applyfilter(int32_t FS)
{
   uint8_t EQ[20];
   int32_t return_code;
   int32_t Freq;
   uint8_t Param[4];
   uint8_t MutePattern;
   int32_t i;

   for (i = 0; i <= 3; i++)
   {
      //CHxx EQ1,2 (LPF)
      Freq = FreqFromFilterSetting(DevParam.FilterParams[i].LPF);
      if (Freq > 0)
      {
         MakeEQ(FS, Freq, 1, 0.71, 0, EQ);     //Q=0.71 LPF
      }
      else
      {
         ClearEQ(EQ);
      }
      return_code = I2CWrite(TAS5508_ADDRESS, 0x51+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x52+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x58+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x59+i*14,EQ,20);

      //CHxx EQ3,4 (HPF)
      Freq = FreqFromFilterSetting(DevParam.FilterParams[i].HPF);
      if (Freq > 0)
      {
         MakeEQ(FS, Freq, 0,  0.71, 0, EQ);     //Q=0.71, HPF
      }
      else
      {
         ClearEQ(EQ);
      }
      return_code = I2CWrite(TAS5508_ADDRESS, 0x53+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x54+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x5A+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x5B+i*14,EQ,20);
   }

   Param[0] = 0;
   Param[1] = 0;
   Param[2] = 0;

   for (i = 0; i <= 3; i++)
   {
      //CH Offset
      Param[3] = (uint8_t)(0x48 - DevParam.FilterParams[i].OFFSET * 4);
      return_code = I2CWrite(TAS5508_ADDRESS, 0xD1+i*2,Param,4);
      return_code = I2CWrite(TAS5508_ADDRESS, 0xD2+i*2,Param,4);
   }

   //CH Mute
   MutePattern = (uint8_t)
                (DevParam.FilterParams[0].MUTE * 0x03 +
                 DevParam.FilterParams[1].MUTE * 0x0C +
                 DevParam.FilterParams[2].MUTE * 0x30 +
                 DevParam.FilterParams[3].MUTE * 0xC0);
   return_code = I2CWrite(TAS5508_ADDRESS, 0x0F, &MutePattern,1);
}


//Filter setting entry
void Menu01(int32_t NewKeyData)
{
   char Line1[20];
   char Line2[20];

      switch (NewKeyData)
      {
      case 1:  //Enter
      case 4:    //Down
         currentFilterMenu = 0;
         FilterChanged = 0;
         DevParam.currentwin = 3;
         return;
         break;
      case 2:  //Cancel
      case 3:    //Up
         DevParam.currentwin = 0;
         return;
         break;
      case 5:    //Left
      case 6:   //Right
         DevParam.currentwin = 2;
         return;
         break;
      default:
         break;
      }

      //Create Screen String
      sprintf(Line1, "KDA-TAS4i");
      sprintf(Line2, "Filter Menu ?");
      //Send LCD
      SendString(Line1,1);
      SendString(Line2,2);
}

//EQ Setting Entry
void Menu02(int32_t NewKeyData)
{
   char Line1[20];
   char Line2[20];

      switch (NewKeyData)
      {
      case 1:  //Enter
      case 4:    //Down
		currentEQMenu = 0;
		EQChanged = 0;
         DevParam.currentwin = 4;
         return;
         break;
      case 2:  //cancel
      case 3:    //Up
         DevParam.currentwin = 0;
         return;
         break;
      case 5:    //Left
      case 6:   //Right
         DevParam.currentwin = 1;
         return;
         break;
      default:
         break;
      }

      //Create Screen String
      sprintf(Line1, "KDA-TAS4i");
      sprintf(Line2, "EQ Menu ?");
      //Send LCD
      SendString(Line1,1);
      SendString(Line2,2);
}

// Convert Filter value to string
void FilterNumToStr(int32_t FilterNum, char * FilterStr)
{

   if ((FilterNum < 0) || (FilterNum > 31))
      strcpy(FilterStr, "--");
   else
      strcpy(FilterStr, FilterFreqStr[FilterNum]);

}

void MuteToStr(int32_t MuteValue, char * MuteStr)
{
   if (MuteValue == 0)
   {
      strcpy(MuteStr, "In Use");
   }
   else
   {
      strcpy(MuteStr, "Mute");
   }
}

//Filter Menu Screen
void FilterMenu(int32_t NewKeyData)
{
   //Control EQ0,1(reserved for LPF) ,2,3 (for HPF)
   char Line1[20];
   char Line2[20];

   int32_t CurrentCH;
   int32_t CurrentFilterSetting;
   CurrentCH = (int32_t)(currentFilterMenu / 4);
   CurrentFilterSetting = currentFilterMenu - CurrentCH * 4;

      switch (NewKeyData)
      {
      case 1:  //Enter
         //save changes
         FilterChanged = 0;
         DevParam.currentwin = 3;
         applyfilter(SPDIFFreqs[currentfs - 4]);
           writeDevParam(0);
         return;
         break;
      case 2:   //Cancel
         //discard changes
         FilterChanged = 0;
           readDevParam();
         DevParam.currentwin = 1;
           writeDevParam(0);
         return;
         break;
      case 3:    //Up
         if (currentFilterMenu > 0)
            currentFilterMenu -= 1;
         else
		 {
		 	if (currentFilterMenu == 0)
			{
		         DevParam.currentwin = 1;
		         return;
			}
		 }
         break;
      case 4:    //Down
         if (currentFilterMenu < 15)
            currentFilterMenu += 1;
         else
            currentFilterMenu = 15;
         break;
      case 5:    //Left
         FilterChanged = 1;
         switch (CurrentFilterSetting)
         {
            case 0:   //LPF
               if (DevParam.FilterParams[CurrentCH].LPF > 0)
                   DevParam.FilterParams[CurrentCH].LPF -= 1;
               else
                   DevParam.FilterParams[CurrentCH].LPF = 0;
               break;
            case 1:   //HPF
               if (DevParam.FilterParams[CurrentCH].HPF > 0)
                   DevParam.FilterParams[CurrentCH].HPF -= 1;
               else
                   DevParam.FilterParams[CurrentCH].HPF = 0;
               break;
            case 2:   //OFFSET
               if (DevParam.FilterParams[CurrentCH].OFFSET > -15)
                   DevParam.FilterParams[CurrentCH].OFFSET -= 1;
               else
                   DevParam.FilterParams[CurrentCH].OFFSET = -15;
               break;
            case 3:   //MUTE
               if (DevParam.FilterParams[CurrentCH].MUTE == 1)
                   DevParam.FilterParams[CurrentCH].MUTE = 0;
               else
                   DevParam.FilterParams[CurrentCH].MUTE = 1;
               break;
         }
         break;
      case 6:   //Right
         FilterChanged = 1;
         switch (CurrentFilterSetting)
         {
            case 0:   //LPF
               if (DevParam.FilterParams[CurrentCH].LPF < 31)
                   DevParam.FilterParams[CurrentCH].LPF += 1;
               else
                   DevParam.FilterParams[CurrentCH].LPF = 31;
               break;
            case 1:   //HPF
               if (DevParam.FilterParams[CurrentCH].HPF < 31)
                   DevParam.FilterParams[CurrentCH].HPF += 1;
               else
                   DevParam.FilterParams[CurrentCH].HPF = 0;
               break;
            case 2:   //OFFSET
               if (DevParam.FilterParams[CurrentCH].OFFSET < 15)
                   DevParam.FilterParams[CurrentCH].OFFSET += 1;
               else
                   DevParam.FilterParams[CurrentCH].OFFSET = 15;
               break;
            case 3:   //MUTE
               if (DevParam.FilterParams[CurrentCH].MUTE == 0)
                   DevParam.FilterParams[CurrentCH].MUTE = 1;
               else
                   DevParam.FilterParams[CurrentCH].MUTE = 0;
               break;
         }
         break;
      default:
         //SendString("No Key",2);
         break;
      }

      //Create Screen String
         switch (CurrentFilterSetting)
         {
            case 0:   //LPF
               sprintf(Line1, "CH%i-%i LPF",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2);
               FilterNumToStr(DevParam.FilterParams[CurrentCH].LPF,Line2);
               break;
            case 1:   //HPF
               sprintf(Line1, "CH%i-%i HPF",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2);
               FilterNumToStr(DevParam.FilterParams[CurrentCH].HPF,Line2);
               break;
            case 2:   //OFFSET
               sprintf(Line1, "CH%i-%i OFFSET",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2);
               sprintf(Line2, "%ddB", DevParam.FilterParams[CurrentCH].OFFSET);
               break;
            case 3:   //MUTE
               sprintf(Line1, "CH%i-%i MUTE",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2);
               MuteToStr(DevParam.FilterParams[CurrentCH].MUTE, Line2);
               break;
         }
      //Send LCD
      if (FilterChanged == 1)
      {
         strcat(Line1, "  *");
      }
      SendString(Line1,1);
      SendString(Line2,2);
}

void EQTypeToStr(int32_t EQTypeNum, char * RetStr)
{
   if ((EQTypeNum < 0) || (EQTypeNum > 3))
      strcpy(RetStr, "--");
   else
      strcpy(RetStr, EQTypeStr[EQTypeNum]);
}

void EQFreqNumToStr(int32_t EQFreqNum, char * EQFreqRetStr)
{
   if ((EQFreqNum < 0) || (EQFreqNum > 31))
      strcpy(EQFreqRetStr, "--");
   else
      strcpy(EQFreqRetStr, EQFreqStr[EQFreqNum]);
}

void EQQNumToStr(int32_t EQQNum, char * EQQRetStr)
{
   if ((EQQNum < 0) || (EQQNum > 31))
      strcpy(EQQRetStr, "--");
   else
      strcpy(EQQRetStr, EQQStr[EQQNum]);
}

//EQ Menu Screen
void EQMenu(int32_t NewKeyData)
{
   //Control EQ5,6,7
   char Line1[20];
   char Line2[20];
  //double EQQ;
   int32_t CurrentCH; //0,1,2,3 = CH12,34,56,78
   int32_t CurrentEQ; //0,1,2 = EQ5,6,7
   int32_t CurrentSetting; //0,1,2,3 = EQType, EQFreq, EQQ, EQGain

   CurrentCH = (int32_t)(currentEQMenu / 12);
   CurrentEQ = (int32_t)((currentEQMenu - CurrentCH * 12) / 4);
   CurrentSetting = currentEQMenu - CurrentCH * 12 - CurrentEQ * 4;

      switch (NewKeyData)
      {
      case 1:  //Enter
         //save changes
         EQChanged = 0;
         DevParam.currentwin = 4;
         applyEQ(SPDIFFreqs[currentfs - 4]);
           writeDevParam(0);
         return;
         break;
      case 2: //Cancel
         //discard changes
         EQChanged = 0;
         readDevParam();
         DevParam.currentwin = 2;
           writeDevParam(0);
         return;
         break;
      case 3:    //Up
         if (currentEQMenu > 0)
            currentEQMenu -= 1;
         else
		 {
		 	if (currentEQMenu == 0)
		 	{
         		DevParam.currentwin = 2;
				return;
			}
		 }	
         break;
      case 4:    //Down
         if (currentEQMenu < 47)
            currentEQMenu += 1;
         else
		 	currentEQMenu = 47;
         break;
      case 5:    //Left
         EQChanged = 1;
         switch (CurrentSetting)
         {
            case 0:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQType > 0 )  //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQType -= 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQType = 0;
               break;
            case 1:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq > 0 )   //0 - 31
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq -= 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq = 0;
               break;
            case 2:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQQ > 0 )     //0 - 31
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQQ -= 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQQ = 0;
               break;
            case 3:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQGain > -15 )   //-15,... 0,... 15
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQGain -= 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQGain = -15;
               break;
            default:
               break;
         }
         break;
      case 6:   //Right
         EQChanged = 1;
         switch (CurrentSetting)
         {
            case 0:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQType < 3 )  //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQType += 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQType = 3;
               break;
            case 1:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq < 31 )   //0 - 31
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq += 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq = 31;
               break;
            case 2:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQQ < 31 )     //0 - 31
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQQ += 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQQ = 31;
               break;
            case 3:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQGain < 15 )   //-15,... 0,... 15
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQGain += 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQGain = 15;
               break;
            default:
               break;
         }
         break;
      default:
         //SendString("No Key",2);
         break;
      }

      //Create Screen String
      switch (CurrentSetting)
      {
         case 0:   //EQType
            sprintf(Line1, "CH%d-%d EQ%d Type",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2,(int8_t)CurrentEQ+5 );
            EQTypeToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQType ,Line2);
            break;
         case 1:   //EQFreq
            sprintf(Line1, "CH%d-%d EQ%d Freq",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2,(int8_t)CurrentEQ+5);
            EQFreqNumToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq, Line2);
            break;
         case 2:   //EQQ
            sprintf(Line1, "CH%d-%d EQ%d Q",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2,(int8_t)CurrentEQ+5);
            EQQNumToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQQ, Line2);
            break;
         case 3:
            sprintf(Line1, "CH%d-%d EQ%d Gain",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2,(int8_t)CurrentEQ+5);
            sprintf(Line2, "%ddB", DevParam.EQParams[CurrentCH][CurrentEQ].EQGain);
            break;
         default:
            break;
      }
      //Send LCD
      if (EQChanged == 1)
      {
         strcat(Line1, " *");
      }

      SendString(Line1,1);
      SendString(Line2,2);
}

// Main Screen to show Volume, Channel
void mainScreen(int32_t NewKeyData)
{
   char Line1[20];
   char Line2[20];
   int32_t Volume;

   Volume = (int32_t)(((DevParam.currentvol - 0x48) * -1) / 4);

      switch (NewKeyData)
      {
      case 1:  //Enter
         //SendString("Enter Pressed",2);
         DevParam.currentwin = 1;
           writeDevParam(0);
         return;
         break;
      case 2:
         //SendString("Cancel Pressed",2);
         break;
      case 3:    //Up
         if (Volume < 16)
         {
            Volume += 1;
            DevParam.currentvol = ((Volume * 4) * -1) + 0x48;
            writeDevParam(1);
            I2C_SetVolume();
         }
         else
            Volume = 16;
         break;
      case 4:    //Down
         if (Volume > -100)
         {
            Volume -= 1;
            DevParam.currentvol = ((Volume * 4) * -1) + 0x48;
            writeDevParam(1);
            I2C_SetVolume();
         }
         else
            Volume = -100;
         break;
      case 5:    //Left
         if (DevParam.currentch > 0)
         {
            DevParam.currentch -= 1;
            writeDevParam(2);
            I2C_SetCH();
         }
         else
            DevParam.currentch = 0;
         break;
      case 6:   //Right
         if (DevParam.currentch < 7)
         {
            DevParam.currentch += 1;
            writeDevParam(2);
            I2C_SetCH();
         }
         else
            DevParam.currentch = 7;
         break;
      default:
         break;
      }

      //Create Screen String
      sprintf(Line1, "KDA-TAS4i     D%d", DevParam.currentch);
      if ((currentfs < 4) || (currentfs > 7))
         sprintf(Line2, "%3ddB Fs=--kHz", (int16_t)Volume);
      else
         sprintf(Line2, "%3ddB Fs=%s", (int16_t)Volume, currentfsstr[currentfs - 4]);

      //Send LCD
      SendString(Line1,1);
      SendString(Line2,2);

}

// Get Key / pass screen
void ProcessKey(int32_t NewKeyData)
{
   switch (DevParam.currentwin)
   {
      case 0:
         mainScreen(NewKeyData);
         break;
      case 1:
         Menu01(NewKeyData);
         break;
      case 2:
         Menu02(NewKeyData);
         break;
      case 3:
         FilterMenu(NewKeyData);
         break;
      case 4:
         EQMenu(NewKeyData);
         break;
      default:
         mainScreen(NewKeyData);
         break;
   }
}

// Init
void initializeBoard()
{
   uint8_t WriteData;
   char LCDLine[20];
 
	PORTC=0x00;
	DDRC=0xF7;

	DDRA = 0xE0;	//PortA, 7,6,5 is out, other in
	PORTA = 0xBF;	//LED Off

	DDRE=0xFF;	//PE is output
	PORTE = 0xC8;	//Reset High

    msDelay(10);

	DDRB = 0xF0;	//PB7,6,5,4 is output
	PORTB = 0x00;	//Set Voltage Lowest

   lcd_init(LCD_DISP_ON);
   lcd_home();

   i2c_init();
   currentfs = 0;

	//Initialize key state
	KeyMode = 0;
	PrevKey = 0;
	NewKey = 0;

   readDevParam();
   //Once for Initial.
   //memset(&DevParam, 0, sizeof(DevParam));

   ClearLCD();

	memset(LCDLine, 0, sizeof(LCDLine));
	sprintf(LCDLine, "KOON DIGITAL");
    SendString(LCDLine,1);
	sprintf(LCDLine, "    AUDIO DIY");
    SendString(LCDLine,2);
    msDelay(1500);

   //Serial Audio Format = 1 0 00 0 1 0 1   (I2S 24bit)
   WriteData = 0x85;   //I2S
   I2CWrite(CS8416_ADDRESS, 0x05, &WriteData, 1);

   //Control3 = 10110000
   WriteData = 0xB0;   //1011 GPIO is TX passthrough
   I2CWrite(CS8416_ADDRESS, 0x03, &WriteData, 1);

   I2C_SetCH();

   //set volume
   I2C_SetVolume();

   ClearLCD();

}


// Main Loop
int main()
{
   int32_t return_code;
   int32_t newfs;
   uint8_t MUTEMode;

   msDelay(100);
   initializeBoard();

   //set mute pattern
   MUTEMode = 0x00;       //Unmute all
   return_code = I2CWrite(TAS5508_ADDRESS, 0x0F, &MUTEMode, 1);

   while (1)
   {
		switch(KeyMode)
		{
		case 0:
		  msDelay(50);
		  break;
		case 1:
			msDelay(400);
			break;
		case 2:
			msDelay(200);
			break;
		default:
			msDelay(100);
			break;
		}
     {
         //task for check fs
         newfs = I2C_GetFs();
         if (currentfs != newfs)
         {
            if ((newfs < 4) || (newfs > 7)) //non support
            {
                //mute all
                MUTEMode = 0xFF;
                I2CWrite(TAS5508_ADDRESS, 0x0f, &MUTEMode, 1);
            }
            else
            {
                applyfilter(SPDIFFreqs[newfs-4]);
                applyEQ(SPDIFFreqs[newfs-4]);
            }
            currentfs = newfs;
         }
     }
     //Task Key Process
     {
         NewKey = PollKey();
			switch(KeyMode)
			{
			case 0:	//Initial Key State, None Key detected
				if (NewKey > 0)
				{
					KeyMode = 1;	//to state 1.
					if (NewKey != PrevKey)	{	ProcessKey(NewKey);	}
					PrevKey = NewKey;
				}
				else	{ ProcessKey(0); }
			  break;
			case 1:	//Some key detected. wait 400 ms to another input.
				if (NewKey > 0)
				{
					if (NewKey != PrevKey) 	{	KeyMode = 1;	}	//different key detected.
					else  					{	KeyMode = 2;	}	//Same key detected.
		         	ProcessKey(NewKey);
					PrevKey = NewKey;
				}
				else	//no key pressed. return to state 0.
				{
					KeyMode = 0;
					PrevKey = NewKey;
					ProcessKey(0);
				}
				break;
			case 2:	//If same key still pressed, run same routine per 100ms.
				if (NewKey > 0)
				{
					if (NewKey != PrevKey)	{	KeyMode = 1; 	}	//different key detected.
					else					{	KeyMode = 2;	}	//repeat same key operation
		         	ProcessKey(NewKey);
					PrevKey = NewKey;
				}
				else
				{
					KeyMode = 0;
					PrevKey = NewKey;
					ProcessKey(0);
				}
				break;
			default:
				break;
			}	//switch
	     }	//Task
    }	//While

	return 0;

}


 

vvadim
Offline
Зарегистрирован: 23.05.2012

ну сами подумайте, кто будет ковыряться в чужом код на 1400 строк...

MacSim
Offline
Зарегистрирован: 28.11.2012

andriano пишет:

А Вы дэйташит на него внимательно изучали?

Не умею даташиты читать....

повторю. Hi андриано .

Начните с букваря.

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

vvadim пишет:

ну сами подумайте, кто будет ковыряться в чужом код на 1400 строк...

Это не мне. Человек попросил какую-нибудь информацию по управлению tas, я скинул (мне не жалко). 

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

MacSim пишет:

andriano пишет:

А Вы дэйташит на него внимательно изучали?

Не умею даташиты читать....

повторю. Hi андриано .

Начните с букваря.

В каком месте написал, что не умею???

По делу есть что сказать?

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

Нашел код для sta308. Сама микросхема пока едет, проверить в железе не могу. Посмотрите знающие люди, ошибок много?

/************************************************************  
 * Control sta308  
 ************************************************************/
#include "Sta308a.h"   
#include <Wire.h>
#define  adress 0x40
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int Aud_Treble308;


void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
  InitSta308a();
  lcd.begin(16, 2);
  lcd.print("hello");
}


const char Sta308a_InitDat[]={   
  Sta308a_ConfA_Init,            
  Sta308a_ConfB_Init,            
  Sta308a_ConfC_Init,            
  Sta308a_ConfD_Init,            
  Sta308a_ConfE_Init,            
  Sta308a_ConfF_Init,            
  Sta308a_ConfG_Init,            
  Sta308a_ConfH_Init,            
  Sta308a_ConfI_Init,            
  Sta308a_Mmute_Init,            
  Sta308a_Mvol_Init,                 
  Sta308a_C1Vol_Init,            
  Sta308a_C2Vol_Init,            
  Sta308a_C3Vol_Init,            
  Sta308a_C4Vol_Init,            
  Sta308a_C5Vol_Init,            
  Sta308a_C6Vol_Init,            
  Sta308a_C7Vol_Init,            
  Sta308a_C8Vol_Init,            
  Sta308a_C1VTNB_Init,               
  Sta308a_C2VTNB_Init,               
  Sta308a_C3VTNB_Init,               
  Sta308a_C4VTNB_Init,               
  Sta308a_C5VTNB_Init,               
  Sta308a_C6VTNB_Init,               
  Sta308a_C7VTNB_Init,               
  Sta308a_C8VTNB_Init,               
  Sta308a_C12im_Init,            
  Sta308a_C34im_Init,            
  Sta308a_C56im_Init,            
  Sta308a_C78im_Init,            
  Sta308a_Auto1_Init,            
  Sta308a_Auto2_Init,            
  Sta308a_Auto3_Init,            
  Sta308a_PreEQ_Init,            
  Sta308a_Ageq_Init,                 
  Sta308a_Bgeq_Init,                 
  Sta308a_Cgeq_Init,                 
  Sta308a_Dgeq_Init,                 
  Sta308a_Fgeq_Init,                 
  Sta308a_BQlp_Init,                 
  Sta308a_MXlp_Init,                 
  Sta308a_EQbp_Init,                 
  Sta308a_ToneBP_Init,               
  Sta308a_Tone_Init,                 
  Sta308a_C1234ls_Init,          
  Sta308a_C5678ls_Init,          
  Sta308a_L1ar_Init,                 
  Sta308a_L1atrt_Init,               
  Sta308a_L2ar_Init,                 
  Sta308a_L2atrt_Init,               
  Sta308a_C12ot_Init,            
  Sta308a_C34ot_Init,            
  Sta308a_C56ot_Init,            
  Sta308a_C78ot_Init,            
  Sta308a_C12om_Init,            
  Sta308a_C34om_Init,            
  Sta308a_C56om_Init,            
  Sta308a_C78om_Init,            
  Sta308a_Cfaddr1_Init,          
  Sta308a_Cfaddr2_Init,          
  Sta308a_B1cf1_Init,            
  Sta308a_B1cf2_Init,            
  Sta308a_B1cf3_Init,            
  Sta308a_B2cf1_Init,            
  Sta308a_B2cf2_Init,            
  Sta308a_B2cf3_Init,            
  Sta308a_A1cf1_Init,            
  Sta308a_A1cf2_Init,            
  Sta308a_A1cf3_Init,            
  Sta308a_A2cf1_Init,            
  Sta308a_A2cf2_Init,            
  Sta308a_A2cf3_Init,            
  Sta308a_B0cf1_Init,            
  Sta308a_B0cf2_Init,            
  Sta308a_B0cf3_Init,            
  Sta308a_Cfud_Init,                 
  Sta308a_MPCC1_Init,            
  Sta308a_MPCC2_Init,            
  Sta308a_RES0_Init,             
  Sta308a_RES1_Init,                 
  Sta308a_PSC1_Init,                 
  Sta308a_PSC2_Init,                 
  Sta308a_PSC3_Init                  
};   

/**********************************************************  
 * EQ Coefficient Array  
 * ArrayFormat:  
 * Arr[][]={{EQCofficientAddress0,PointVal},  
 * {EQCofficientAddress1,PointVal},  
 * {EQCofficientAddress2,PointVal},     
 * }  
 * 
 **********************************************************/
const char Sta308aEQArray[EQNum][EQVal]={   
  // TopAdr   BotAdr   (0x3d)  (0x3e)  (0x3f)  (0x40) (0x41) (0x42)  (0x43)  (0x44)   (0x45)  (0x46)  (0x47)  (0x48)  (0x49)  (0x4a)  (0x4b)   
  {    
    0    ,   5    ,  0x80 ,  0x71 ,  0x8f  , 0x7f,  0x8e , 0x71 , 0x7f  , 0x8e  ,  0x3e  , 0x80  ,  0xe2 , 0xb9  , 0x3f  ,  0xc7 ,  0x38  }
  ,   
  {    
    0    ,   10   ,  0x93 ,  0x29 ,  0xe4  , 0x58 , 0xde , 0xb2 , 0x6c  , 0xd6  ,  0x1c  , 0x9a  ,  0x20 , 0xc4  , 0x46  ,  0x80 ,  0x44  }
  ,   
  {    
    0    ,   55   ,  0x80 ,  0x71 ,  0x8f  , 0x7f , 0x8e , 0x71 , 0x7f  , 0x8e  ,  0x3e  , 0x80  ,  0xe2 , 0xb9  , 0x3f  ,  0xc7 ,  0x38  }
  ,   
  {    
    0    ,   60   ,  0x93 ,  0x29 ,  0xe4  , 0x58 , 0xde , 0xb2 , 0x6c  , 0xd6  ,  0x1c  , 0x9a  ,  0x20 , 0xc4  , 0x46  ,  0x80 ,  0x44  }
  ,   
  {    
    0    , 105+150,  0x00 ,  0x00 ,  0x32  , 0x00 , 0x00 , 0x32 , 0x7f  , 0x8e  ,  0x3e  , 0x80  ,  0xe2 , 0xb9  , 0x00  ,  0x00 ,  0x19  }
  ,   
  {
    (110+150)/256   ,(110+150)%256  ,  0x80 ,  0x25 ,  0xab  , 0x7f , 0x33 , 0x03 , 0x7f  , 0xda  ,  0x55  , 0x80  ,  0x4a , 0xff  , 0x40  ,  0x40 ,  0xff  }
  ,   
  {
    (115+150)/256   ,(115+150)%256  ,  0x80 ,  0x56 ,  0x00  , 0x7f , 0x5e , 0xb0 , 0x7f  , 0xaa  ,  0x00  , 0x80  ,  0xaa , 0x96  , 0x3f  ,  0xfb ,  0x5c  }
  ,   
  {
    (120+150)/256   ,(120+150)%256  ,  0x80 ,  0x18 ,  0xa7  , 0x7f , 0xd7 , 0xd8 , 0x7f  , 0xe7  ,  0x59  , 0x80  ,  0x31 , 0x3e  , 0x3f  ,  0xfb ,  0x74  }

};   

const   char Sta308aEQSingleArray[EQSingleNum][EQSingleVal]={   
  {
    400/256,400%256, 0x7f  , 0xff  ,  0xff      }
  ,//0x40  , 0x26  ,  0xe6  },   
  {
    401/256,401%256, 0x7f  , 0xff  ,  0xff      }
  ,//0x40  , 0x26  ,  0xe6  },   
  {
    402/256,402%256, 0x7f  , 0xff  ,  0xff      }
  ,//0x22  , 0x78  ,  0x1a  }   

  //  {416/256,416%256, 0x00  , 0x00  ,  0x00  },   
  //  {464/256,464%256, 0x00  , 0x00  ,  0x00  }   

};         



/************************************************************  
 * Volume Array  
 ************************************************************/
char Sta308aVolArray[51]={   
  VOL00,VOL01,VOL02,VOL03,VOL04,VOL05,VOL06,VOL07,VOL08,VOL09,   
  VOL10,VOL11,VOL12,VOL13,VOL14,VOL15,VOL16,VOL17,VOL18,VOL19,   
  VOL20,VOL21,VOL22,VOL23,VOL24,VOL25,VOL26,VOL27,VOL28,VOL29,   
  VOL30,VOL31,VOL32,VOL33,VOL34,VOL35,VOL36,VOL37,VOL38,VOL39,   
  VOL40,VOL41,VOL42,VOL43,VOL44,VOL45,VOL46,VOL47,VOL48,VOL49,VOL50
};   





/*******************************************  
 * initial sta308a  
 *******************************************/
void    InitSta308a(void)   
{   
  unsigned char Count;   
  for(Count=0;    Count<0x54;  Count++)   
  {   
    Wire.beginTransmission(adress); // transmit to device #4
    Wire.write(Count);
    Wire.write(Sta308a_InitDat[Count]);
    Wire.endTransmission();    // stop transmitting

  }   
  Aud_Treble308=0x77;   
  ProcessEQ();   
}   


/*********************************************  
 * send Value to  Sta308a  
 *********************************************/
void    SendSta308aVol()   
{ 
  unsigned char Dat;  
  Wire.beginTransmission(adress); // transmit to device #4
  Wire.write(Sta308a_Mvol);
  Wire.write(Sta308aVolArray[Dat]);
  Wire.endTransmission();    // stop transmitting

}   

/*********************************************  
 * Bass manager  
 *********************************************/
void    SendSta308aBass()   
{ 
  unsigned char Dat;  
  Wire.beginTransmission(adress); // transmit to device #4
  Wire.write(Sta308a_Tone);
  Wire.write(Dat);
  Wire.endTransmission();    // stop transmitting

}   

/***********************************************  
 * Mute sta308a  
 ***********************************************/
void    SendSta308aMuteOn()   
{   
  Wire.beginTransmission(adress); // transmit to device #4
  Wire.write(Sta308a_Mmute);
  Wire.write(0x01);
  Wire.endTransmission();    // stop transmitting 
}   

/*********************************************  
 * Mute off  
 *********************************************/
void    SendSta308aMuteOff()   
{   
  Wire.beginTransmission(adress); // transmit to device #4
  Wire.write(Sta308a_Mmute);
  Wire.write(0x00);
  Wire.endTransmission();    // stop transmitting    
}   


/***************************************  
 * Select308AM(0);  
 * 
 ***************************************/
void    Select308AM()   
{ 
  unsigned char i;  
  if(i==1)   
  {   
    Wire.beginTransmission(adress); // transmit to device #4
    Wire.write(Sta308a_Auto3);
    Wire.write(Sta308a_Auto3_Init+0x10);
    Wire.endTransmission();    // stop transmitting   
  }   
  else   
  {   
    Wire.beginTransmission(adress); // transmit to device #4
    Wire.write(Sta308a_Auto3);
    Wire.write(Sta308a_Auto3_Init);
    Wire.endTransmission();    // stop transmitting   SendByteData(0x40,Sta308a_Auto3,Sta308a_Auto3_Init);   
  }      
}      

/*******************************************  
 * select am B  
 *******************************************/
void    Slect308AMFreq()   
{ 
  unsigned char i;  
  Wire.beginTransmission(adress); // transmit to device #4
  Wire.write(Sta308a_Auto3);
  Wire.write(Sta308a_Auto3_Init+0x10+i);
  Wire.endTransmission();    // stop transmitting   SendByteData(0x40,Sta308a_Auto3,Sta308a_Auto3_Init+0x10+i);   
}      


/********************************************  
 * process EQ  
 ********************************************/
void        ProcessEQ()   
{   
  unsigned char EqCont0;   
  unsigned char EqCont1;   

  for(EqCont0=0; EqCont0<EQNum; EqCont0++)   
  {   
    for(EqCont1=0; EqCont1<EQVal; EqCont1++)   
    {   
      Wire.beginTransmission(adress); // transmit to device #4
      Wire.write(0x3b+EqCont1);
      Wire.write(Sta308aEQArray[EqCont0][EqCont1]);
      Wire.endTransmission();    
    }   
    Wire.beginTransmission(adress); // transmit to device #4
    Wire.write(0x4c);
    Wire.write(0x02);
    Wire.endTransmission();  
    delayMicroseconds(2);   
  }   

  //ReadEqValue(0x00, 0x05, 0x80);   
  //  EqCont0=ReadByteData(0x40,0x00);   
  //  while(EqCont0==0x83) ;   


  for(EqCont0=0; EqCont0<EQSingleNum; EqCont0++)   
  {   
    for(EqCont1=0; EqCont1<EQSingleVal; EqCont1++)   
    {   
      Wire.beginTransmission(adress); // transmit to device #4
      Wire.write(0x3b+EqCont1);
      Wire.write(Sta308aEQSingleArray[EqCont0][EqCont1]);
      Wire.endTransmission();   
    }   
    Wire.beginTransmission(adress); // transmit to device #4
    Wire.write(0x4c);
    Wire.write(0x01);
    Wire.endTransmission();  
    delayMicroseconds(2);    
  }   
  //ReadEqValue(416/256,416%256, 0x7f);    
}      


/***********************************************************/
void    ReadEqValue()   
{  
  char AdrH; 
  char AdrL; 
  char Value; 
  unsigned char DatH=0,DatM=0,DatL=0;    
  Wire.beginTransmission(adress); // transmit to device #4
  Wire.write(0x3b);
  Wire.write(AdrH);
  Wire.endTransmission();   
  Wire.beginTransmission(adress); // transmit to device #4
  Wire.write(0x3c);
  Wire.write(AdrL);
  Wire.endTransmission();   
  Wire.requestFrom(adress, 0x3d);    // request 6 bytes from slave device #2

  while(Wire.available())    // slave may send less than requested
  { 
    DatH = Wire.read(); // receive a byte as character
  }

  Wire.requestFrom(adress, 0x3e);    // request 6 bytes from slave device #2

  while(Wire.available())    // slave may send less than requested
  { 
    DatM = Wire.read(); // receive a byte as character
  }  
  Wire.requestFrom(adress, 0x3f);    // request 6 bytes from slave device #2

  while(Wire.available())    // slave may send less than requested
  { 
    DatL = Wire.read(); // receive a byte as character
  }    
  while(DatH==Value) ;   
}   
void loop(){
  lcd.print("Init");
  delay (500);
};




И sta308.h

/********************************************************* 
 * Sta308a 
 *********************************************************/


//  define  initial value 
#define		Sta308a_ConfA_Init				0x83                    // 0x83 
#define		Sta308a_ConfB_Init				0x00                    // 0x00 
#define		Sta308a_ConfC_Init				0x00                    // 0x00 
#define		Sta308a_ConfD_Init				0xc2                    // 0xfe 
#define		Sta308a_ConfE_Init				0x03                    // 0x00 
#define		Sta308a_ConfF_Init				0x00//|0x40  //0x05     // 0x00 
#define		Sta308a_ConfG_Init				0x02                    // 0x00 
#define		Sta308a_ConfH_Init				0x7e//0xfe              // 0x7e 
#define		Sta308a_ConfI_Init				0x00//0x80              // 0x80 
#define		Sta308a_Mmute_Init				0x00                    // 0x00 
#define		Sta308a_Mvol_Init				0x00                    // 0x00 
#define		Sta308a_C1Vol_Init				0x60-0x05+0x02          // 0x60 
#define		Sta308a_C2Vol_Init				0x60-0x05+0x02          // 0x60 
#define		Sta308a_C3Vol_Init				0x60                    // 0x60 
#define		Sta308a_C4Vol_Init				0x60                    // 0x60 
#define		Sta308a_C5Vol_Init				0x60                    // 0x60 
#define		Sta308a_C6Vol_Init				0x60-0x09               // 0x60 
#define		Sta308a_C7Vol_Init				0x60                    // 0x60 
#define		Sta308a_C8Vol_Init				0x60                    // 0x60 
#define		Sta308a_C1VTNB_Init			        0x10                    // 0x0c 
#define		Sta308a_C2VTNB_Init			        0x10                    // 0x0c 
#define		Sta308a_C3VTNB_Init			        0x10                    // 0x0a 
#define		Sta308a_C4VTNB_Init			        0x10                    // 0x10 
#define		Sta308a_C5VTNB_Init			        0x10                    // 0x10 
#define		Sta308a_C6VTNB_Init			        0x10                    // 0x10 
#define		Sta308a_C7VTNB_Init	       		        0x10                    // 0x10 
#define		Sta308a_C8VTNB_Init			        0x10                    // 0x10 
#define		Sta308a_C12im_Init				0x10                    // 0x22 
#define		Sta308a_C34im_Init				0x32                    // 0x12 
#define		Sta308a_C56im_Init				0x54                    // 0x54 
#define		Sta308a_C78im_Init				0x76                    // 0x76 
#define		Sta308a_Auto1_Init				0x00                    // 0x00 
#define		Sta308a_Auto2_Init				0x83                    // 0x80 
#define		Sta308a_Auto3_Init				0x03//+0x10//2          // 0x00 
#define		Sta308a_PreEQ_Init				0xa0                    // 0x00 
#define		Sta308a_Ageq_Init			        0x0f                    // 0x0f 
#define		Sta308a_Bgeq_Init			        0x0f                    // 0x0f 
#define		Sta308a_Cgeq_Init				0x0f                    // 0x0f 
#define		Sta308a_Dgeq_Init				0x0f                    // 0x0f 
#define		Sta308a_Fgeq_Init				0x0f                    // 0x0f 
#define		Sta308a_BQlp_Init				0x00                    // 0x00 
#define		Sta308a_MXlp_Init				0x00                    // 0x00 
#define		Sta308a_EQbp_Init				0x00                    // 0x00 
#define		Sta308a_ToneBP_Init			        0x00                    // 0x00 
#define		Sta308a_Tone_Init				0x77                    // 0x77 
#define		Sta308a_C1234ls_Init			        0x00                    // 0x00 
#define		Sta308a_C5678ls_Init		        	0x00//6a                // 0x00 
#define		Sta308a_L1ar_Init				0x6a//9                 // 0x6a 
#define		Sta308a_L1atrt_Init			        0x69//a                 // 0x69 
#define		Sta308a_L2ar_Init			        0x6a//9                 // 0x6a 
#define		Sta308a_L2atrt_Init			        0x69                    // 0x69 
#define		Sta308a_C12ot_Init				0x20                    // 0x40 
#define		Sta308a_C34ot_Init				0x64                    // 0x62 
#define		Sta308a_C56ot_Init				0x51                    // 0x51 
#define		Sta308a_C78ot_Init				0x73                    // 0x73 
#define		Sta308a_C12om_Init				0x10                    // 0x10 
#define		Sta308a_C34om_Init				0x32                    // 0x32 
#define		Sta308a_C56om_Init				0x54                    // 0x54 
#define		Sta308a_C78om_Init				0x76                    // 0x76 
#define		Sta308a_Cfaddr1_Init			        0x00                    // 0x00 
#define		Sta308a_Cfaddr2_Init			        0x00                    // 0x00 
#define		Sta308a_B1cf1_Init				0x00                    // 0x00 
#define		Sta308a_B1cf2_Init				0x00                    // 0x00 
#define		Sta308a_B1cf3_Init				0x00                    // 0x00 
#define		Sta308a_B2cf1_Init				0x00                    // 0x00 
#define		Sta308a_B2cf2_Init				0x00                    // 0x00 
#define		Sta308a_B2cf3_Init				0x00                    // 0x00 
#define		Sta308a_A1cf1_Init				0x00                    // 0x00 
#define		Sta308a_A1cf2_Init				0x00                    // 0x00 
#define		Sta308a_A1cf3_Init				0x00                    // 0x00 
#define		Sta308a_A2cf1_Init				0x00                    // 0x00 
#define		Sta308a_A2cf2_Init				0x00                    // 0x00 
#define		Sta308a_A2cf3_Init				0x00                    // 0x00 
#define		Sta308a_B0cf1_Init				0x00                    // 0x00 
#define		Sta308a_B0cf2_Init				0x00                    // 0x00 
#define		Sta308a_B0cf3_Init				0x00                    // 0x00 
#define		Sta308a_Cfud_Init				0x00                    // 0x00 
#define		Sta308a_MPCC1_Init				0x2d                    // 0x2d 
#define		Sta308a_MPCC2_Init				0xc0                    // 0xc0 
#define		Sta308a_RES0_Init 				0x00                    // 0x00 
#define		Sta308a_RES1_Init				0x00                    // 0x00 
#define		Sta308a_PSC1_Init				0x00                    // 0x00 
#define		Sta308a_PSC2_Init				0x0f                    // 0x0f 
#define		Sta308a_PSC3_Init				0xff                    // 0xff 


//  Sta308 Address 

#define		Sta308a_ConfA				0x00 
#define		Sta308a_ConfB				0x01 
#define		Sta308a_ConfC				0x02 
#define		Sta308a_ConfD				0x03 
#define		Sta308a_ConfE				0x04 
#define		Sta308a_ConfF				0x05 
#define		Sta308a_ConfG				0x06 
#define		Sta308a_ConfH				0x07 
#define		Sta308a_ConfI				0x08 

#define		Sta308a_Mmute				0x09 
#define		Sta308a_Mvol				0x0a 

#define		Sta308a_C1Vol				0x0b 
#define		Sta308a_C2Vol				0x0c 
#define		Sta308a_C3Vol				0x0d 
#define		Sta308a_C4Vol				0x0e 
#define		Sta308a_C5Vol				0x0f 
#define		Sta308a_C6Vol				0x10 
#define		Sta308a_C7Vol				0x11 
#define		Sta308a_C8Vol				0x12 

#define		Sta308a_C1VTNB		              	0x13 
#define		Sta308a_C2VTNB			        0x14 
#define		Sta308a_C3VTNB		        	0x15 
#define		Sta308a_C4VTNB			        0x16 
#define		Sta308a_C5VTNB	         		0x17 
#define		Sta308a_C6VTNB		        	0x18 
#define		Sta308a_C7VTNB			        0x19 
#define		Sta308a_C8VTNB			        0x1a 

#define		Sta308a_C12im				0x1b 
#define		Sta308a_C34im				0x1c 
#define		Sta308a_C56im				0x1d 
#define		Sta308a_C78im				0x1e 

#define		Sta308a_Auto1				0x1f 
#define		Sta308a_Auto2				0x20 
#define		Sta308a_Auto3				0x21 
#define		Sta308a_PreEQ				0x22 
#define		Sta308a_Ageq				0x23 
#define		Sta308a_Bgeq				0x24 
#define		Sta308a_Cgeq				0x25 
#define		Sta308a_Dgeq				0x26 
#define		Sta308a_Fgeq				0x27 
#define		Sta308a_BQlp				0x28 
#define		Sta308a_MXlp				0x29 
#define		Sta308a_EQbp				0x2a 
#define		Sta308a_ToneBP			        0x2b 
#define		Sta308a_Tone				0x2c 
#define		Sta308a_C1234ls			        0x2d 
#define		Sta308a_C5678ls			        0x2e 
#define		Sta308a_L1ar				0x2f 
#define		Sta308a_L1atrt			        0x30 
#define		Sta308a_L2ar				0x31 
#define		Sta308a_L2atrt			        0x32 
#define		Sta308a_C12ot				0x33 
#define		Sta308a_C34ot				0x34 
#define		Sta308a_C56ot				0x35 
#define		Sta308a_C78ot				0x36 
#define		Sta308a_C12om				0x37 
#define		Sta308a_C34om				0x38 
#define		Sta308a_C56om				0x39 
#define		Sta308a_C78om				0x3a 
#define		Sta308a_Cfaddr1			        0x3b 
#define		Sta308a_Cfaddr2			        0x3c 
#define		Sta308a_B1cf1				0x3d 
#define		Sta308a_B1cf2				0x3e 
#define		Sta308a_B1cf3				0x3f 
#define		Sta308a_B2cf1				0x40 
#define		Sta308a_B2cf2				0x41 
#define		Sta308a_B2cf3				0x42 
#define		Sta308a_A1cf1				0x43 
#define		Sta308a_A1cf2				0x44 
#define		Sta308a_A1cf3				0x45 
#define		Sta308a_A2cf1				0x46 
#define		Sta308a_A2cf2				0x47 
#define		Sta308a_A2cf3				0x48 
#define		Sta308a_B0cf1				0x49 
#define		Sta308a_B0cf2				0x4a 
#define		Sta308a_B0cf3				0x4b 
#define		Sta308a_Cfud				0x4c 
#define		Sta308a_MPCC1				0x4d 
#define		Sta308a_MPCC2				0x4e 
#define		Sta308a_RES0 				0x4f 

#define		Sta308a_RES1				0x50 
#define		Sta308a_PSC1				0x51 
#define		Sta308a_PSC2				0x52 
#define		Sta308a_PSC3				0x53 

//  Volume Value 
#define		VOL00								0x32+0x20					 
#define		VOL01								0x31+0x1b 

#define		VOL02								0x30+0x10 
#define		VOL03								0x2f+0x08 
#define		VOL04								0x36 
#define		VOL05								0x2d+0x04 
#define		VOL06								0x2c+0x02 


#define		VOL07								0x2b+0x01 
#define		VOL08								0x2a+0x01 
#define		VOL09								0x29+0x01 
#define		VOL10								0x28+0x01 
#define		VOL11								0x27+0x01 
#define		VOL12								0x26+0x01 
#define		VOL13								0x25+0x01 
#define		VOL14								0x24+0x01 

#define		VOL15								0x23+0x01 
#define		VOL16								0x22+0x01 
#define		VOL17								0x21+0x01 
#define		VOL18								0x20+0x01 
#define		VOL19								0x1f+0x01 
#define		VOL20								0x1f 
#define		VOL21								0x1d+0x01 
#define		VOL22								0x1c+0x01 
#define		VOL23								0x1b+0x01 
#define		VOL24								0x1a+0x01 

#define		VOL25								0x19+0x01 
#define		VOL26								0x18+0x01 
#define		VOL27								0x17+0x01 
#define		VOL28								0x16+0x01 
#define		VOL29								0x15+0x01 
#define		VOL30								0x14+0x01 
#define		VOL31								0x13+0x01 
#define		VOL32								0x12+0x01 
#define		VOL33								0x11+0x01 
#define		VOL34								0x10+0x01 

#define		VOL35								0x0f+0x01 
#define		VOL36								0x0f 
#define		VOL37								0x0d+0x01 
#define		VOL38								0x0c+0x01 
#define		VOL39								0x0b+0x01 
#define		VOL40								0x0a+0x01 
#define		VOL41								0x09+0x01 
#define		VOL42								0x08+0x01 
#define		VOL43								0x07+0x01 
#define		VOL44								0x06+0x01 

#define		VOL45								0x05//+0x01 
#define		VOL46								0x04//+0x01 
#define		VOL47								0x03//+0x01 
#define		VOL48								0x02//+0x01 
#define		VOL49								0x01//+0x01 
#define		VOL50								0x00 

//  EQ Define 
#define   EQVal								17 
#define   EQNum								8	 

#define   EQSingleVal							5 
#define   EQSingleNum							3	 

void	ProcessEQ(void); 
void	ReadEqValue(char , char , char ); 
/*************************************/



extern	void	InitSta308a(void); 
extern	void	SendSta308aVol(unsigned char); 
extern  void	SendSta308aMuteOff(void); 
extern  void	SendSta308aMuteOn(void); 
extern	void	SendSta308aBass(unsigned char); 
extern  void	Select308AM(unsigned char); 
extern  void	Slect308AMFreq(unsigned char); 
extern  void	ProcessEQ(void); 

 

smart_pic
Offline
Зарегистрирован: 17.04.2016

slider пишет:

kimmel.dima , как разберетесь, черкните сюда. У меня вопрос какая минимильная инициализация является необходимой для запуска. 

 У самого мастер кит BA2070 валяется  на TAS5504A (+ PL1705 + 2 PCM1808 ) и усилители BA2071 http://lib.chipdip.ru/269/DOC000269591.pdf .  Кончилась atmega8 (греется, кз на пине было) , она с кнопок громкости управляла ей.  TAS5504A была куплена новая и заменена. Техподдержки на мастер кит нет, прошивки сказали нет (секрет), покупайте новую линейку усилителей. // А зачем , раз такая низкая надёжность и не ремонтопригодность при потраченных 8т.р. ? 

 Так что единственный вариант починить через arduino .

Схема  BA2070 ( BM2070) на  TAS5504 к BM2071  http://masterkit.ru/zip/bm2070.pdf  

Также хочу разобраться как управлять этим набором.

Пишите в личку , может совместно осилим

 

kimmel.dima
Offline
Зарегистрирован: 20.02.2014
тас5508 работает, на дисплее непонятные вещи. Может кто помочь?

[code]
#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <Wire.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);



//I2C device address of  CS8416
#define CS8416_ADDRESS 0x20
//AD0 = 0
//AD1 = 0
//AD2 = 0
//BASE = 0010xxx

#define TAS5508_ADDRESS 0x36

// 1/3Oct Equalizer Frequencies
const uint16_t EQFreqs[32] = {0,20,25,32,40,50,63,80,
                        100,125,160,200,250,315,400,500,
                        630,800,1000,1250,1600,2000,2500,3150,
                        4000,5000,6300,8000,10000,12500,16000,20000};

// Strings to show
const char EQFreqStr[32][8] = {"None","20Hz","25Hz","32Hz",
                              "40Hz","50Hz","63Hz","80Hz",
                              "100Hz","125Hz","160Hz","200Hz",
                              "250Hz","315Hz","400Hz","500Hz",
                              "630Hz","800Hz","1.0kHz","1.25kHz",
                              "1.6kHz","2.0kHz","2.5kHz","3.15kHz",
                              "4.0kHz","5.0kHz","6.3kHz","8.0kHz",
                              "10kHz","12.5kHz","16kHz","20kHz"};

//string for Q each index (actual Q = Q^2/100)
const char EQQStr[32][8] = {"0.000","0.010","0.040","0.090",
              "0.160","0.250","0.360","0.490",
              "0.640","0.810","1.000","1.210",
              "1.440","1.690","1.960","2.250",
              "2.560","2.890","3.240","3.610",
              "4.000","4.410","4.840","5.290",
              "5.760","6.250","6.760","7.290",
              "7.840","8.410","9.000","9.610"};

const char EQTypeStr[4][12] = {"None","LowShelf","HighShelf","Peaking"};

// Crossover Filter Point32_ts
const uint16_t FilterFreqs[32] =
                     {0,50,65,80,100,120,150,180,220,260,300,350,
                      400,500,650,800,1000,1200,1500,1800,2200,2600,3000,
                      3500,4000,5000,6500,8000,10000,12000,15000,18000};

const char FilterFreqStr[32][8] =
        {"None","50Hz","65Hz","80Hz",
         "100Hz","120Hz","150Hz","180Hz",
         "220Hz","260Hz","300Hz","350Hz",
         "400Hz","500Hz","650Hz","800Hz",
         "1kHz","1.2kHz","1.5kHz","1.8kHz",
         "2.2kHz","2.6kHz","3.0kHz","3.5kHz",
         "4.0kHz","5.0kHz","6.5kHz","8.0kHz",
         "10kHz","12kHz","15kHz","18kHz"};

// CS8416 SPDIF Frequencies
const uint32_t SPDIFFreqs[4] = {44100,48000,88200,96000};
const char currentfsstr[4][8] = {"44.1kHz","48kHz","88.2kHz","96kHz"};

// Global Values
uint8_t currentfs;      //Fs (44.1/48/88.2/96) current state
uint8_t currentFilterMenu;  //Filter Menu Number
uint8_t FilterChanged;    //1: There were data change
int32_t newfs;
int32_t return_code;
uint8_t MUTEMode;
uint8_t currentEQMenu;  //EQ Menu Number
uint8_t EQChanged;    //1: there were data change

uint8_t KeyMode;  //0:none, 1: First Key, 2: Repeat Key
uint8_t PrevKey;  //remember previous key state
uint8_t NewKey;   //get new key entry
uint8_t WriteData;
// Parameters to store Flash
struct EQParam {
   uint8_t   EQType;   //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
   uint8_t   EQFreq;   //0 - 31
   uint8_t   EQQ;            //0 - 31
   int8_t   EQGain;   //-15,... 0,... 15
   }; //4 bytes

struct FilterParam {
   uint8_t LPF;   // 0:No LPF
   uint8_t HPF;   //0:No HPF
   int8_t OFFSET; //0:mid
   uint8_t MUTE;  //0:normal, 1:mute
   }; //4 bytes

struct Params {
   int16_t currentvol;
   int8_t currentch;
   int8_t currentwin;

   struct FilterParam FilterParams[4];   //CH12,34,56,78

   struct EQParam EQParams[4][3];   // CH12,34,56,78 - EQ5,6,7

} ;
struct Params DevParam; //4 + 16 + 48 = 68 bytes
struct Params DevParam_EEPROM __attribute__((section(".eeprom")));


//Utility Functions

void msDelay(uint16_t delay)
{
  while (delay--) 
  {
  _delay_ms(1);
  } 
}

//Read Flash
void readDevParam()
{
  eeprom_busy_wait();
  eeprom_read_block(&DevParam, &DevParam_EEPROM,sizeof(DevParam_EEPROM));   

}

//Write Flash
void writeDevParam(int mode)
{
  eeprom_busy_wait();
  switch (mode)
    {
    case 0: //Write All
      eeprom_write_block(&DevParam, &DevParam_EEPROM, sizeof(DevParam_EEPROM));
      break;
    case 1: //Volume Only
      eeprom_write_word(&(DevParam_EEPROM.currentvol), DevParam.currentvol);
      break;
    case 2: //Channel Only
      eeprom_write_byte(&(DevParam_EEPROM.currentch), DevParam.currentch);
      break;
    default:
      eeprom_write_block(&DevParam, &DevParam_EEPROM, sizeof(DevParam_EEPROM));
      break;
    }
  eeprom_busy_wait();
}

//LCD Functions

//LCD Function, String 0 terminated SendStr, Line is Upper(1) Lower(2)
void SendString(char * SendStr, uint8_t Line)
{
   int StrLen;
   char Packet[32];
   int i;

  lcd.setCursor(0,0);
  msDelay(1);

  if (Line == 2)
  {
    lcd.setCursor(0,1);
  }
  msDelay(1);

   StrLen = strlen(SendStr);
   memset(Packet, 0, sizeof(Packet));
   strncpy(Packet, SendStr, 16);
   for (i = StrLen; i <= 18; i++)
   {
      Packet[i] = 0x20;
   }

    lcd.print(Packet);
  lcd.setCursor(0,0);
}

//LCD Function
void ClearLCD()
{
  lcd.clear();
}

//LCD Function
/*uint8_t PollKey()
{

  if ( bit_is_clear(PINA, PINA0))
    return 3;

  if ( bit_is_clear(PINA, PINA4))
    return 4;

  if ( bit_is_clear(PINA, PINA1))
    return 5;

  if ( bit_is_clear(PINA, PINA3))
    return 6;

  if ( bit_is_clear(PINA, PINA2))
    return 1;

         return 1;   //ENTER
         return 2;   //cancel
         return 3;   //up
         return 4;   //Down
         return 5;   //Left
         return 6;   //right

   return 0;
}*/

//I2C Function
/* I2CWrite
write data to slave.
Sends START, slave address, index and then data, STOP
Waits for slave to respond. 
PARAM1: uint8_t address - slave device address
PARAM2: uint8_t index - subaddress of register/memory to write 
PARAM3: char * writestring - write data buffer
PARAM4: uint8_t len  - length of data to write   
RETURN: 0 or negative error code (see code)
*/
const uint16_t I2C_TIMEOUT = 1000; // Used to check for errors in I2C communication
  
uint8_t I2CWrite(uint8_t address,uint8_t subaddress, uint8_t * writestring,  bool sendStop)
{ 
  uint8_t length;
  Wire.beginTransmission(address);
  Wire.write(subaddress); 
  Wire.write(writestring,length);
  uint8_t rcode = Wire.endTransmission(sendStop); // Returns 0 on success
  return rcode; 
  }


/* I2CRead 
PARAM1: uint8_taddress - slave address
PARAM2: uint8_t subaddress - subaddress in in EEPROM to read from 
PARAM3: char *retstring          - buffer for data
PARAM4: uint8_t len   - size of data buffer 
          
RETURN: 0 or error code*/  
uint8_t I2CRead(uint8_t address,uint8_t subaddress, uint8_t * retstring, uint8_t nbytes)
{
  uint32_t timeOutTimer;
  Wire.beginTransmission(address);
  Wire.write(subaddress);
  uint8_t rcode = Wire.endTransmission(false); // Don't release the bus
  if (rcode)
  {
    return rcode; // access failed
  }

  Wire.requestFrom(address, nbytes, (uint8_t)true); 
  for (uint8_t cnt = 0; cnt < nbytes; cnt++)
  {
    if (Wire.available())
      retstring[cnt] = Wire.read();
    else {
      timeOutTimer = micros();
      while (((micros() - timeOutTimer) < I2C_TIMEOUT) && !Wire.available());
      if (Wire.available())
        retstring[cnt] = Wire.read();
      else {
        
        return 5; // This error value is not already taken by endTransmission
      }
    }
  }
  return 0; // Success
}

//I2C Functions
uint8_t I2C_GetFs()
{
   //returns data rate.
   //  0 : Error
   //  1 : invalid
   //  2 : 32 kHz
   //  3 : 38 kHz
   //  4 : 44.1kHz
   //  5 : 48 kHz
   //  6 : 88.2 kHz
   //  7 : 96 kHz
   //  8 : 176.4kHz
   //  9 : 192 kHz
   char Clk_Mode;
   uint8_t return_code;
   return_code = I2CRead(TAS5508_ADDRESS, 0x00, 1, 1);
   if (return_code != 0) {      return 0;   }
   
   return ( ((1 & 0xE0) >> 5) + 2  );
   
}

// TAS5518 and PSVC Volume control
// PSVC is 4 bit programmable, 16dB
void I2C_SetVolume()
{
   char test_string[4];
   uint8_t return_code;
   int16_t TAS5508Volume;
   uint8_t PortAVolume;
   if (DevParam.currentvol < 0x48)   //+x.xx dB
   {
      TAS5508Volume = DevParam.currentvol;
      PortAVolume = 0x0F;
   }
   else
   {
      if (DevParam.currentvol < 0x89)  //0 - -15dB
      {
         TAS5508Volume = 0x48;
         PortAVolume = 16 - (uint8_t)(((DevParam.currentvol - 0x48)) / 4);
      }
      else
      {
         TAS5508Volume = DevParam.currentvol - 0x48;
         PortAVolume = 0;
      }
   }

   //set volume
   test_string[0] = 0;
   test_string[1] = 0;
   test_string[2] = 0;
   test_string[3] = TAS5508Volume & 0xff;
   return_code = I2CWrite(TAS5508_ADDRESS, 0xD9, test_string, 4);
   //WrPortI(PADR, &PADRShadow, PortAVolume);

  //Output Volume to Control
  PORTB = (PortAVolume)<<4;
}

// CS8416 Rx Selector
void I2C_SetCH()
{
   
  WriteData = 0x80 + DevParam.currentch * 8 + DevParam.currentch;
  I2CWrite(CS8416_ADDRESS, 0x04, WriteData, 1);
}

//Make biquad Filter parameter
void MakeEQ(int32_t Fs, int32_t f0, int32_t mode, double Q, int32_t gain,  uint8_t * EQ)
{
   double w0;
   double cosw0;
   double sinw0;
   double alpha;
   double A;
   double sqrtA;
   double twosqrtAalpha;
   double b0;
   double b1;
   double b2;
   double a0;
   double a1;
   double a2;
   int32_t Qb0;
   int32_t Qb1;
   int32_t Qb2;
   int32_t Qa1;
   int32_t Qa2;

   b0 = 0.0;
   b1 = 1.0;
   b2 = 0.0;
   a0 = 1.0;
   a1 = 0.0;
   a2 = 0.0;

   w0 = 2.000 * 3.141516 * f0 / Fs;
   cosw0 = cos(w0);
   sinw0 = sin(w0);

   alpha = sinw0 / (2.00 * Q);
   A =  pow( ((double)(gain)) /40.0 , 10);
   sqrtA = sqrt(A);
   twosqrtAalpha = 2*sqrtA*alpha;

   if ( mode == 0) //HPF
   {
      a0 = 1.0 + alpha;
      b1 = -1.0 * (1.0 + cosw0) / a0 ;
      b0 = -1.0 * b1 / 2.00;
      b2 = b0;
      a1 = -2.0 * cosw0 / a0 ;
      a2 = (1.0 - alpha) / a0;
   }
   if ( mode == 1) //LPF
   {
      a0 = 1.0 + alpha;
      b1 = (1.0 - cosw0) / a0 ;
      b0 = b1 / 2.00;
      b2 = b0;
      a1 = -2.0 * cosw0 / a0 ;
      a2 = (1.0 - alpha) / a0;
   }
   if ( mode == 2) //LowShelf
   {
      a0 = (A+1)+(A-1)*cosw0+twosqrtAalpha;
      b0 = A*((A+1) - (A-1)*cosw0 + twosqrtAalpha);
      b1 = 2*A*((A-1) - (A+1)*cosw0) ;
      b2 = A*((A+1)-(A-1)*cosw0-twosqrtAalpha);
      a1 = -2.0*((A-1)+(A+1)*cosw0) ;
      a2 = (A+1)+(A-1)*cosw0-twosqrtAalpha;
   }
   if ( mode == 3) //HighShelf
   {
      a0 = (A+1)-(A-1)*cosw0+twosqrtAalpha;
      b0 = A*((A+1) + (A-1)*cosw0 + twosqrtAalpha);
      b1 = -2*A*((A-1) + (A+1)*cosw0) ;
      b2 = A*((A+1)+(A-1)*cosw0-twosqrtAalpha);
      a1 = 2.0*((A-1)-(A+1)*cosw0) ;
      a2 = (A+1)-(A-1)*cosw0-twosqrtAalpha;
   }
   if ( mode == 4) //Peaking
   {
      a0 = 1.0 + alpha / A;
      b0 = 1.0 + alpha * A;
      b1 = -2.0 * cosw0 ;
      b2 = 1.0 - alpha * A;
      a1 = -2.0 * cosw0 ;
      a2 = 1.0 - alpha / A;
   }
   if ( mode > 1)
   {
      b0 = b0 / a0;
      b1 = b1 / a0;
      b2 = b2 / a0;
      a1 = a1 / a0;
      a2 = a2 / a0;
   }
   //quantize
   Qb0 = (int32_t)(b0 *  8388608L);
   Qb1 = (int32_t)(b1 *  8388608L);
   Qb2 = (int32_t)(b2 *  8388608L);
   Qa1 = (int32_t)(a1 * -8388608L);
   Qa2 = (int32_t)(a2 * -8388608L);

   //Modify sign bit
   if (Qb0 < 0) Qb0 = Qb0 + 268435456L;
   if (Qb1 < 0) Qb1 = Qb1 + 268435456L;
   if (Qb2 < 0) Qb2 = Qb2 + 268435456L;
   if (Qa1 < 0) Qa1 = Qa1 + 268435456L;
   if (Qa2 < 0) Qa2 = Qa2 + 268435456L;

   //get each byte
   *(EQ   ) = (uint8_t)((Qb0>>24) & 0xFF);
   *(EQ+1 ) = (uint8_t)((Qb0>>16) & 0xFF);
   *(EQ+2 ) = (uint8_t)((Qb0>>8)  & 0xFF);
   *(EQ+3 ) = (uint8_t)( Qb0      & 0xFF);
   *(EQ+4 ) = (uint8_t)((Qb1>>24) & 0xFF);
   *(EQ+5 ) = (uint8_t)((Qb1>>16) & 0xFF);
   *(EQ+6 ) = (uint8_t)((Qb1>>8)  & 0xFF);
   *(EQ+7 ) = (uint8_t)( Qb1      & 0xFF);
   *(EQ+8 ) = (uint8_t)((Qb2>>24) & 0xFF);
   *(EQ+9 ) = (uint8_t)((Qb2>>16) & 0xFF);
   *(EQ+10) = (uint8_t)((Qb2>>8)  & 0xFF);
   *(EQ+11) = (uint8_t)( Qb2      & 0xFF);
   *(EQ+12) = (uint8_t)((Qa1>>24) & 0xFF);
   *(EQ+13) = (uint8_t)((Qa1>>16) & 0xFF);
   *(EQ+14) = (uint8_t)((Qa1>>8)  & 0xFF);
   *(EQ+15) = (uint8_t)( Qa1      & 0xFF);
   *(EQ+16) = (uint8_t)((Qa2>>24) & 0xFF);
   *(EQ+17) = (uint8_t)((Qa2>>16) & 0xFF);
   *(EQ+18) = (uint8_t)((Qa2>>8)  & 0xFF);
   *(EQ+19) = (uint8_t)( Qa2      & 0xFF);
}

void ClearEQ(uint8_t * EQ)
{
   //get each byte
   memset(EQ, 0,20);
   *(EQ+1 ) = 0x80;
}

// convert Q value to string
double EQQNumToValue(int32_t EQQ)
{
   double retVal;
   if ((EQQ < 0) || (EQQ > 31))
   {
      retVal = 0;
   }
   else
   {
      retVal = (EQQ * EQQ) / 100.00 ;
   }
   return retVal;
}

// convert EQ frequency value to string
int32_t FreqFromEQSetting(int32_t EQSetting)
{
   if ((EQSetting < 0) || (EQSetting > 31))
      return 0;

   return EQFreqs[EQSetting];
}

// convert Filter frequency value to string
int32_t FreqFromFilterSetting(int32_t FilterSetting)
{
   if ((FilterSetting < 0) || (FilterSetting > 31))
      return 0;

   return FilterFreqs[FilterSetting];
}

// Calculate Equalizers and apply
void applyEQ(int32_t FS)
{
   uint8_t EQ[20];
   int32_t return_code;
   int32_t Freq;
   double Q;

   int32_t i;
   int32_t j;

   //Loop for CH12,34,56,78
   for (j = 0; j <= 3; j++)
   {
      //Loop for EQ5,6,7 in each CH
      for (i = 0; i <= 2; i++)
      {
         Freq = FreqFromEQSetting(DevParam.EQParams[j][i].EQFreq);
         if ((Freq > 0) && (DevParam.EQParams[j][i].EQType > 0))
         {
            Q = EQQNumToValue(DevParam.EQParams[j][i].EQQ);
            MakeEQ(FS, Freq, DevParam.EQParams[j][i].EQType + 1, Q ,
             DevParam.EQParams[j][i].EQGain, EQ);
         }
         else
         {
            ClearEQ(EQ);
         }
         return_code = I2CWrite(TAS5508_ADDRESS, 0x55 + i + j*7*2,EQ,20);
         return_code = I2CWrite(TAS5508_ADDRESS, 0x5C + i + j*7*2,EQ,20);
      }
   }
}

// Calculate Filter and apply
void applyfilter(int32_t FS)
{
   uint8_t EQ[20];
   int32_t return_code;
   int32_t Freq;
   uint8_t Param[4];
   uint8_t MutePattern;
   int32_t i;

   for (i = 0; i <= 3; i++)
   {
      //CHxx EQ1,2 (LPF)
      Freq = FreqFromFilterSetting(DevParam.FilterParams[i].LPF);
      if (Freq > 0)
      {
         MakeEQ(FS, Freq, 1, 0.71, 0, EQ);     //Q=0.71 LPF
      }
      else
      {
         ClearEQ(EQ);
      }
      return_code = I2CWrite(TAS5508_ADDRESS, 0x51+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x52+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x58+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x59+i*14,EQ,20);

      //CHxx EQ3,4 (HPF)
      Freq = FreqFromFilterSetting(DevParam.FilterParams[i].HPF);
      if (Freq > 0)
      {
         MakeEQ(FS, Freq, 0,  0.71, 0, EQ);     //Q=0.71, HPF
      }
      else
      {
         ClearEQ(EQ);
      }
      return_code = I2CWrite(TAS5508_ADDRESS, 0x53+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x54+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x5A+i*14,EQ,20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x5B+i*14,EQ,20);
   }

   Param[0] = 0;
   Param[1] = 0;
   Param[2] = 0;

   for (i = 0; i <= 3; i++)
   {
      //CH Offset
      Param[3] = (0x48 - DevParam.FilterParams[i].OFFSET * 4);
      return_code = I2CWrite(TAS5508_ADDRESS, 0xD1+i*2,Param,4);
      return_code = I2CWrite(TAS5508_ADDRESS, 0xD2+i*2,Param,4);
   }

   //CH Mute
   MutePattern = 
                (DevParam.FilterParams[0].MUTE * 0x03 +
                 DevParam.FilterParams[1].MUTE * 0x0C +
                 DevParam.FilterParams[2].MUTE * 0x30 +
                 DevParam.FilterParams[3].MUTE * 0xC0);
   return_code = I2CWrite(TAS5508_ADDRESS, 0x0F, &MutePattern,1);
}


//Filter setting entry
void Menu01(int32_t NewKeyData)
{
   char Line1[20];
   char Line2[20];

      switch (NewKeyData)
      {
      case 1:  //Enter
      case 4:    //Down
         currentFilterMenu = 0;
         FilterChanged = 0;
         DevParam.currentwin = 3;
         return;
         break;
      case 2:  //Cancel
      case 3:    //Up
         DevParam.currentwin = 0;
         return;
         break;
      case 5:    //Left
      case 6:   //Right
         DevParam.currentwin = 2;
         return;
         break;
      default:
         break;
      }

      //Create Screen String
      sprintf(Line1, "KDA-TAS4i");
      sprintf(Line2, "Filter Menu ?");
      //Send LCD
      SendString(Line1,1);
      SendString(Line2,2);
}

//EQ Setting Entry
void Menu02(int32_t NewKeyData)
{
   char Line1[20];
   char Line2[20];

      switch (NewKeyData)
      {
      case 1:  //Enter
      case 4:    //Down
    currentEQMenu = 0;
    EQChanged = 0;
         DevParam.currentwin = 4;
         return;
         break;
      case 2:  //cancel
      case 3:    //Up
         DevParam.currentwin = 0;
         return;
         break;
      case 5:    //Left
      case 6:   //Right
         DevParam.currentwin = 1;
         return;
         break;
      default:
         break;
      }

      //Create Screen String
      sprintf(Line1, "KDA-TAS4i");
      sprintf(Line2, "EQ Menu ?");
      //Send LCD
      SendString(Line1,1);
      SendString(Line2,2);
}

// Convert Filter value to string
void FilterNumToStr(int32_t FilterNum, char * FilterStr)
{

   if ((FilterNum < 0) || (FilterNum > 31))
      strcpy(FilterStr, "--");
   else
      strcpy(FilterStr, FilterFreqStr[FilterNum]);

}

void MuteToStr(int32_t MuteValue, char * MuteStr)
{
   if (MuteValue == 0)
   {
      strcpy(MuteStr, "In Use");
   }
   else
   {
      strcpy(MuteStr, "Mute");
   }
}

//Filter Menu Screen
void FilterMenu(int32_t NewKeyData)
{
   //Control EQ0,1(reserved for LPF) ,2,3 (for HPF)
   char Line1[20];
   char Line2[20];

   int32_t CurrentCH;
   int32_t CurrentFilterSetting;
   CurrentCH = (int32_t)(currentFilterMenu / 4);
   CurrentFilterSetting = currentFilterMenu - CurrentCH * 4;

      switch (NewKeyData)
      {
      case 1:  //Enter
         //save changes
         FilterChanged = 0;
         DevParam.currentwin = 3;
         applyfilter(SPDIFFreqs[currentfs - 4]);
           writeDevParam(0);
         return;
         break;
      case 2:   //Cancel
         //discard changes
         FilterChanged = 0;
           readDevParam();
         DevParam.currentwin = 1;
           writeDevParam(0);
         return;
         break;
      case 3:    //Up
         if (currentFilterMenu > 0)
            currentFilterMenu -= 1;
         else
     {
      if (currentFilterMenu == 0)
      {
             DevParam.currentwin = 1;
             return;
      }
     }
         break;
      case 4:    //Down
         if (currentFilterMenu < 15)
            currentFilterMenu += 1;
         else
            currentFilterMenu = 15;
         break;
      case 5:    //Left
         FilterChanged = 1;
         switch (CurrentFilterSetting)
         {
            case 0:   //LPF
               if (DevParam.FilterParams[CurrentCH].LPF > 0)
                   DevParam.FilterParams[CurrentCH].LPF -= 1;
               else
                   DevParam.FilterParams[CurrentCH].LPF = 0;
               break;
            case 1:   //HPF
               if (DevParam.FilterParams[CurrentCH].HPF > 0)
                   DevParam.FilterParams[CurrentCH].HPF -= 1;
               else
                   DevParam.FilterParams[CurrentCH].HPF = 0;
               break;
            case 2:   //OFFSET
               if (DevParam.FilterParams[CurrentCH].OFFSET > -15)
                   DevParam.FilterParams[CurrentCH].OFFSET -= 1;
               else
                   DevParam.FilterParams[CurrentCH].OFFSET = -15;
               break;
            case 3:   //MUTE
               if (DevParam.FilterParams[CurrentCH].MUTE == 1)
                   DevParam.FilterParams[CurrentCH].MUTE = 0;
               else
                   DevParam.FilterParams[CurrentCH].MUTE = 1;
               break;
         }
         break;
      case 6:   //Right
         FilterChanged = 1;
         switch (CurrentFilterSetting)
         {
            case 0:   //LPF
               if (DevParam.FilterParams[CurrentCH].LPF < 31)
                   DevParam.FilterParams[CurrentCH].LPF += 1;
               else
                   DevParam.FilterParams[CurrentCH].LPF = 31;
               break;
            case 1:   //HPF
               if (DevParam.FilterParams[CurrentCH].HPF < 31)
                   DevParam.FilterParams[CurrentCH].HPF += 1;
               else
                   DevParam.FilterParams[CurrentCH].HPF = 0;
               break;
            case 2:   //OFFSET
               if (DevParam.FilterParams[CurrentCH].OFFSET < 15)
                   DevParam.FilterParams[CurrentCH].OFFSET += 1;
               else
                   DevParam.FilterParams[CurrentCH].OFFSET = 15;
               break;
            case 3:   //MUTE
               if (DevParam.FilterParams[CurrentCH].MUTE == 0)
                   DevParam.FilterParams[CurrentCH].MUTE = 1;
               else
                   DevParam.FilterParams[CurrentCH].MUTE = 0;
               break;
         }
         break;
      default:
         //SendString("No Key",2);
         break;
      }

      //Create Screen String
         switch (CurrentFilterSetting)
         {
            case 0:   //LPF
               sprintf(Line1, "CH%i-%i LPF",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2);
               FilterNumToStr(DevParam.FilterParams[CurrentCH].LPF,Line2);
               break;
            case 1:   //HPF
               sprintf(Line1, "CH%i-%i HPF",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2);
               FilterNumToStr(DevParam.FilterParams[CurrentCH].HPF,Line2);
               break;
            case 2:   //OFFSET
               sprintf(Line1, "CH%i-%i OFFSET",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2);
               sprintf(Line2, "%ddB", DevParam.FilterParams[CurrentCH].OFFSET);
               break;
            case 3:   //MUTE
               sprintf(Line1, "CH%i-%i MUTE",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2);
               MuteToStr(DevParam.FilterParams[CurrentCH].MUTE, Line2);
               break;
         }
      //Send LCD
      if (FilterChanged == 1)
      {
         strcat(Line1, "  *");
      }
      SendString(Line1,1);
      SendString(Line2,2);
}

void EQTypeToStr(int32_t EQTypeNum, char * RetStr)
{
   if ((EQTypeNum < 0) || (EQTypeNum > 3))
      strcpy(RetStr, "--");
   else
      strcpy(RetStr, EQTypeStr[EQTypeNum]);
}

void EQFreqNumToStr(int32_t EQFreqNum, char * EQFreqRetStr)
{
   if ((EQFreqNum < 0) || (EQFreqNum > 31))
      strcpy(EQFreqRetStr, "--");
   else
      strcpy(EQFreqRetStr, EQFreqStr[EQFreqNum]);
}

void EQQNumToStr(int32_t EQQNum, char * EQQRetStr)
{
   if ((EQQNum < 0) || (EQQNum > 31))
      strcpy(EQQRetStr, "--");
   else
      strcpy(EQQRetStr, EQQStr[EQQNum]);
}

//EQ Menu Screen
void EQMenu(int32_t NewKeyData)
{
   //Control EQ5,6,7
   char Line1[20];
   char Line2[20];
  //double EQQ;
   int32_t CurrentCH; //0,1,2,3 = CH12,34,56,78
   int32_t CurrentEQ; //0,1,2 = EQ5,6,7
   int32_t CurrentSetting; //0,1,2,3 = EQType, EQFreq, EQQ, EQGain

   CurrentCH = (int32_t)(currentEQMenu / 12);
   CurrentEQ = (int32_t)((currentEQMenu - CurrentCH * 12) / 4);
   CurrentSetting = currentEQMenu - CurrentCH * 12 - CurrentEQ * 4;

      switch (NewKeyData)
      {
      case 1:  //Enter
         //save changes
         EQChanged = 0;
         DevParam.currentwin = 4;
         applyEQ(SPDIFFreqs[currentfs - 4]);
           writeDevParam(0);
         return;
         break;
      case 2: //Cancel
         //discard changes
         EQChanged = 0;
         readDevParam();
         DevParam.currentwin = 2;
           writeDevParam(0);
         return;
         break;
      case 3:    //Up
         if (currentEQMenu > 0)
            currentEQMenu -= 1;
         else
     {
      if (currentEQMenu == 0)
      {
            DevParam.currentwin = 2;
        return;
      }
     }  
         break;
      case 4:    //Down
         if (currentEQMenu < 47)
            currentEQMenu += 1;
         else
      currentEQMenu = 47;
         break;
      case 5:    //Left
         EQChanged = 1;
         switch (CurrentSetting)
         {
            case 0:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQType > 0 )  //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQType -= 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQType = 0;
               break;
            case 1:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq > 0 )   //0 - 31
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq -= 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq = 0;
               break;
            case 2:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQQ > 0 )     //0 - 31
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQQ -= 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQQ = 0;
               break;
            case 3:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQGain > -15 )   //-15,... 0,... 15
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQGain -= 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQGain = -15;
               break;
            default:
               break;
         }
         break;
      case 6:   //Right
         EQChanged = 1;
         switch (CurrentSetting)
         {
            case 0:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQType < 3 )  //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQType += 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQType = 3;
               break;
            case 1:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq < 31 )   //0 - 31
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq += 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq = 31;
               break;
            case 2:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQQ < 31 )     //0 - 31
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQQ += 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQQ = 31;
               break;
            case 3:
               if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQGain < 15 )   //-15,... 0,... 15
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQGain += 1;
               else
                  DevParam.EQParams[CurrentCH][CurrentEQ].EQGain = 15;
               break;
            default:
               break;
         }
         break;
      default:
         //SendString("No Key",2);
         break;
      }

      //Create Screen String
      switch (CurrentSetting)
      {
         case 0:   //EQType
            sprintf(Line1, "CH%d-%d EQ%d Type",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2,(int8_t)CurrentEQ+5 );
            EQTypeToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQType ,Line2);
            break;
         case 1:   //EQFreq
            sprintf(Line1, "CH%d-%d EQ%d Freq",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2,(int8_t)CurrentEQ+5);
            EQFreqNumToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq, Line2);
            break;
         case 2:   //EQQ
            sprintf(Line1, "CH%d-%d EQ%d Q",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2,(int8_t)CurrentEQ+5);
            EQQNumToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQQ, Line2);
            break;
         case 3:
            sprintf(Line1, "CH%d-%d EQ%d Gain",(int8_t)CurrentCH*2+1,(int8_t)CurrentCH*2+2,(int8_t)CurrentEQ+5);
            sprintf(Line2, "%ddB", DevParam.EQParams[CurrentCH][CurrentEQ].EQGain);
            break;
         default:
            break;
      }
      //Send LCD
      if (EQChanged == 1)
      {
         strcat(Line1, " *");
      }

      SendString(Line1,1);
      SendString(Line2,2);
}

// Main Screen to show Volume, Channel
void mainScreen(int32_t NewKeyData)
{
   char Line1[20];
   char Line2[20];
   int32_t Volume;

   Volume = (int32_t)(((DevParam.currentvol - 0x48) * -1) / 4);

      switch (NewKeyData)
      {
      case 1:  //Enter
         //SendString("Enter Pressed",2);
         DevParam.currentwin = 1;
           writeDevParam(0);
         return;
         break;
      case 2:
         //SendString("Cancel Pressed",2);
         break;
      case 3:    //Up
         if (Volume < 16)
         {
            Volume += 1;
            DevParam.currentvol = ((Volume * 4) * -1) + 0x48;
            writeDevParam(1);
            I2C_SetVolume();
         }
         else
            Volume = 16;
         break;
      case 4:    //Down
         if (Volume > -100)
         {
            Volume -= 1;
            DevParam.currentvol = ((Volume * 4) * -1) + 0x48;
            writeDevParam(1);
            I2C_SetVolume();
         }
         else
            Volume = -100;
         break;
      case 5:    //Left
         if (DevParam.currentch > 0)
         {
            DevParam.currentch -= 1;
            writeDevParam(2);
            I2C_SetCH();
         }
         else
            DevParam.currentch = 0;
         break;
      case 6:   //Right
         if (DevParam.currentch < 7)
         {
            DevParam.currentch += 1;
            writeDevParam(2);
            I2C_SetCH();
         }
         else
            DevParam.currentch = 7;
         break;
      default:
         break;
      }

      //Create Screen String
      sprintf(Line1, "KDA-TAS4i     D%d", DevParam.currentch);
      if ((currentfs < 4) || (currentfs > 7))
         sprintf(Line2, "%3ddB Fs=--kHz", (int16_t)Volume);
      else
         sprintf(Line2, "%3ddB Fs=%s", (int16_t)Volume, currentfsstr[currentfs - 4]);

      //Send LCD
      SendString(Line1,1);
      SendString(Line2,2);

}

// Get Key / pass screen
void ProcessKey(int32_t NewKeyData)
{
   switch (DevParam.currentwin)
   {
      case 0:
         mainScreen(NewKeyData);
         break;
      case 1:
         Menu01(NewKeyData);
         break;
      case 2:
         Menu02(NewKeyData);
         break;
      case 3:
         FilterMenu(NewKeyData);
         break;
      case 4:
         EQMenu(NewKeyData);
         break;
      default:
         mainScreen(NewKeyData);
         break;
   }
}

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  Wire.begin();
  
  lcd.setCursor(0,0);

  lcd.print("TEST");

   WriteData = 0x85;   //I2S
   I2CWrite(CS8416_ADDRESS, 0x05, &WriteData, 1);

   //Control3 = 10110000
   WriteData = 0xB0;   //1011 GPIO is TX passthrough
   I2CWrite(CS8416_ADDRESS, 0x03, &WriteData, 1);

   I2C_SetCH();

   //set volume
   I2C_SetVolume();
}


// Main Loop
void loop()
{
   

   msDelay(100);
   //set mute pattern
   MUTEMode = 0x00;       //Unmute all
   return_code = I2CWrite(TAS5508_ADDRESS, 0x0F,&MUTEMode,1);


    /*switch(KeyMode)
    {
    case 0:
      msDelay(50);
      break;
    case 1:
      msDelay(400);
      break;
    case 2:
      msDelay(200);
      break;
    default:
      msDelay(100);
      break;
    }*/
     
       {  //task for check fs
         newfs = I2C_GetFs();
         if (currentfs != newfs)
         {
            if ((newfs < 4) || (newfs > 7)) //non support
            {
                //mute all
            return_code = I2CWrite(TAS5508_ADDRESS, 0x0F,&MUTEMode,1);
            }
            else
            {
                applyfilter(SPDIFFreqs[newfs-4]);
                applyEQ(SPDIFFreqs[newfs-4]);
            }
            currentfs = newfs;
         }
     }
     //Task Key Process
     {
/*         NewKey = PollKey();
      switch(KeyMode)
      {
      case 0: //Initial Key State, None Key detected
        if (NewKey > 0)
        {
          KeyMode = 1;  //to state 1.
          if (NewKey != PrevKey)  { ProcessKey(NewKey); }
          PrevKey = NewKey;
        }
        else  { ProcessKey(0); }
        break;
      case 1: //Some key detected. wait 400 ms to another input.
        if (NewKey > 0)
        {
          if (NewKey != PrevKey)  { KeyMode = 1;  } //different key detected.
          else            { KeyMode = 2;  } //Same key detected.
              ProcessKey(NewKey);
          PrevKey = NewKey;
        }
        else  //no key pressed. return to state 0.
        {
          KeyMode = 0;
          PrevKey = NewKey;
          ProcessKey(0);
        }
        break;
      case 2: //If same key still pressed, run same routine per 100ms.
        if (NewKey > 0)
        {
          if (NewKey != PrevKey)  { KeyMode = 1;  } //different key detected.
          else          { KeyMode = 2;  } //repeat same key operation
              ProcessKey(NewKey);
          PrevKey = NewKey;
        }
        else
        {
          KeyMode = 0;
          PrevKey = NewKey;
          ProcessKey(0);
        }
        break;
      default:
        break;
      } //switch*/
       }  //Task
    } //While

 






[/code]

 

smart_pic
Offline
Зарегистрирован: 17.04.2016

Разобрался с TAS5504. TAS5508 аналогична по структуре и управлению. Есть некоторые особенности , плюс  8 выходов.

Сделал управление через ВЕБ интерфейс.

Делал сразу на 8 входных каналов , хотя плату сделал пока на 4 канала.

Не нашел как загрузить изображение

 

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

smart_pic пишет:

Разобрался с TAS5504. TAS5508 аналогична по структуре и управлению. Есть некоторые особенности , плюс  8 выходов.

Сделал управление через ВЕБ интерфейс.

Делал сразу на 8 входных каналов , хотя плату сделал пока на 4 канала.

Не нашел как загрузить изображение

 

А код посмотреть можно? У меня полнотью управляется 08-ая, но с дисплеем пока заморочки.

smart_pic
Offline
Зарегистрирован: 17.04.2016

Код написагн для PIC18

Вам врядли подойдет

 

kimmel.dima
Offline
Зарегистрирован: 20.02.2014

Допилил код для tas5508. В протеусе все работает.

#include <LiquidCrystal.h>
#include <Wire.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int ENTER = 14;
const int up = 15;
const int Down = 16;
const int Left = 17;
const int right = 18;

//I2C device address of  CS8416
#define CS8416_ADDRESS 0x20
//AD0 = 0
//AD1 = 0
//AD2 = 0
//BASE = 0010xxx

#define TAS5508_ADDRESS 0x36

// 1/3Oct Equalizer Frequencies
const uint16_t EQFreqs[32] = {0, 20, 25, 32, 40, 50, 63, 80,
                              100, 125, 160, 200, 250, 315, 400, 500,
                              630, 800, 1000, 1250, 1600, 2000, 2500, 3150,
                              4000, 5000, 6300, 8000, 10000, 12500, 16000, 20000
                             };

// Strings to show
const char EQFreqStr[32][8] = {"None", "20Hz", "25Hz", "32Hz",
                               "40Hz", "50Hz", "63Hz", "80Hz",
                               "100Hz", "125Hz", "160Hz", "200Hz",
                               "250Hz", "315Hz", "400Hz", "500Hz",
                               "630Hz", "800Hz", "1.0kHz", "1.25kHz",
                               "1.6kHz", "2.0kHz", "2.5kHz", "3.15kHz",
                               "4.0kHz", "5.0kHz", "6.3kHz", "8.0kHz",
                               "10kHz", "12.5kHz", "16kHz", "20kHz"
                              };

//string for Q each index (actual Q = Q^2/100)
const char EQQStr[32][8] = {"0.000", "0.010", "0.040", "0.090",
                            "0.160", "0.250", "0.360", "0.490",
                            "0.640", "0.810", "1.000", "1.210",
                            "1.440", "1.690", "1.960", "2.250",
                            "2.560", "2.890", "3.240", "3.610",
                            "4.000", "4.410", "4.840", "5.290",
                            "5.760", "6.250", "6.760", "7.290",
                            "7.840", "8.410", "9.000", "9.610"
                           };

const char EQTypeStr[4][12] = {"None", "LowShelf", "HighShelf", "Peaking"};

// Crossover Filter Point32_ts
const uint16_t FilterFreqs[32] =
{ 0, 50, 65, 80, 100, 120, 150, 180, 220, 260, 300, 350,
  400, 500, 650, 800, 1000, 1200, 1500, 1800, 2200, 2600, 3000,
  3500, 4000, 5000, 6500, 8000, 10000, 12000, 15000, 18000
};

const char FilterFreqStr[32][8] =
{ "None", "50Hz", "65Hz", "80Hz",
  "100Hz", "120Hz", "150Hz", "180Hz",
  "220Hz", "260Hz", "300Hz", "350Hz",
  "400Hz", "500Hz", "650Hz", "800Hz",
  "1kHz", "1.2kHz", "1.5kHz", "1.8kHz",
  "2.2kHz", "2.6kHz", "3.0kHz", "3.5kHz",
  "4.0kHz", "5.0kHz", "6.5kHz", "8.0kHz",
  "10kHz", "12kHz", "15kHz", "18kHz"
};

// CS8416 SPDIF Frequencies
const uint32_t SPDIFFreqs[4] = {44100, 48000, 88200, 96000};
const char currentfsstr[4][8] = {"44.1kHz", "48kHz", "88.2kHz", "96kHz"};

// Global Values
uint8_t currentfs;      //Fs (44.1/48/88.2/96) current state
uint8_t currentFilterMenu;  //Filter Menu Number
uint8_t FilterChanged;    //1: There were data change
int32_t newfs;
int32_t return_code;
uint8_t MUTEMode;
uint8_t currentEQMenu;  //EQ Menu Number
uint8_t EQChanged;    //1: there were data change

uint8_t KeyMode;  //0:none, 1: First Key, 2: Repeat Key
uint8_t PrevKey;  //remember previous key state
uint8_t NewKey;   //get new key entry
uint8_t WriteData;



// Parameters to store Flash
struct EQParam {
  uint8_t   EQType;   //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
  uint8_t   EQFreq;   //0 - 31
  uint8_t   EQQ;            //0 - 31
  int8_t   EQGain;   //-15,... 0,... 15
}; //4 bytes

struct FilterParam {
  uint8_t LPF;   // 0:No LPF
  uint8_t HPF;   //0:No HPF
  int8_t OFFSET; //0:mid
  uint8_t MUTE;  //0:normal, 1:mute
}; //4 bytes

struct Params {
  int16_t currentvol;
  int8_t currentch;
  int8_t currentwin;

  struct FilterParam FilterParams[4];   //CH12,34,56,78

  struct EQParam EQParams[4][3];   // CH12,34,56,78 - EQ5,6,7

} ;
struct Params DevParam; //4 + 16 + 48 = 68 bytes
struct Params DevParam_EEPROM __attribute__((section(".eeprom")));


//Utility Functions

void msDelay(uint16_t delay)
{
  while (delay--)
  {
    _delay_ms(1);
  }
}

//Read Flash
void readDevParam()
{
  eeprom_busy_wait();
  eeprom_read_block(&DevParam, &DevParam_EEPROM, sizeof(DevParam_EEPROM));

}

//Write Flash
void writeDevParam(int mode)
{
  eeprom_busy_wait();
  switch (mode)
  {
    case 0: //Write All
      eeprom_write_block(&DevParam, &DevParam_EEPROM, sizeof(DevParam_EEPROM));
      break;
    case 1: //Volume Only
      eeprom_write_word(&(DevParam_EEPROM.currentvol), DevParam.currentvol);
      break;
    case 2: //Channel Only
      eeprom_write_byte(&(DevParam_EEPROM.currentch), DevParam.currentch);
      break;
    default:
      eeprom_write_block(&DevParam, &DevParam_EEPROM, sizeof(DevParam_EEPROM));
      break;
  }
  eeprom_busy_wait();
}

//LCD Functions

//LCD Function, String 0 terminated SendStr, Line is Upper(1) Lower(2)
void SendString(char * SendStr, uint8_t Line)
{

  int StrLen;
  char Packet[32];
  int i;

  lcd.setCursor(0, 0);
  msDelay(1);
  if (Line == 2)

  {
    lcd.setCursor(0, 1);
  }
  msDelay(1);
  StrLen = strlen(SendStr);
  memset(Packet, 0, sizeof(Packet));
  strncpy(Packet, SendStr, 16);

  for (i = StrLen; i <= 18; i++)
  {
    Packet[i] = 32;

  }

  lcd.print(Packet);
  lcd.setCursor(0, 0);

}

//LCD Function
void ClearLCD()
{
  lcd.clear();
}

//LCD Function
uint8_t PollKey()
{

  if ( digitalRead(up) == HIGH)
    return 3;

  if ( digitalRead(Down) == HIGH)
    return 4;

  if ( digitalRead(Left) == HIGH)
    return 5;

  if ( digitalRead(right) == HIGH)
    return 6;

  if ( digitalRead(ENTER) == HIGH)
    return 1;

  return 1;   //ENTER
  return 2;   //cancel
  return 3;   //up
  return 4;   //Down
  return 5;   //Left
  return 6;   //right

  return 0;
}

//I2C Function
/* I2CWrite
  write data to slave.
  Sends START, slave address, index and then data, STOP
  Waits for slave to respond.
  PARAM1: uint8_t address - slave device address
  PARAM2: uint8_t index - subaddress of register/memory to write
  PARAM3: char * writestring - write data buffer
  PARAM4: uint8_t len  - length of data to write
  RETURN: 0 or negative error code (see code)
*/
const uint16_t I2C_TIMEOUT = 1000; // Used to check for errors in I2C communication

uint8_t I2CWrite(uint8_t address, uint8_t subaddress, uint8_t * writestring,  bool sendStop)
{
  uint8_t length;
  Wire.beginTransmission(address);
  Wire.write(subaddress);
  Wire.write(writestring, length);
  uint8_t rcode = Wire.endTransmission(sendStop); // Returns 0 on success
  return rcode;
}


/* I2CRead
  PARAM1: uint8_taddress - slave address
  PARAM2: uint8_t subaddress - subaddress in in EEPROM to read from
  PARAM3: char *retstring          - buffer for data
  PARAM4: uint8_t len   - size of data buffer

  RETURN: 0 or error code*/
uint8_t I2CRead(uint8_t address, uint8_t subaddress, uint8_t * retstring, uint8_t nbytes)
{
  uint32_t timeOutTimer;
  Wire.beginTransmission(address);
  Wire.write(subaddress);
  uint8_t rcode = Wire.endTransmission(false); // Don't release the bus
  if (rcode)
  {
    return rcode; // access failed
  }

  Wire.requestFrom(address, nbytes, (uint8_t)true);
  for (uint8_t cnt = 0; cnt < nbytes; cnt++)
  {
    if (Wire.available())
      retstring[cnt] = Wire.read();
    else {
      timeOutTimer = micros();
      while (((micros() - timeOutTimer) < I2C_TIMEOUT) && !Wire.available());
      if (Wire.available())
        retstring[cnt] = Wire.read();
      else {

        return 5; // This error value is not already taken by endTransmission
      }
    }
  }
  return 0; // Success
}

//I2C Functions
uint8_t I2C_GetFs()
{
  //returns data rate.
  //  0 : Error
  //  1 : invalid
  //  2 : 32 kHz
  //  3 : 38 kHz
  //  4 : 44.1kHz
  //  5 : 48 kHz
  //  6 : 88.2 kHz
  //  7 : 96 kHz
  //  8 : 176.4kHz
  //  9 : 192 kHz
  char Clk_Mode;
  uint8_t return_code;
  return_code = I2CRead(TAS5508_ADDRESS, 0x00, 1, 1);
  if (return_code != 0) {
    return 0;
  }

  return ( ((1 & 0xE0) >> 5) + 2  );

}

// TAS5518 and PSVC Volume control
// PSVC is 4 bit programmable, 16dB
void I2C_SetVolume()
{
  char test_string[4];
  uint8_t return_code;
  int16_t TAS5508Volume;
  uint8_t PortAVolume;
  if (DevParam.currentvol < 0x48)   //+x.xx dB
  {
    TAS5508Volume = DevParam.currentvol;
    PortAVolume = 0x0F;
  }
  else
  {
    if (DevParam.currentvol < 0x89)  //0 - -15dB
    {
      TAS5508Volume = 0x48;
      PortAVolume = 16 - (uint8_t)(((DevParam.currentvol - 0x48)) / 4);
    }
    else
    {
      TAS5508Volume = DevParam.currentvol - 0x48;
      PortAVolume = 0;
    }
  }

  //set volume
  test_string[0] = 0;
  test_string[1] = 0;
  test_string[2] = 0;
  test_string[3] = TAS5508Volume & 0xff;
  return_code = I2CWrite(TAS5508_ADDRESS, 0xD9, test_string, 4);
  //WrPortI(PADR, &PADRShadow, PortAVolume);

  //Output Volume to Control
  PORTB = (PortAVolume) << 4;
}

// CS8416 Rx Selector
void I2C_SetCH()
{

  WriteData = 0x80 + DevParam.currentch * 8 + DevParam.currentch;
  I2CWrite(CS8416_ADDRESS, 0x04, WriteData, 1);
}

//Make biquad Filter parameter
void MakeEQ(int32_t Fs, int32_t f0, int32_t mode, double Q, int32_t gain,  uint8_t * EQ)
{
  double w0;
  double cosw0;
  double sinw0;
  double alpha;
  double A;
  double sqrtA;
  double twosqrtAalpha;
  double b0;
  double b1;
  double b2;
  double a0;
  double a1;
  double a2;
  int32_t Qb0;
  int32_t Qb1;
  int32_t Qb2;
  int32_t Qa1;
  int32_t Qa2;

  b0 = 0.0;
  b1 = 1.0;
  b2 = 0.0;
  a0 = 1.0;
  a1 = 0.0;
  a2 = 0.0;

  w0 = 2.000 * 3.141516 * f0 / Fs;
  cosw0 = cos(w0);
  sinw0 = sin(w0);

  alpha = sinw0 / (2.00 * Q);
  A =  pow( ((double)(gain)) / 40.0 , 10);
  sqrtA = sqrt(A);
  twosqrtAalpha = 2 * sqrtA * alpha;

  if ( mode == 0) //HPF
  {
    a0 = 1.0 + alpha;
    b1 = -1.0 * (1.0 + cosw0) / a0 ;
    b0 = -1.0 * b1 / 2.00;
    b2 = b0;
    a1 = -2.0 * cosw0 / a0 ;
    a2 = (1.0 - alpha) / a0;
  }
  if ( mode == 1) //LPF
  {
    a0 = 1.0 + alpha;
    b1 = (1.0 - cosw0) / a0 ;
    b0 = b1 / 2.00;
    b2 = b0;
    a1 = -2.0 * cosw0 / a0 ;
    a2 = (1.0 - alpha) / a0;
  }
  if ( mode == 2) //LowShelf
  {
    a0 = (A + 1) + (A - 1) * cosw0 + twosqrtAalpha;
    b0 = A * ((A + 1) - (A - 1) * cosw0 + twosqrtAalpha);
    b1 = 2 * A * ((A - 1) - (A + 1) * cosw0) ;
    b2 = A * ((A + 1) - (A - 1) * cosw0 - twosqrtAalpha);
    a1 = -2.0 * ((A - 1) + (A + 1) * cosw0) ;
    a2 = (A + 1) + (A - 1) * cosw0 - twosqrtAalpha;
  }
  if ( mode == 3) //HighShelf
  {
    a0 = (A + 1) - (A - 1) * cosw0 + twosqrtAalpha;
    b0 = A * ((A + 1) + (A - 1) * cosw0 + twosqrtAalpha);
    b1 = -2 * A * ((A - 1) + (A + 1) * cosw0) ;
    b2 = A * ((A + 1) + (A - 1) * cosw0 - twosqrtAalpha);
    a1 = 2.0 * ((A - 1) - (A + 1) * cosw0) ;
    a2 = (A + 1) - (A - 1) * cosw0 - twosqrtAalpha;
  }
  if ( mode == 4) //Peaking
  {
    a0 = 1.0 + alpha / A;
    b0 = 1.0 + alpha * A;
    b1 = -2.0 * cosw0 ;
    b2 = 1.0 - alpha * A;
    a1 = -2.0 * cosw0 ;
    a2 = 1.0 - alpha / A;
  }
  if ( mode > 1)
  {
    b0 = b0 / a0;
    b1 = b1 / a0;
    b2 = b2 / a0;
    a1 = a1 / a0;
    a2 = a2 / a0;
  }
  //quantize
  Qb0 = (int32_t)(b0 *  8388608L);
  Qb1 = (int32_t)(b1 *  8388608L);
  Qb2 = (int32_t)(b2 *  8388608L);
  Qa1 = (int32_t)(a1 * -8388608L);
  Qa2 = (int32_t)(a2 * -8388608L);

  //Modify sign bit
  if (Qb0 < 0) Qb0 = Qb0 + 268435456L;
  if (Qb1 < 0) Qb1 = Qb1 + 268435456L;
  if (Qb2 < 0) Qb2 = Qb2 + 268435456L;
  if (Qa1 < 0) Qa1 = Qa1 + 268435456L;
  if (Qa2 < 0) Qa2 = Qa2 + 268435456L;

  //get each byte
  *(EQ   ) = (uint8_t)((Qb0 >> 24) & 0xFF);
  *(EQ + 1 ) = (uint8_t)((Qb0 >> 16) & 0xFF);
  *(EQ + 2 ) = (uint8_t)((Qb0 >> 8)  & 0xFF);
  *(EQ + 3 ) = (uint8_t)( Qb0      & 0xFF);
  *(EQ + 4 ) = (uint8_t)((Qb1 >> 24) & 0xFF);
  *(EQ + 5 ) = (uint8_t)((Qb1 >> 16) & 0xFF);
  *(EQ + 6 ) = (uint8_t)((Qb1 >> 8)  & 0xFF);
  *(EQ + 7 ) = (uint8_t)( Qb1      & 0xFF);
  *(EQ + 8 ) = (uint8_t)((Qb2 >> 24) & 0xFF);
  *(EQ + 9 ) = (uint8_t)((Qb2 >> 16) & 0xFF);
  *(EQ + 10) = (uint8_t)((Qb2 >> 8)  & 0xFF);
  *(EQ + 11) = (uint8_t)( Qb2      & 0xFF);
  *(EQ + 12) = (uint8_t)((Qa1 >> 24) & 0xFF);
  *(EQ + 13) = (uint8_t)((Qa1 >> 16) & 0xFF);
  *(EQ + 14) = (uint8_t)((Qa1 >> 8)  & 0xFF);
  *(EQ + 15) = (uint8_t)( Qa1      & 0xFF);
  *(EQ + 16) = (uint8_t)((Qa2 >> 24) & 0xFF);
  *(EQ + 17) = (uint8_t)((Qa2 >> 16) & 0xFF);
  *(EQ + 18) = (uint8_t)((Qa2 >> 8)  & 0xFF);
  *(EQ + 19) = (uint8_t)( Qa2      & 0xFF);
}

void ClearEQ(uint8_t * EQ)
{
  //get each byte
  memset(EQ, 0, 20);
  *(EQ + 1 ) = 0x80;
}

void setup() {
  // set up the LCD's number of columns and rows:
  //lcd_init(LCD_DISP_ON);
  //lcd_home();
  Wire.begin();
  lcd.begin(16, 2);
  pinMode(ENTER, INPUT);
  pinMode(right, INPUT);
  pinMode(up, INPUT);
  pinMode(Down, INPUT);
  pinMode(Left, INPUT);
  //pinMode(ENTER, HIGH);
  //pinMode(right, HIGH);
  //pinMode(up, HIGH);
  //pinMode(Down, HIGH);
  //pinMode(Left, HIGH);

  currentfs = 0;

  //Initialize key state
  KeyMode = 0;
  PrevKey = 0;
  NewKey = 0;

  readDevParam();
  //Once for Initial.
  //memset(&DevParam, 0, sizeof(DevParam));

  ClearLCD();

  //memset(LCDLine, 0, sizeof(LCDLine));
  //sprintf(LCDLine, "KOON DIGITAL");
  // SendString(LCDLine,1);
  //sprintf(LCDLine, "    AUDIO DIY");
  //SendString(LCDLine,2);
  msDelay(1500);
  WriteData = 0x85;   //I2S
  I2CWrite(CS8416_ADDRESS, 0x05, &WriteData, 1);

  //Control3 = 10110000
  WriteData = 0xB0;   //1011 GPIO is TX passthrough
  I2CWrite(CS8416_ADDRESS, 0x03, &WriteData, 1);

  I2C_SetCH();

  //set volume
  I2C_SetVolume();
  ClearLCD();
}


// convert Q value to string
double EQQNumToValue(int32_t EQQ)
{
  double retVal;
  if ((EQQ < 0) || (EQQ > 31))
  {
    retVal = 0;
  }
  else
  {
    retVal = (EQQ * EQQ) / 100.00 ;
  }
  return retVal;
}

// convert EQ frequency value to string
int32_t FreqFromEQSetting(int32_t EQSetting)
{
  if ((EQSetting < 0) || (EQSetting > 31))
    return 0;

  return EQFreqs[EQSetting];
}

// convert Filter frequency value to string
int32_t FreqFromFilterSetting(int32_t FilterSetting)
{
  if ((FilterSetting < 0) || (FilterSetting > 31))
    return 0;

  return FilterFreqs[FilterSetting];
}

// Calculate Equalizers and apply
void applyEQ(int32_t FS)
{
  uint8_t EQ[20];
  int32_t return_code;
  int32_t Freq;
  double Q;

  int32_t i;
  int32_t j;

  //Loop for CH12,34,56,78
  for (j = 0; j <= 3; j++)
  {
    //Loop for EQ5,6,7 in each CH
    for (i = 0; i <= 2; i++)
    {
      Freq = FreqFromEQSetting(DevParam.EQParams[j][i].EQFreq);
      if ((Freq > 0) && (DevParam.EQParams[j][i].EQType > 0))
      {
        Q = EQQNumToValue(DevParam.EQParams[j][i].EQQ);
        MakeEQ(FS, Freq, DevParam.EQParams[j][i].EQType + 1, Q ,
               DevParam.EQParams[j][i].EQGain, EQ);
      }
      else
      {
        ClearEQ(EQ);
      }
      return_code = I2CWrite(TAS5508_ADDRESS, 0x55 + i + j * 7 * 2, EQ, 20);
      return_code = I2CWrite(TAS5508_ADDRESS, 0x5C + i + j * 7 * 2, EQ, 20);
    }
  }
}

// Calculate Filter and apply
void applyfilter(int32_t FS)
{
  uint8_t EQ[20];
  int32_t return_code;
  int32_t Freq;
  uint8_t Param[4];
  uint8_t MutePattern;
  int32_t i;

  for (i = 0; i <= 3; i++)
  {
    //CHxx EQ1,2 (LPF)
    Freq = FreqFromFilterSetting(DevParam.FilterParams[i].LPF);
    if (Freq > 0)
    {
      MakeEQ(FS, Freq, 1, 0.71, 0, EQ);     //Q=0.71 LPF
    }
    else
    {
      ClearEQ(EQ);
    }
    return_code = I2CWrite(TAS5508_ADDRESS, 0x51 + i * 14, EQ, 20);
    return_code = I2CWrite(TAS5508_ADDRESS, 0x52 + i * 14, EQ, 20);
    return_code = I2CWrite(TAS5508_ADDRESS, 0x58 + i * 14, EQ, 20);
    return_code = I2CWrite(TAS5508_ADDRESS, 0x59 + i * 14, EQ, 20);

    //CHxx EQ3,4 (HPF)
    Freq = FreqFromFilterSetting(DevParam.FilterParams[i].HPF);
    if (Freq > 0)
    {
      MakeEQ(FS, Freq, 0,  0.71, 0, EQ);     //Q=0.71, HPF
    }
    else
    {
      ClearEQ(EQ);
    }
    return_code = I2CWrite(TAS5508_ADDRESS, 0x53 + i * 14, EQ, 20);
    return_code = I2CWrite(TAS5508_ADDRESS, 0x54 + i * 14, EQ, 20);
    return_code = I2CWrite(TAS5508_ADDRESS, 0x5A + i * 14, EQ, 20);
    return_code = I2CWrite(TAS5508_ADDRESS, 0x5B + i * 14, EQ, 20);
  }

  Param[0] = 0;
  Param[1] = 0;
  Param[2] = 0;

  for (i = 0; i <= 3; i++)
  {
    //CH Offset
    Param[3] = (uint8_t)(0x48 - DevParam.FilterParams[i].OFFSET * 4);
    return_code = I2CWrite(TAS5508_ADDRESS, 0xD1 + i * 2, Param, 4);
    return_code = I2CWrite(TAS5508_ADDRESS, 0xD2 + i * 2, Param, 4);
  }

  //CH Mute
  MutePattern = (uint8_t)
                (DevParam.FilterParams[0].MUTE * 0x03 +
                 DevParam.FilterParams[1].MUTE * 0x0C +
                 DevParam.FilterParams[2].MUTE * 0x30 +
                 DevParam.FilterParams[3].MUTE * 0xC0);
  return_code = I2CWrite(TAS5508_ADDRESS, 0x0F, &MutePattern, 1);
}


//Filter setting entry
void Menu01(int32_t NewKeyData)
{
  char Line1[20];
  char Line2[20];

  switch (NewKeyData)
  {
    case 1:  //Enter
    case 4:    //Down
      currentFilterMenu = 0;
      FilterChanged = 0;
      DevParam.currentwin = 3;
      return;
      break;
    case 2:  //Cancel
    case 3:    //Up
      DevParam.currentwin = 0;
      return;
      break;
    case 5:    //Left
    case 6:   //Right
      DevParam.currentwin = 2;
      return;
      break;
    default:
      break;
  }

  //Create Screen String
  sprintf(Line1, "KDA-TAS4i");
  sprintf(Line2, "Filter Menu ?");
  //Send LCD
  SendString(Line1, 1);
  SendString(Line2, 2);
}

//EQ Setting Entry
void Menu02(int32_t NewKeyData)
{
  char Line1[20];
  char Line2[20];

  switch (NewKeyData)
  {
    case 1:  //Enter
    case 4:    //Down
      currentEQMenu = 0;
      EQChanged = 0;
      DevParam.currentwin = 4;
      return;
      break;
    case 2:  //cancel
    case 3:    //Up
      DevParam.currentwin = 0;
      return;
      break;
    case 5:    //Left
    case 6:   //Right
      DevParam.currentwin = 1;
      return;
      break;
    default:
      break;
  }

  //Create Screen String
  sprintf(Line1, "KDA-TAS4i");
  sprintf(Line2, "EQ Menu ?");
  //Send LCD
  SendString(Line1, 1);
  SendString(Line2, 2);
}

// Convert Filter value to string
void FilterNumToStr(int32_t FilterNum, char * FilterStr)
{

  if ((FilterNum < 0) || (FilterNum > 31))
    strcpy(FilterStr, "--");
  else
    strcpy(FilterStr, FilterFreqStr[FilterNum]);

}

void MuteToStr(int32_t MuteValue, char * MuteStr)
{
  if (MuteValue == 0)
  {
    strcpy(MuteStr, "In Use");
  }
  else
  {
    strcpy(MuteStr, "Mute");
  }
}

//Filter Menu Screen
void FilterMenu(int32_t NewKeyData)
{
  //Control EQ0,1(reserved for LPF) ,2,3 (for HPF)
  char Line1[20];
  char Line2[20];

  int32_t CurrentCH;
  int32_t CurrentFilterSetting;
  CurrentCH = (int32_t)(currentFilterMenu / 4);
  CurrentFilterSetting = currentFilterMenu - CurrentCH * 4;

  switch (NewKeyData)
  {
    case 1:  //Enter
      //save changes
      FilterChanged = 0;
      DevParam.currentwin = 3;
      applyfilter(SPDIFFreqs[currentfs - 4]);
      writeDevParam(0);
      return;
      break;
    case 2:   //Cancel
      //discard changes
      FilterChanged = 0;
      readDevParam();
      DevParam.currentwin = 1;
      writeDevParam(0);
      return;
      break;
    case 3:    //Up
      if (currentFilterMenu > 0)
        currentFilterMenu -= 1;
      else
      {
        if (currentFilterMenu == 0)
        {
          DevParam.currentwin = 1;
          return;
        }
      }
      break;
    case 4:    //Down
      if (currentFilterMenu < 15)
        currentFilterMenu += 1;
      else
        currentFilterMenu = 15;
      break;
    case 5:    //Left
      FilterChanged = 1;
      switch (CurrentFilterSetting)
      {
        case 0:   //LPF
          if (DevParam.FilterParams[CurrentCH].LPF > 0)
            DevParam.FilterParams[CurrentCH].LPF -= 1;
          else
            DevParam.FilterParams[CurrentCH].LPF = 0;
          break;
        case 1:   //HPF
          if (DevParam.FilterParams[CurrentCH].HPF > 0)
            DevParam.FilterParams[CurrentCH].HPF -= 1;
          else
            DevParam.FilterParams[CurrentCH].HPF = 0;
          break;
        case 2:   //OFFSET
          if (DevParam.FilterParams[CurrentCH].OFFSET > -15)
            DevParam.FilterParams[CurrentCH].OFFSET -= 1;
          else
            DevParam.FilterParams[CurrentCH].OFFSET = -15;
          break;
        case 3:   //MUTE
          if (DevParam.FilterParams[CurrentCH].MUTE == 1)
            DevParam.FilterParams[CurrentCH].MUTE = 0;
          else
            DevParam.FilterParams[CurrentCH].MUTE = 1;
          break;
      }
      break;
    case 6:   //Right
      FilterChanged = 1;
      switch (CurrentFilterSetting)
      {
        case 0:   //LPF
          if (DevParam.FilterParams[CurrentCH].LPF < 31)
            DevParam.FilterParams[CurrentCH].LPF += 1;
          else
            DevParam.FilterParams[CurrentCH].LPF = 31;
          break;
        case 1:   //HPF
          if (DevParam.FilterParams[CurrentCH].HPF < 31)
            DevParam.FilterParams[CurrentCH].HPF += 1;
          else
            DevParam.FilterParams[CurrentCH].HPF = 0;
          break;
        case 2:   //OFFSET
          if (DevParam.FilterParams[CurrentCH].OFFSET < 15)
            DevParam.FilterParams[CurrentCH].OFFSET += 1;
          else
            DevParam.FilterParams[CurrentCH].OFFSET = 15;
          break;
        case 3:   //MUTE
          if (DevParam.FilterParams[CurrentCH].MUTE == 0)
            DevParam.FilterParams[CurrentCH].MUTE = 1;
          else
            DevParam.FilterParams[CurrentCH].MUTE = 0;
          break;
      }
      break;
    default:
      //SendString("No Key",2);
      break;
  }

  //Create Screen String
  switch (CurrentFilterSetting)
  {
    case 0:   //LPF
      sprintf(Line1, "CH%i-%i LPF", (int8_t)CurrentCH * 2 + 1, (int8_t)CurrentCH * 2 + 2);
      FilterNumToStr(DevParam.FilterParams[CurrentCH].LPF, Line2);
      break;
    case 1:   //HPF
      sprintf(Line1, "CH%i-%i HPF", (int8_t)CurrentCH * 2 + 1, (int8_t)CurrentCH * 2 + 2);
      FilterNumToStr(DevParam.FilterParams[CurrentCH].HPF, Line2);
      break;
    case 2:   //OFFSET
      sprintf(Line1, "CH%i-%i OFFSET", (int8_t)CurrentCH * 2 + 1, (int8_t)CurrentCH * 2 + 2);
      sprintf(Line2, "%ddB", DevParam.FilterParams[CurrentCH].OFFSET);
      break;
    case 3:   //MUTE
      sprintf(Line1, "CH%i-%i MUTE", (int8_t)CurrentCH * 2 + 1, (int8_t)CurrentCH * 2 + 2);
      MuteToStr(DevParam.FilterParams[CurrentCH].MUTE, Line2);
      break;
  }
  //Send LCD
  if (FilterChanged == 1)
  {
    strcat(Line1, "  *");
  }
  SendString(Line1, 1);
  SendString(Line2, 2);
}

void EQTypeToStr(int32_t EQTypeNum, char * RetStr)
{
  if ((EQTypeNum < 0) || (EQTypeNum > 3))
    strcpy(RetStr, "--");
  else
    strcpy(RetStr, EQTypeStr[EQTypeNum]);
}

void EQFreqNumToStr(int32_t EQFreqNum, char * EQFreqRetStr)
{
  if ((EQFreqNum < 0) || (EQFreqNum > 31))
    strcpy(EQFreqRetStr, "--");
  else
    strcpy(EQFreqRetStr, EQFreqStr[EQFreqNum]);
}

void EQQNumToStr(int32_t EQQNum, char * EQQRetStr)
{
  if ((EQQNum < 0) || (EQQNum > 31))
    strcpy(EQQRetStr, "--");
  else
    strcpy(EQQRetStr, EQQStr[EQQNum]);
}

//EQ Menu Screen
void EQMenu(int32_t NewKeyData)
{
  //Control EQ5,6,7
  char Line1[20];
  char Line2[20];
  //double EQQ;
  int32_t CurrentCH; //0,1,2,3 = CH12,34,56,78
  int32_t CurrentEQ; //0,1,2 = EQ5,6,7
  int32_t CurrentSetting; //0,1,2,3 = EQType, EQFreq, EQQ, EQGain

  CurrentCH = (int32_t)(currentEQMenu / 12);
  CurrentEQ = (int32_t)((currentEQMenu - CurrentCH * 12) / 4);
  CurrentSetting = currentEQMenu - CurrentCH * 12 - CurrentEQ * 4;

  switch (NewKeyData)
  {
    case 1:  //Enter
      //save changes
      EQChanged = 0;
      DevParam.currentwin = 4;
      applyEQ(SPDIFFreqs[currentfs - 4]);
      writeDevParam(0);
      return;
      break;
    case 2: //Cancel
      //discard changes
      EQChanged = 0;
      readDevParam();
      DevParam.currentwin = 2;
      writeDevParam(0);
      return;
      break;
    case 3:    //Up
      if (currentEQMenu > 0)
        currentEQMenu -= 1;
      else
      {
        if (currentEQMenu == 0)
        {
          DevParam.currentwin = 2;
          return;
        }
      }
      break;
    case 4:    //Down
      if (currentEQMenu < 47)
        currentEQMenu += 1;
      else
        currentEQMenu = 47;
      break;
    case 5:    //Left
      EQChanged = 1;
      switch (CurrentSetting)
      {
        case 0:
          if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQType > 0 )  //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
            DevParam.EQParams[CurrentCH][CurrentEQ].EQType -= 1;
          else
            DevParam.EQParams[CurrentCH][CurrentEQ].EQType = 0;
          break;
        case 1:
          if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq > 0 )   //0 - 31
            DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq -= 1;
          else
            DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq = 0;
          break;
        case 2:
          if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQQ > 0 )     //0 - 31
            DevParam.EQParams[CurrentCH][CurrentEQ].EQQ -= 1;
          else
            DevParam.EQParams[CurrentCH][CurrentEQ].EQQ = 0;
          break;
        case 3:
          if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQGain > -15 )   //-15,... 0,... 15
            DevParam.EQParams[CurrentCH][CurrentEQ].EQGain -= 1;
          else
            DevParam.EQParams[CurrentCH][CurrentEQ].EQGain = -15;
          break;
        default:
          break;
      }
      break;
    case 6:   //Right
      EQChanged = 1;
      switch (CurrentSetting)
      {
        case 0:
          if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQType < 3 )  //0:None, 1:LowShelf, 2:HighShelf, 3:Peaking
            DevParam.EQParams[CurrentCH][CurrentEQ].EQType += 1;
          else
            DevParam.EQParams[CurrentCH][CurrentEQ].EQType = 3;
          break;
        case 1:
          if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq < 31 )   //0 - 31
            DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq += 1;
          else
            DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq = 31;
          break;
        case 2:
          if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQQ < 31 )     //0 - 31
            DevParam.EQParams[CurrentCH][CurrentEQ].EQQ += 1;
          else
            DevParam.EQParams[CurrentCH][CurrentEQ].EQQ = 31;
          break;
        case 3:
          if ( DevParam.EQParams[CurrentCH][CurrentEQ].EQGain < 15 )   //-15,... 0,... 15
            DevParam.EQParams[CurrentCH][CurrentEQ].EQGain += 1;
          else
            DevParam.EQParams[CurrentCH][CurrentEQ].EQGain = 15;
          break;
        default:
          break;
      }
      break;
    default:
      //SendString("No Key",2);
      break;
  }

  //Create Screen String
  switch (CurrentSetting)
  {
    case 0:   //EQType
      sprintf(Line1, "CH%d-%d EQ%d Type", (int8_t)CurrentCH * 2 + 1, (int8_t)CurrentCH * 2 + 2, (int8_t)CurrentEQ + 5 );
      EQTypeToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQType , Line2);
      break;
    case 1:   //EQFreq
      sprintf(Line1, "CH%d-%d EQ%d Freq", (int8_t)CurrentCH * 2 + 1, (int8_t)CurrentCH * 2 + 2, (int8_t)CurrentEQ + 5);
      EQFreqNumToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQFreq, Line2);
      break;
    case 2:   //EQQ
      sprintf(Line1, "CH%d-%d EQ%d Q", (int8_t)CurrentCH * 2 + 1, (int8_t)CurrentCH * 2 + 2, (int8_t)CurrentEQ + 5);
      EQQNumToStr(DevParam.EQParams[CurrentCH][CurrentEQ].EQQ, Line2);
      break;
    case 3:
      sprintf(Line1, "CH%d-%d EQ%d Gain", (int8_t)CurrentCH * 2 + 1, (int8_t)CurrentCH * 2 + 2, (int8_t)CurrentEQ + 5);
      sprintf(Line2, "%ddB", DevParam.EQParams[CurrentCH][CurrentEQ].EQGain);
      break;
    default:
      break;
  }
  //Send LCD
  if (EQChanged == 1)
  {
    strcat(Line1, " *");
  }

  SendString(Line1, 1);
  SendString(Line2, 2);
}

// Main Screen to show Volume, Channel
void mainScreen(int32_t NewKeyData)
{
  char Line1[20];
  char Line2[20];
  int32_t Volume;

  Volume = (int32_t)(((DevParam.currentvol - 0x48) * -1) / 4);

  switch (NewKeyData)
  {
    case 1:  //Enter
      //SendString("Enter Pressed",2);
      DevParam.currentwin = 1;
      writeDevParam(0);
      return;
      break;
    case 2:
      //SendString("Cancel Pressed",2);
      break;
    case 3:    //Up
      if (Volume < 16)
      {
        Volume += 1;
        DevParam.currentvol = ((Volume * 4) * -1) + 0x48;
        writeDevParam(1);
        I2C_SetVolume();
      }
      else
        Volume = 16;
      break;
    case 4:    //Down
      if (Volume > -100)
      {
        Volume -= 1;
        DevParam.currentvol = ((Volume * 4) * -1) + 0x48;
        writeDevParam(1);
        I2C_SetVolume();
      }
      else
        Volume = -100;
      break;
    case 5:    //Left
      if (DevParam.currentch > 0)
      {
        DevParam.currentch -= 1;
        writeDevParam(2);
        I2C_SetCH();
      }
      else
        DevParam.currentch = 0;
      break;
    case 6:   //Right
      if (DevParam.currentch < 7)
      {
        DevParam.currentch += 1;
        writeDevParam(2);
        I2C_SetCH();
      }
      else
        DevParam.currentch = 7;
      break;
    default:
      break;
  }

  //Create Screen String
  sprintf(Line1, "KDA-TAS4i     D%d", DevParam.currentch);
  if ((currentfs < 4) || (currentfs > 7))
    sprintf(Line2, "%3ddB Fs=--kHz", (int16_t)Volume);
  else
    sprintf(Line2, "%3ddB Fs=%s", (int16_t)Volume, currentfsstr[currentfs - 4]);

  //Send LCD
  SendString(Line1, 1);
  SendString(Line2, 2);

}
void ProcessKey(int32_t NewKeyData)
{
  switch (DevParam.currentwin)
  {
    case 0:
      mainScreen(NewKeyData);
      break;
    case 1:
      Menu01(NewKeyData);
      break;
    case 2:
      Menu02(NewKeyData);
      break;
    case 3:
      FilterMenu(NewKeyData);
      break;
    case 4:
      EQMenu(NewKeyData);
      break;
    default:
      mainScreen(NewKeyData);
      break;
  }
}




// Main Loop
void loop()
{


  msDelay(100);
  //set mute pattern
  MUTEMode = 0x00;       //Unmute all
  return_code = I2CWrite(TAS5508_ADDRESS, 0x0F, &MUTEMode, 1);




  { //task for check fs
    newfs = I2C_GetFs();
    if (currentfs != newfs)
    {
      if ((newfs < 4) || (newfs > 7)) //non support
      {
        //mute all
        return_code = I2CWrite(TAS5508_ADDRESS, 0x0F, &MUTEMode, 1);
      }
      else
      {
        applyfilter(SPDIFFreqs[newfs - 4]);
        applyEQ(SPDIFFreqs[newfs - 4]);
      }
      currentfs = newfs;
    }
  }
  //Task Key Process
  {
    NewKey = PollKey();
    switch (KeyMode)
    {
      case 0: //Initial Key State, None Key detected
        if (NewKey > 0)
        {
          KeyMode = 1;  //to state 1.
          if (NewKey != PrevKey)  {
            ProcessKey(NewKey);
          }
          PrevKey = NewKey;
        }
        else  {
          ProcessKey(0);
        }
        break;
      case 1: //Some key detected. wait 400 ms to another input.
        if (NewKey > 0)
        {
          if (NewKey != PrevKey)  {
            KeyMode = 1;   //different key detected.
          }
          else            {
            KeyMode = 2;   //Same key detected.
          }
          ProcessKey(NewKey);
          PrevKey = NewKey;
        }
        else  //no key pressed. return to state 0.
        {
          KeyMode = 0;
          PrevKey = NewKey;
          ProcessKey(0);
        }
        break;
      case 2: //If same key still pressed, run same routine per 100ms.
        if (NewKey > 0)
        {
          if (NewKey != PrevKey)  {
            KeyMode = 1;   //different key detected.
          }
          else          {
            KeyMode = 2;   //repeat same key operation
          }
          ProcessKey(NewKey);
          PrevKey = NewKey;
        }
        else
        {
          KeyMode = 0;
          PrevKey = NewKey;
          ProcessKey(0);
        }
        break;
      default:
        break;
    } //switch
  }  //Task
} //While






 

ega.234
Offline
Зарегистрирован: 06.10.2017

Люди, скиньте кто-нибудь программу конфигурации пожалуйста, очень надо!!!! Весь интернет облазил и не нашел! Просто отдали плату усилителя от ресивера, там как раз TAS5508.