Да конечно, скейч написан под ардуино нано, думаю без труда можно перепесать под свой контролер, сейчас работает с меню, громкость баланс, фазовый захват, полярность сигнала, авто формат, авто вход, настройка стерео и двойное моно, тоесть сам ставишь какой чип будет правый а какой левый, все фильтры, ещё дописал настройки по звуку, но не обкатал их, завтра займусь, короче заставил для эксперемента включить в меню вообще всё что умеет чип, допилю и скину. А так была плата с Китая, там блютуз и два ципа es9039q2m, Китай не стал заморачиватся с двойным моно и просто включил параллельно выходы, на плате был процессор который я так понял только включал в софт es9039q2m, но звук мне не понравился, короче выкинул проц, за одно спалил обе es9039q2m, пока игрался в хард режиме, заказал новый но он больше не запел в плате, скорее всего второго чипа не хватало, проц ждал два адреса от es9039q2m, короче пришлось играться с ардуино, звук на много лучше сейчас чем был с родным проц, сейчас в настройках появилась функция по фильтру гармоник, то есть подавляя вторую или 3 меняет восприятия.
Все пины GND объединены на один общий полигон земли, подавать землю можно на любой пин, отдельно зачищать плату смысла не вижу, но если очень хочется, то можно подпаять провод сбоку разъёма USB, где корпус разъёма подпаивается к плате
Подскажите пожалуйста — если подавать доп питание 5В на Ксинг, землю точно можно кинуть на любой из 20 пинового разьема? (там несколько пинов) Может где то отдельно место зачистить на текстолите под землю? Собираюсь еще один купить и попробовать запитать дополнительно.
Ух какой вкусный цап… И цена, по сути за детали с такой хорошей комплектацией. Купил бы, но у меня уже есть.
… или временно загрузить на пастебин, там можно указать срок хранение
Иначе вот такое получается, как на картинке
#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(); }
}
Можно на vo_pushkov@mail.ru, а лучше оформить здесь на сайте статьёй, чтобы другие могли воспользоваться этой ценной информацией.
Куда скинуть?
Спасибо!
Да конечно, скейч написан под ардуино нано, думаю без труда можно перепесать под свой контролер, сейчас работает с меню, громкость баланс, фазовый захват, полярность сигнала, авто формат, авто вход, настройка стерео и двойное моно, тоесть сам ставишь какой чип будет правый а какой левый, все фильтры, ещё дописал настройки по звуку, но не обкатал их, завтра займусь, короче заставил для эксперемента включить в меню вообще всё что умеет чип, допилю и скину. А так была плата с Китая, там блютуз и два ципа es9039q2m, Китай не стал заморачиватся с двойным моно и просто включил параллельно выходы, на плате был процессор который я так понял только включал в софт es9039q2m, но звук мне не понравился, короче выкинул проц, за одно спалил обе es9039q2m, пока игрался в хард режиме, заказал новый но он больше не запел в плате, скорее всего второго чипа не хватало, проц ждал два адреса от es9039q2m, короче пришлось играться с ардуино, звук на много лучше сейчас чем был с родным проц, сейчас в настройках появилась функция по фильтру гармоник, то есть подавляя вторую или 3 меняет восприятия.
Подéлитесь описанием конструкции и исходниками?
Отличные параметры для дискретного ОУ!
Неделю мучений и чат джипити запустил es9039q2m на ардуино! Строки с пиндоса реально помогли.
Да вообще весьма вкусная плата.
корпус USB нельзя, он с землей соединяется через емкость, т.е. прямого соединения не имеет.
супер, благодарю!
Все пины GND объединены на один общий полигон земли, подавать землю можно на любой пин, отдельно зачищать плату смысла не вижу, но если очень хочется, то можно подпаять провод сбоку разъёма USB, где корпус разъёма подпаивается к плате
Любой вариант,
1) можете «отдельно место зачистить на текстолите под землю» — только убедитесь, что это точно будет земля
2) можете использовать любой земляной пятак 20-пинового разъема, кому и это сложно, 1 пятак там явно подписан — GND, используем его.
Подскажите пожалуйста — если подавать доп питание 5В на Ксинг, землю точно можно кинуть на любой из 20 пинового разьема? (там несколько пинов) Может где то отдельно место зачистить на текстолите под землю? Собираюсь еще один купить и попробовать запитать дополнительно.
В роутере они просто пропишутся.
А мне надо в сети где нет DHCP.
Спасибо. Попробую.
Плохо что сбросятся настройки после обновки.
Еще можно в роутере присвоить.
Протестировано на LuckFox_MAX_0.4.2[4832].
И редактируем /etc/network/interfaces , /etc/init.d/S01RkLunch ...
ps: не получается тут нормально отформатировать текст, продублировал здесьhttps://pastebin.com/raw/SJKp8hSR