audiohobby.ru audiohobby.ru

Комментарии

0
caleb caleb Продам собранную плату ЦАП AH-D19-PRO на BD34352EKV 4 часа назад

Ух какой вкусный цап… И цена, по сути за детали с такой хорошей комплектацией. Купил бы, но у меня уже есть.

+1
zirkony zirkony Документация к ES9039Q2M 1 день назад

… или временно загрузить на пастебин, там можно указать срок хранение

Иначе вот такое получается, как на картинке

+4
Le81 Le81 Документация к ES9039Q2M 1 день назад

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

#include <EEPROM.h>

/* =========================

ПОДКЛЮЧЕНИЯ / АДРЕСА

========================= */

#define DAC_ADDR 0x49

#define LCD_ADDR 0x27

LiquidCrystal_I2C lcd(LCD_ADDR, 16, 2);

#define ENC_A 2

#define ENC_B 3

#define BTN 4

#define CHIP_EN_PIN 7 // HIGH=ON, LOW=RESET

/* =========================

РЕГИСТРЫ ES9039Q2M (DEC)

========================= */

#define REG_SYS 0x00

#define REG_IFACE_POL 0x03

#define REG_CLKCFG 0x04

#define REG_PLL_BW 0x05

#define REG_AUTO_INPUT 57

#define REG_SLOT_L 64

#define REG_SLOT_R 65

#define REG_VOL_L 74

#define REG_VOL_R 75

#define REG_FILTER 88

#define REG_PATH 90

#define REG_THD_C2_LSB 91

#define REG_THD_C3_LSB 107

#define REG_AM_ENABLE 123

#define REG_AM_TIME_L 124

#define REG_S1 0x1C

#define REG_S2 0x1D

#define REG_ID 225

/* =========================

ПРОТОТИПЫ

========================= */

bool wr(uint8_t r, uint8_t v);

bool wr16(uint8_t addrLSB, uint16_t val);

bool rd(uint8_t r, uint8_t &v);

bool pingDAC();

void chipOn();

void chipOff();

void chipReset(uint16_t ms=400);

bool lockStatus();

uint32_t fsFromS2();

void volWriteLR(uint8_t vL,uint8_t vR);

void setFilter(uint8_t f);

void writePathConfig();

void applySafe_VolBal();

void applySafe_Filter();

void applySafe_Path();

void applyAutoMute();

void applyTHD_C2();

void applyTHD_C3();

void queueApply(bool softR=false);

void runPending();

void showStatus();

void drawMenu();

void doAction(uint8_t idx);

void encISR();

void pollBtn();

void onChangeSafe(uint8_t code);

void onChangeDanger(uint8_t what);

/* =========================

СОСТОЯНИЕ / МЕНЮ

========================= */

uint8_t g_volBase=0; // 0..255 (0=0 dB)

int8_t g_balance=0; // -24..+24 (≈±12 dБ)

uint8_t g_dfilt=0; // 0..7

uint8_t g_path=0; // 0=ST,1=MonoL,2=MonoR,3=Swap

// bypass биты REG_PATH

bool g_bypIIR=false;

bool g_bypFIR4=false;

bool g_bypFIR2=false;

// интерфейс / клок

uint8_t g_pol=0; // 0..3

uint8_t g_pll=0x04; // 0x02..0x08 обычно

bool g_autoClk=true;

bool g_autoIn =true;

bool g_hardtrue; // «опасные» не писать

uint16_t g_settle=700; // мс после «опасных»

// AutoMute

bool g_amCh1=true;

bool g_amCh2=true;

bool g_amRampGND=true; // bit11

uint16_t g_amTime=0x00F; // [10:0]

// THD (signed 16-bit)

int16_t g_c2_L=0, g_c2_R=0;

int16_t g_c3_L=0, g_c3_R=0;

/* ===== Планировщик «опасных» ===== */

struct Pending { bool polarity=false, pll=false, autoclk=false, autoin=false, softReset=false; } pend;

/* ===== EEPROM / пресеты ===== */

#define CFG_VERSION 0x39 // меняй при правке структуры

struct Config {

uint8_t version;

uint8_t volBase; int8_t balance; uint8_t dfilt; uint8_t path;

bool bypIIR, bypFIR4, bypFIR2;

uint8_t pol, pll; bool autoClk, autoIn;

bool hardOnly; uint16_t settle;

bool amCh1, amCh2, amRamp; uint16_t amTime;

int16_t c2L, c2R, c3L, c3R;

uint8_t autosave;

uint16_t crc;

};

uint16_t crc16(const uint8_t* p, size_t n){

uint16_t c=0xFFFF;

for(size_t i=0;i<n;i++){ c ^= p[i]; for(uint8_t b=0;b<8;b++){ c = (c&1)?(c>>1)^0xA001:(c>>1); } }

return c;

}

#define EE_ADDR_LAST 0

#define EE_ADDR_PRE1 128

#define EE_ADDR_PRE2 256

#define EE_ADDR_PRE3 384

bool g_autosave=true;

uint8_t g_presetSel=1; // 1..3

/* ===== UI ===== */

volatile int16_t enc_delta=0;

bool btn_short=false, btn_lfalse, btn_dbl=false;

uint8_t menu_idx=0; bool edit=false;

const char* MENU[]={

// базовые

«Status»,«Volume»,«Balance»,«Filter»,«Path»,

// bypass

«Bypass IIR»,«Bypass FIR4»,«Bypass FIR2»,

// AutoMute

«AM Ch1»,«AM Ch2»,«AM RampGND»,«AM Time»,

// THD

«THD C2 L»,«THD C2 R»,«THD C3 L»,«THD C3 R»,

// интерфейс/PLL

«Polarity»,«DPLL BW»,«AutoClock»,«AutoInput»,

// пресеты

«Preset Load»,«Preset Save»,«Autosave»,

// прочее

«HardOnly»,«Reset»

};

const uint8_t MCNT = sizeof(MENU)/sizeof(MENU[0]);

/* =========================

I2C helpers

========================= */

bool wr(uint8_t r, uint8_t v){

Wire.beginTransmission(DAC_ADDR);

Wire.write®; Wire.write(v);

return (Wire.endTransmission()==0);

}

bool wr16(uint8_t addrLSB, uint16_t val){

return wr(addrLSB, (uint8_t)(val & 0xFF))

&& wr(addrLSB+1, (uint8_t)((val>>8)&0xFF));

}

bool rd(uint8_t r, uint8_t &v){

Wire.beginTransmission(DAC_ADDR); Wire.write®;

if(Wire.endTransmission(false)!=0) return false;

if(Wire.requestFrom((int)DAC_ADDR,1)!=1) return false;

v=Wire.read(); return true;

}

bool pingDAC(){ Wire.beginTransmission(DAC_ADDR); return (Wire.endTransmission()==0); }

/* =========================

ЧИП / СТАТУС

========================= */

void chipOn(){ pinMode(CHIP_EN_PIN,OUTPUT); digitalWrite(CHIP_EN_PIN,HIGH); }

void chipOff(){ digitalWrite(CHIP_EN_PIN,LOW); }

void chipReset(uint16_t ms){ chipOff(); delay(ms); chipOn(); delay(150); }

bool lockStatus(){ uint8_t s1=0; if(!rd(REG_S1,s1)) return false; return (s1&0x80)!=0; }

uint32_t fsFromS2(){

uint8_t s2=0; if(!rd(REG_S2,s2)) return 0; switch(s2&0x0F){

case 0: return 44100; case 1: return 48000; case 2: return 88200; case 3: return 96000;

case 4: return 176400; case 5: return 192000; case 6: return 384000; default: return 0; }

}

/* =========================

ЗАПИСИ В ЦАП (без mute)

========================= */

void volWriteLR(uint8_t vL,uint8_t vR){ wr(REG_VOL_L,vL); wr(REG_VOL_R,vR); }

void setFilter(uint8_t f){ wr(REG_FILTER, f & 0x07); }

void writePathConfig(){

uint8_t v=0;

if(g_bypIIR) v|=0x04;

if(g_bypFIR4) v|=0x02;

if(g_bypFIR2) v|=0x01;

wr(REG_PATH, v);

switch(g_path){

default:

case 0: wr(REG_SLOT_L,0x00); wr(REG_SLOT_R,0x01); break;

case 1: wr(REG_SLOT_L,0x00); wr(REG_SLOT_R,0x00); break;

case 2: wr(REG_SLOT_L,0x01); wr(REG_SLOT_R,0x01); break;

case 3: wr(REG_SLOT_L,0x01); wr(REG_SLOT_R,0x00); break;

}

}

void applySafe_VolBal(){

int16_t vL=g_volBase, vR=g_volBase;

if(g_balance>0) vL+=g_balance; else if(g_balance<0) vR+=(-g_balance);

if(vL<0)vL=0; if(vL>255)vL=255; if(vR<0)vR=0; if(vR>255)vR=255;

volWriteLR((uint8_t)vL,(uint8_t)vR);

}

void applySafe_Filter(){ setFilter(g_dfilt); }

void applySafe_Path(){ writePathConfig(); }

void applyAutoMute(){

uint8_t en = (g_amCh1?1:0) | (g_amCh2?2:0);

wr(REG_AM_ENABLE, en);

uint16_t t = ((g_amRampGND?1:0)<<11) | (g_amTime & 0x07FF);

wr16(REG_AM_TIME_L, t);

}

// THD: LSB->MSB, [15:0]=L, [31:16]=R

void applyTHD_C2(){

uint16_t wL=(uint16_t)g_c2_L, wR=(uint16_t)g_c2_R;

wr(REG_THD_C2_LSB+0,(uint8_t)(wL&0xFF));

wr(REG_THD_C2_LSB+1,(uint8_t)((wL>>8)&0xFF));

wr(REG_THD_C2_LSB+2,(uint8_t)(wR&0xFF));

wr(REG_THD_C2_LSB+3,(uint8_t)((wR>>8)&0xFF));

}

void applyTHD_C3(){

uint16_t wL=(uint16_t)g_c3_L, wR=(uint16_t)g_c3_R;

wr(REG_THD_C3_LSB+0,(uint8_t)(wL&0xFF));

wr(REG_THD_C3_LSB+1,(uint8_t)((wL>>8)&0xFF));

wr(REG_THD_C3_LSB+2,(uint8_t)(wR&0xFF));

wr(REG_THD_C3_LSB+3,(uint8_t)((wR>>8)&0xFF));

}

/* =========================

ОПАСНЫЕ — ПЛАНИРОВЩИК

========================= */

void queueApply(bool softR){ if(!g_hardOnly) pend.softReset |= softR; }

void runPending(){

static bool busy=false;

if(g_hardOnly){ pend=Pending(); busy=false; return; }

if(busy) return;

if(!(pend.polarity||pend.pll||pend.autoclk||pend.autoin||pend.softReset)) return;

busy=true;

if(pend.softReset){ wr(REG_SYS,0x80); delay(6); }

wr(REG_SYS,0x02); // аналог включен

if(pend.polarity) wr(REG_IFACE_POL,(g_pol&0x03));

if(pend.autoclk) wr(REG_CLKCFG, g_autoClk?0x40:0x00);

if(pend.pll) wr(REG_PLL_BW, g_pll);

if(pend.autoin) wr(REG_AUTO_INPUT,g_autoIn?0x01:0x00);

writePathConfig();

applySafe_VolBal();

setFilter(g_dfilt);

delay(g_settle);

pend=Pending();

busy=false;

}

/* =========================

EEPROM / PRESETS

========================= */

void cfgFromGlobals(Config &c){

c.version=CFG_VERSION;

c.volBase=g_volBase; c.balance=g_balance; c.dfilt=g_dfilt; c.path=g_path;

c.bypIIR=g_bypIIR; c.bypFIR4=g_bypFIR4; c.bypFIR2=g_bypFIR2;

c.pol=g_pol; c.pll=g_pll; c.autoClk=g_autoClk; c.autoIn=g_autoIn;

c.hardg_hardOnly; c.settle=g_settle;

c.amCh1=g_amCh1; c.amCh2=g_amCh2; c.amRamp=g_amRampGND; c.amTime=g_amTime;

c.c2L=g_c2_L; c.c2R=g_c2_R; c.c3L=g_c3_L; c.c3R=g_c3_R;

c.autosave=g_autosave?1:0;

c.crc=0;

c.crc=crc16((uint8_t*)&c, sizeof(Config)-2);

}

void globalsFromCfg(const Config &c){

g_volBase=c.volBase; g_balance=c.balance; g_dfilt=c.dfilt; g_path=c.path;

g_bypIIR=c.bypIIR; g_bypFIR4=c.bypFIR4; g_bypFIR2=c.bypFIR2;

g_pol=c.pol; g_pll=c.pll; g_autoClk=c.autoClk; g_autoIn=c.autoIn;

g_hardc.hardOnly; g_settle=c.settle;

g_amCh1=c.amCh1; g_amCh2=c.amCh2; g_amRampGND=c.amRamp; g_amTime=c.amTime;

g_c2_L=c.c2L; g_c2_R=c.c2R; g_c3_L=c.c3L; g_c3_R=c.c3R;

g_autosave=(c.autosave!=0);

}

bool eepromWrite(int base, const Config &c){

Config tmp=c;

for(unsigned i=0;i<sizeof(Config);++i) EEPROM.update(base+i, ((uint8_t*)&tmp)[i]);

return true;

}

bool eepromRead(int base, Config &c){

for(unsigned i=0;i<sizeof(Config);++i) ((uint8_t*)&c)[i]=EEPROM.read(base+i);

if(c.version!=CFG_VERSION) return false;

uint16_t calc=crc16((uint8_t*)&c, sizeof(Config)-2);

return (calc==c.crc);

}

void loadSlot(uint8_t slot){

int addr = (slot==1)?EE_ADDR_PRE1: (slot==2)?EE_ADDR_PRE2: EE_ADDR_PRE3;

Config c; if(eepromRead(addr,c)){ globalsFromCfg©; }

}

void saveSlot(uint8_t slot){

int addr = (slot==1)?EE_ADDR_PRE1: (slot==2)?EE_ADDR_PRE2: EE_ADDR_PRE3;

Config c; cfgFromGlobals©; eepromWrite(addr,c);

}

void autosaveWrite(){

if(!g_autosave) return;

static uint32_t last=0;

uint32_t now=millis();

if(now-last<1500) return; // экономим ресурс EEPROM

last=now;

Config c; cfgFromGlobals©; eepromWrite(EE_ADDR_LAST,c);

}

void autosaveLoadOnBoot(){

Config c; if(eepromRead(EE_ADDR_LAST,c)){ globalsFromCfg©; }

}

/* =========================

ЭКРАН / МЕНЮ

========================= */

void showStatus(){

lcd.clear();

lcd.print(lockStatus()? «Lock:Y »:«Lock:N „);

lcd.print(“P:»); lcd.print(g_pol);

lcd.setCursor(0,1);

uint32_t fs=fsFromS2();

if(fs){ lcd.print(«Fs:»); lcd.print(fs/1000); lcd.print(«k „); }

else { lcd.print(“Fs:? „); }

}

void drawMenu(){

lcd.clear();

lcd.print(“[»); lcd.print(menu_idx+1); lcd.print("/"); lcd.print(MCNT); lcd.print("] ");

lcd.print(MENU[menu_idx]);

lcd.setCursor(0,1);

switch(menu_idx){

case 0: lcd.print(«Status»); break;

case 1: lcd.print(«Vol: „); lcd.print(g_volBase); break;

case 2: lcd.print(“Bal: „); lcd.print((int)g_balance); break;

case 3: lcd.print(“Filt: „); lcd.print(g_dfilt); break;

case 4: lcd.print(“Path: „); lcd.print(g_path); break;

case 5: lcd.print(“Byp IIR: „); lcd.print(g_bypIIR ?“Y»:«N»); break;

case 6: lcd.print(«Byp FIR4: „); lcd.print(g_bypFIR4?“Y»:«N»); break;

case 7: lcd.print(«Byp FIR2: „); lcd.print(g_bypFIR2?“Y»:«N»); break;

case 8: lcd.print(«AM Ch1: „); lcd.print(g_amCh1?“ON»:«OFF»); break;

case 9: lcd.print(«AM Ch2: „); lcd.print(g_amCh2?“ON»:«OFF»); break;

case 10: lcd.print(«AM RampGND: „); lcd.print(g_amRampGND?“Y»:«N»); break;

case 11: lcd.print(«AM Time: „); lcd.print(g_amTime); break;

case 12: lcd.print(“THD C2 L: „); lcd.print(g_c2_L); break;

case 13: lcd.print(“THD C2 R: „); lcd.print(g_c2_R); break;

case 14: lcd.print(“THD C3 L: „); lcd.print(g_c3_L); break;

case 15: lcd.print(“THD C3 R: „); lcd.print(g_c3_R); break;

case 16: lcd.print(“Pol: „); lcd.print(g_pol); break;

case 17: lcd.print(“DPLL:0x»); lcd.print(g_pll,HEX); break;

case 18: lcd.print(«AutoClk: „); lcd.print(g_autoClk?“ON»:«OFF»); break;

case 19: lcd.print(«AutoIn: „); lcd.print(g_autoIn ?“ON»:«OFF»); break;

case 20: lcd.print(«Load P»); lcd.print(g_presetSel); break;

case 21: lcd.print(«Save P»); lcd.print(g_presetSel); break;

case 22: lcd.print(«Autosave: „); lcd.print(g_autosave?“ON»:«OFF»); break;

case 23: lcd.print(«HardOnly: „);lcd.print(g_hardOnly?“YES»:«NO»); break;

case 24: lcd.print(«Reset CHIP_EN»); break;

}

}

/* =========================

ВВОД / ОБРАБОТКА

========================= */

void encISR(){

static uint8_t prev=0;

uint8_t cur=(digitalRead(ENC_A)<<1)|digitalRead(ENC_B);

static const int8_t tab[4][4]={{0,-1,+1,0},{+1,0,0,-1},{-1,0,0,+1},{0,+1,-1,0}};

enc_delta+=tab[prev][cur]; prev=cur;

}

void pollBtn(){

static uint32_t t0=0,down=0; static bool last=false;

static uint32_t lastUp=0; static bool clickArmed=false;

const uint16_t DEB=20,L900, DBL=350;

bool raw=(digitalRead(BTN)==LOW); uint32_t now=millis();

if(raw!=last && (now-t0)>DEB){

t0=now; last=raw;

if(raw){ down=now; }

else{

uint32_t dur=now-down;

if(dur<600){

if(clickArmed && (now-lastUp)<DBL){ btn_dbl=true; clickArmed=false; }

else { btn_short=true; clickArmed=true; lastUp=now; }

}else if(dur>=LONG){ btn_ltrue; clickArmed=false; }

}

}

if(clickArmed && (now-lastUp)>=DBL) clickArmed=false;

}

void onChangeSafe(uint8_t code){

switch(code){

case 1: applySafe_VolBal(); autosaveWrite(); break;

case 2: applySafe_Filter(); autosaveWrite(); break;

case 3: applySafe_Path(); autosaveWrite(); break;

case 4: applyAutoMute(); autosaveWrite(); break;

case 5: applyTHD_C2(); autosaveWrite(); break;

case 6: applyTHD_C3(); autosaveWrite(); break;

}

}

void onChangeDanger(uint8_t what){

if(g_hardOnly) return;

if(what==10) pend.polarity=true;

if(what==11) pend.pll=true;

if(what==12) pend.autoclk=true;

if(what==13) pend.autoin=true;

queueApply(false);

autosaveWrite();

}

void doAction(uint8_t idx){

if(idx==0){ showStatus(); return; }

if(idx==20){ // Load preset

loadSlot(g_presetSel);

writePathConfig(); setFilter(g_dfilt); applySafe_VolBal();

applyAutoMute(); applyTHD_C2(); applyTHD_C3();

drawMenu(); return;

}

if(idx==21){ // Save preset

saveSlot(g_presetSel);

drawMenu(); return;

}

if(idx==24){

chipReset();

wr(REG_SYS,0x02);

writePathConfig(); setFilter(g_dfilt); applySafe_VolBal();

applyAutoMute(); applyTHD_C2(); applyTHD_C3();

drawMenu(); return;

}

}

/* =========================

SETUP / LOOP

========================= */

void setup(){

chipOn();

Wire.begin();

lcd.init(); lcd.backlight();

pinMode(ENC_A,INPUT_PULLUP); pinMode(ENC_B,INPUT_PULLUP); pinMode(BTN,INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(ENC_A), encISR, CHANGE);

attachInterrupt(digitalPinToInterrupt(ENC_B), encISR, CHANGE);

lcd.print(«ES9039Q2M +EEPROM»);

lcd.setCursor(0,1);

if(pingDAC()){ uint8_t id=0; rd(REG_ID,id); lcd.print(«I2C OK ID:»); lcd.print(id,HEX); }

else lcd.print(«I2C ERR»);

// загрузить автосохранённое состояние (если валидно)

autosaveLoadOnBoot();

// аналог ON, применить конфиг в железо

wr(REG_SYS,0x02);

writePathConfig(); setFilter(g_dfilt); applySafe_VolBal();

applyAutoMute(); applyTHD_C2(); applyTHD_C3();

drawMenu();

}

void loop(){

static uint32_t tPoll=0;

static uint32_t tStat=0;

if(millis()-tPoll>5){ pollBtn(); tPoll=millis(); }

int16_t d=enc_delta; enc_delta=0;

// редактирование

if(edit && d){

switch(menu_idx){

// базовые

case 1:{ int n=g_volBase+(d>0?+1:-1); if(n<0)n=0; if(n>255)n=255; g_volBase=n; onChangeSafe(1);}break;

case 2:{ int n=g_balance+(d>0?+1:-1); if(n<-24)n=-24; if(n>24)n=24; g_balance=n; onChangeSafe(1);}break;

case 3:{ int n=g_dfilt +(d>0?+1:-1); if(n<0)n=7; if(n>7)n=0; g_dfilt=n; onChangeSafe(2);}break;

case 4:{ int n=g_path +(d>0?+1:-1); if(n<0)n=3; if(n>3)n=0; g_path =n; onChangeSafe(3);}break;

// bypass

case 5: g_bypIIR = !g_bypIIR; onChangeSafe(3); break;

case 6: g_bypFIR4 = !g_bypFIR4; onChangeSafe(3); break;

case 7: g_bypFIR2 = !g_bypFIR2; onChangeSafe(3); break;

// AutoMute

case 8: g_amCh1 = !g_amCh1; onChangeSafe(4); break;

case 9: g_amCh2 = !g_amCh2; onChangeSafe(4); break;

case 10: g_amRampGND = !g_amRampGND; onChangeSafe(4); break;

case 11:{ int n=g_amTime+(d>0?+1:-1); if(n<0)n=0; if(n>0x07FF)n=0x07FF; g_amTime=(uint16_t)n; onChangeSafe(4);}break;

// THD

case 12:{ int n=g_c2_L+(d>0?+1:-1); if(n<-32768)n=-32768; if(n>32767)n=32767; g_c2_L=(int16_t)n; onChangeSafe(5);}break;

case 13:{ int n=g_c2_R+(d>0?+1:-1); if(n<-32768)n=-32768; if(n>32767)n=32767; g_c2_R=(int16_t)n; onChangeSafe(5);}break;

case 14:{ int n=g_c3_L+(d>0?+1:-1); if(n<-32768)n=-32768; if(n>32767)n=32767; g_c3_L=(int16_t)n; onChangeSafe(6);}break;

case 15:{ int n=g_c3_R+(d>0?+1:-1); if(n<-32768)n=-32768; if(n>32767)n=32767; g_c3_R=(int16_t)n; onChangeSafe(6);}break;

// интерфейс/PLL

case 16:{ int n=g_pol+(d>0?+1:-1); if(n<0)n=3; if(n>3)n=0; g_pol=n; onChangeDanger(10);}break;

case 17:{ int n=g_pll+(d>0?+1:-1); if(n<0x01)n=0x01; if(n>0x10)n=0x10; g_pll=n; onChangeDanger(11);}break;

case 18: g_autoClk=!g_autoClk; onChangeDanger(12); break;

case 19: g_autoIn =!g_autoIn; onChangeDanger(13); break;

// пресеты

case 20:{ int n=g_presetSel+(d>0?+1:-1); if(n<1)n=1; if(n>3)n=3; g_presetSel=n; }break;

case 21:{ int n=g_presetSel+(d>0?+1:-1); if(n<1)n=1; if(n>3)n=3; g_presetSel=n; }break;

case 22: g_autosave=!g_autosave; autosaveWrite(); break;

case 23: g_hard!g_hardOnly; autosaveWrite(); break;

}

drawMenu();

}

// навигация

if(!edit && d){

int n = (int)menu_idx + (d>0?+1:-1);

if(n<0) n=MCNT-1; if(n>=MCNT) n=0;

menu_idx=(uint8_t)n; drawMenu();

}

// клики

if(btn_short){ btn_short=false; if(menu_idx==0) showStatus(); else doAction(menu_idx); }

if(btn_dbl){ btn_dbl=false; if(!g_hardOnly){ pend.softReset=false; runPending(); showStatus(); } }

if(btn_long){ btn_lfalse; edit=!edit; lcd.setCursor(15,0); lcd.print(edit?"*":" "); }

// фон

runPending();

if(menu_idx==0 && millis()-tStat>800){ showStatus(); tStat=millis(); }

}

0
Pushok62 Pushok62 Документация к ES9039Q2M 1 день назад

Можно на vo_pushkov@mail.ru, а лучше оформить здесь на сайте статьёй, чтобы другие могли воспользоваться этой ценной информацией.

0
Le81 Le81 Документация к ES9039Q2M 1 день назад

Куда скинуть?

0
Pushok62 Pushok62 Документация к ES9039Q2M 1 день назад

Спасибо!

+3
Le81 Le81 Документация к ES9039Q2M 1 день назад

Да конечно, скейч написан под ардуино нано, думаю без труда можно перепесать под свой контролер, сейчас работает с меню, громкость баланс, фазовый захват, полярность сигнала, авто формат, авто вход, настройка стерео и двойное моно, тоесть сам ставишь какой чип будет правый а какой левый, все фильтры, ещё дописал настройки по звуку, но не обкатал их, завтра займусь, короче заставил для эксперемента включить в меню вообще всё что умеет чип, допилю и скину. А так была плата с Китая, там блютуз и два ципа es9039q2m, Китай не стал заморачиватся с двойным моно и просто включил параллельно выходы, на плате был процессор который я так понял только включал в софт es9039q2m, но звук мне не понравился, короче выкинул проц, за одно спалил обе es9039q2m, пока игрался в хард режиме, заказал новый но он больше не запел в плате, скорее всего второго чипа не хватало, проц ждал два адреса от es9039q2m, короче пришлось играться с ардуино, звук на много лучше сейчас чем был с родным проц, сейчас в настройках появилась функция по фильтру гармоник, то есть подавляя вторую или 3 меняет восприятия.

0
Pushok62 Pushok62 Документация к ES9039Q2M 1 день назад

Подéлитесь описанием конструкции и исходниками?

0
igorigotos17 igorigotos17 Дискретный операционный усилитель AH-OP3 v1.0 1 день назад

Отличные параметры для дискретного ОУ!

0
Le81 Le81 Документация к ES9039Q2M 2 дня назад

Неделю мучений и чат джипити запустил es9039q2m на ардуино! Строки с пиндоса реально помогли.

0
caleb caleb Pcm58 продам 3 дня назад

Да вообще весьма вкусная плата.

+1
admin admin Переделка модуля XingCore в slave для работы с AH-D16 Pro / AH-D17 Pro 3 дня назад

корпус USB нельзя, он с землей соединяется через емкость, т.е. прямого соединения не имеет.

0
anton11 anton11 Переделка модуля XingCore в slave для работы с AH-D16 Pro / AH-D17 Pro 3 дня назад

Все пины GND объединены на один общий полигон земли, подавать землю можно на любой пин, отдельно зачищать плату смысла не вижу, но если очень хочется, то можно подпаять провод сбоку разъёма USB, где корпус разъёма подпаивается к плате

0
admin admin Переделка модуля XingCore в slave для работы с AH-D16 Pro / AH-D17 Pro 3 дня назад

Любой вариант,

1) можете «отдельно место зачистить на текстолите под землю» — только убедитесь, что это точно будет земля

2) можете использовать любой земляной пятак 20-пинового разъема, кому и это сложно, 1 пятак там явно подписан — GND, используем его.

0
Noctis84 Noctis84 Переделка модуля XingCore в slave для работы с AH-D16 Pro / AH-D17 Pro 4 дня назад

Подскажите пожалуйста — если подавать доп питание 5В на Ксинг, землю точно можно кинуть на любой из 20 пинового разьема? (там несколько пинов) Может где то отдельно место зачистить на текстолите под землю? Собираюсь еще один купить и попробовать запитать дополнительно.

0
bavtec bavtec Лисье сердце - рецепт одного из блюд 4 дня назад

В роутере они просто пропишутся.
А мне надо в сети где нет DHCP.

0
bavtec bavtec Лисье сердце - рецепт одного из блюд 4 дня назад

Спасибо. Попробую.
Плохо что сбросятся настройки после обновки.

0
caleb caleb Лисье сердце - рецепт одного из блюд 4 дня назад

Еще можно в роутере присвоить.

+1
zirkony zirkony Лисье сердце - рецепт одного из блюд 5 дней назад

Протестировано на LuckFox_MAX_0.4.2[4832].

И редактируем /etc/network/interfaces , /etc/init.d/S01RkLunch ...

ps: не получается тут нормально отформатировать текст, продублировал здесьhttps://pastebin.com/raw/SJKp8hSR