Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2025:cmoarcas:gheorghe.petrica [2025/05/14 02:12]
gheorghe.petrica
pm:prj2025:cmoarcas:gheorghe.petrica [2025/05/30 09:55] (current)
gheorghe.petrica [Rezultate Obţinute]
Line 37: Line 37:
 === Lista de piese === === Lista de piese ===
  
-^ Nr. Crt. ^ Denumire Componenta ^ Cantitate ^ Descriere / Specificatii ^ +^ Nr. Crt. ^ Denumire Componenta ^ Cantitate ^ Descriere / Specificatii ​^ Link + DataSheet ​
-| 1 | ESP32 DevKit v1 | 1 | Microcontroller cu WiFi + Bluetooth, interfete SPI/I2C/I2S | +| 1 | ESP32 DevKit v1 | 1 | Microcontroller cu WiFi + Bluetooth, interfete SPI/​I2C/​I2S ​|https://​www.electronicmarket.ro/​ro/​product/​esp32-wroom-32-placa-de-dezvoltare-38-pini?​gad_campaignid=21513542058 https://​www.espressif.com/​sites/​default/​files/​documentation/​esp32-wroom-32_datasheet_en.pdf ​
-| 2 | Arduino Uno R3 | 1 | Pentru comunicarea SPI cu casetofonul (emulare CD changer) | +| 2 | Arduino Uno R3 | 1 | Pentru comunicarea SPI cu casetofonul (emulare CD changer) ​| https://​ardushop.ro/​ro/​plci-de-dezvoltare/​2282-placa-de-dezvoltare-uno-r3-compatibil-arduino-6427854027122.html?​gad_campaignid=22058879462 https://​ww1.microchip.com/​downloads/​en/​devicedoc/​doc8161.pdf ​
-| 3 | Modul microfon I2S (INMP441) | 1 | Microfon digital pentru transmitere voce (handsfree) |+| 3 | Modul microfon I2S (INMP441) | 1 | Microfon digital pentru transmitere voce (handsfree) ​| https://​www.emag.ro/​microfon-digital-electroweb-omnidirectional-mems-inmp441-3-f-060/​pd/​DL3NPBYBM/​ https://​www.invensense.com/​wp-content/​uploads/​2015/​02/​INMP441.pdf ​|
 | 4 | Modul cititor microSD pe SPI | 1 | Pentru redare muzica de pe card | | 4 | Modul cititor microSD pe SPI | 1 | Pentru redare muzica de pe card |
-| 5 | Modul ecran TFT 1.44" SPI | 1 | Afisare melodie curenta, status conexiune, etc. |+| 5 | Modul ecran TFT 1.44" SPI | 1 | Afisare melodie curenta, status conexiune, etc. | https://​www.optimusdigital.ro/​en/​lcds/​2167-144-lcd-for-stc-stm32-and-arduino-boards.html?​gad_campaignid=19615979487 https://​cdn-shop.adafruit.com/​datasheets/​ST7735.pdf ​|
 | 6 | Butoane tactile (tip pushbutton) | 5 | Play/Pause, Next, Prev, Accept Call, Reject Call | | 6 | Butoane tactile (tip pushbutton) | 5 | Play/Pause, Next, Prev, Accept Call, Reject Call |
-| 7 | Amplificator audio clasa D (TPA3118) | 1 | Suporta pana la 60W pe canal, alimentare 12–24V |+| 7 | Amplificator audio clasa D (TPA3118) | 1 | Suporta pana la 60W pe canal, alimentare 12–24V ​| https://​sigmanortec.ro/​modul-amplificator-audio-1-canal-60w-4-8ohm-tpa3118-8-24vdc-digital?​SubmitCurrency=1&​id_currency=2&​gad_campaignid=22174019478 https://​www.ti.com/​lit/​ds/​symlink/​tpa3118d2.pdf ​|
 | 8 | Difuzor 5 inch, 4 Ohmi | 1 | Pentru testarea audio (simulare casetofon) | | 8 | Difuzor 5 inch, 4 Ohmi | 1 | Pentru testarea audio (simulare casetofon) |
-| 9 | Sursa de alimentare 24V | 1 | Pentru alimentarea amplificatorului si difuzorului | +| 9 | Sursa de alimentare 24V | 1 | Pentru alimentarea amplificatorului si difuzorului ​| https://​www.a2t.ro/​default-category/​sursa-de-alimentare-24v-10-in-comutatie-stabilizata?​gad_campaignid=18574987832 ​
-| 10 | Sursa step-down (LM2596) | 1 | Pentru a obtine 5V/3.3V pentru ESP32 si periferice | +| 10 | Sursa step-down (LM2596) | 1 | Pentru a obtine 5V/3.3V pentru ESP32 si periferice ​| https://​www.emag.ro/​modul-coborare-tensiune-lm2596-tri252/​pd/​D9XL5VBBM/?​ref=history-shopping_423138763_34366_1 https://​www.ti.com/​lit/​ds/​symlink/​lm2596.pdf ​
-| 11 | Modul DAC audio CS4344 | 1 | Pentru a genera semnal analogic |+| 11 | Modul DAC audio CS4344 | 1 | Pentru a genera semnal analogic ​| https://​ardushop.ro/​ro/​module/​729-modul-dac-audio-cs4344-cu-filtru-trece-jos-si-port-i2s-compatibil-cu-arduino-6427854009272.html https://​www.cirrus.com/​products/​cs4344/ ​|
 | 12 | Breadboard + jumper wires | 1 set | Pentru prototipare si conectare module | | 12 | Breadboard + jumper wires | 1 set | Pentru prototipare si conectare module |
  
 === Diagrama Bloc pentru casetofon === === Diagrama Bloc pentru casetofon ===
-{{:​pm:​prj2025:​cmoarcas:​arduino_uno.png?700|}}+{{:​pm:​prj2025:​cmoarcas:​ImperiumBT.png?700|}}
  
 === Schema electrica === === Schema electrica ===
Line 59: Line 59:
 ===== Software Design ===== ===== Software Design =====
  
 +== CDC Emulator ==
  
-<note tip> +Pentru a putea trimite orice fel de semnal audio catre casetofonul auto, vom folosi un Arduino Uno, iar cu ajutorul interfetei SPI vom trimite o secvente de date catre casetofonIn lipsa acestei secventecasetofonul in momentul in care este aleasa optiunea de redare de pe CD, va genera o eroare de tipul **NO CD CHANGER** chiar daca pe inputul audio este trimis semnal.
-Descrierea codului aplicaţiei (firmware):​ +
-  * mediu de dezvoltare (if any) (e.g. AVR StudioCodeVisionAVR) +
-  ​librării şi surse 3rd-party (e.g. Procyon AVRlib) +
-  ​algoritmi şi structuri pe care plănuiţi să le implementaţi +
-  ​(etapa 3) surse şi funcţii implementate +
-</​note>​+
  
-===== Rezultate Obţinute =====+Folosim urmatoarele define-uri pentru a indica fiecare comanda suportata de casetofon:​ 
 +  #define CDC_PREFIX1 0x53 
 +  #define CDC_PREFIX2 0x2C 
 +  #define CDC_END_CMD 0x14 
 +  #define CDC_PLAY 0xE4 
 +  #define CDC_STOP 0x10 
 +  #define CDC_NEXT 0xF8 
 +  #define CDC_PREV 0x78 
 +  #define CDC_SEEK_FWD 0xD8 
 +  #define CDC_SEEK_RWD 0x58 
 +  #define CDC_CD1 0x0C 
 +  #define CDC_CD2 0x8C 
 +  #define CDC_CD3 0x4C 
 +  #define CDC_CD4 0xCC 
 +  #define CDC_CD5 0x2C 
 +  #define CDC_CD6 0xAC 
 +  #define CDC_SCAN 0xA0 
 +  #define CDC_SFL 0x60 
 +  #define CDC_PLAY_NORMAL 0x08 
 +  #define MODE_PLAY 0xFF 
 +  #define MODE_SHFFL 0x55 
 +  #define MODE_SCAN 0x00 
 +  uint8_t cd, tr, mode; 
 +  unsigned long prevMillis ​0; 
 +   
 +Functia urmatoare **send_package()** trimite un pachet de cate 8 octeti pe SPI, cu intarziere pe fiecare transfer: 
 +  void send_package(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4, uint8_t c5, uint8_t c6, uint8_t c7) { 
 +    uint8_t data[8] ​{c0, c1, c2, c3, c4, c5, c6, c7}; 
 +    for (int i 0; i < 8; i++) { 
 +      SPDR data[i]; 
 +      while (!(SPSR & (1 << SPIF))); 
 +      delayMicroseconds(874);​ 
 +    } 
 +  }
  
-<note tip> +Initializam SPI, dupa cum urmeaza, astfel incat sa ruleze cu o viteza de transfer de 62.5kHz 
-Care au fost rezultatele obţinute în urma realizării proiectului vostru. +  void spi_init() { 
-</note>+    DDRB |= (1 << PB3) | (1 << PB5); 
 +    DDRB &= ~(1 << PB4); 
 +    SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); 
 +    SPSR &= ~(1 << SPI2X); 
 +  }
  
-===== Concluzii =====+In functia **setup()** initializam valorile initiale pentru disc, mod de redare, piesa, precum si interfata SPI. Dupa care trimitem o secventa de comenzi pentru //load// si //idle// 
 +  void setup() { 
 +    cd 1; 
 +    tr 1; 
 +    mode MODE_PLAY;​ 
 +    #ifdef DEBUG 
 +    Serial.begin(9600);​ 
 +    #endif 
 +    delay(1000);​ 
 +    spi_init();​ 
 +    send_package(0x74,​ 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0x8F, 0x7C); // idle 
 +    delayMicroseconds(10000);​ 
 +    send_package(0x34,​ 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFA, 0x3C); // load disc 
 +    delayMicroseconds(100000);​ 
 +    send_package(0x74,​ 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0x8F, 0x7C); // idle 
 +    delayMicroseconds(10000);​ 
 +    #ifdef DEBUG 
 +    Serial.println("​Sent idle/​load/​idle commands"​);​ 
 +    #endif 
 +  }
  
-===== Download =====+In continuare tot pe Arduino, in functia **loop()** vom trimite la fiecare 50ms cate un pachet care contine discul, piesa si modul de redare pentru a mentine conexiunea activa cu casetofonul auto ales: 
 +  void loop() { 
 +    if ((millis() - prevMillis) > 50) { 
 +      send_package(0x34,​ 0xBF ^ cd, 0xFF ^ tr, 0xFF, 0xFF, mode, 0xCF, 0x3C); 
 +      prevMillis ​millis();
  
-<note warning> +      #ifdef DEBUG 
-O arhivă ​(sau mai multe dacă este cazulcu fişierele obţinute în urma realizării proiectului:​ surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-).+      ​Serial.println("Sent packet"​); 
 +      #endif 
 +    } 
 +  }
  
-Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:​pm:​prj20??:​c?​** sau **:​pm:​prj20??:​c?:​nume_student** (dacă este cazul). **Exemplu:​** Dumitru Alin, 331CC -> **:​pm:​prj2009:​cc:​dumitru_alin**. +== Bluetooth Receiver ==
-</​note>​+
  
-===== Jurnal ​=====+In urmatoarele bucati de cod voi descrie cum am folosit un **ESP32** pentru a deveni un receiver audio prin interfata Bluetooth a acestuia si sa redirectionez semnalul audio prin interfata I2S catre DAC extern (e.g. CS4344) 
 + 
 +Definim in continuare pinii folositi pentru interfata I2S, butoanele de play/pause pe care le vom folosi, pinii SPI folositi pentru ecranul TFT, care va folosi biblioteca Adafruit_ST7735,​ precum si variabilele folosite pentru debounce: 
 +  #define I2S_BCLK ​   26 
 +  #define I2S_LRCK ​   25 
 +  #define I2S_DATA ​   22 
 +  #define I2S_MCLK ​   3  // sau I2S_PIN_NO_CHANGE 
 + 
 +  // === Butoane ​==
 +  #define BTN_PLAY ​   12 
 +  #define BTN_PAUSE ​  ​14 ​ // redenumit din NEXT 
 + 
 +  // === Ecran ST7735 === 
 +  #define TFT_CS ​    5 
 +  #define TFT_RST ​   4 
 +  #define TFT_DC ​    16 
 + 
 +  Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,​ TFT_DC, TFT_RST); 
 +  BluetoothA2DPSink a2dp_sink;​ 
 + 
 +  String current_song = "Fara melodie";​ 
 +  String last_displayed_song = "";​ 
 + 
 +  volatile bool playPressed = false; 
 +  volatile bool pausePressed = false; 
 + 
 +  unsigned long lastDebouncePlay = 0; 
 +  unsigned long lastDebouncePause = 0; 
 +  const unsigned long debounceDelay = 150; 
 + 
 +  unsigned long lastPlayPressTime = 0; 
 +  bool waitingForSecondClick = false; 
 + 
 +Functia urmatoare **metadata_callback()** va fi folosita pentru trimiterea de text pe ecranul TFT: 
 +  void metadata_callback(uint8_t id, const uint8_t *text) { 
 +    if (id == 0x01) { 
 +      current_song = String((char*)text);​ 
 +    } 
 +  } 
 + 
 + 
 +In functia **update_display()** vom scrie momentan numele melodiei curente: 
 +  void update_display() { 
 +    if (current_song != last_displayed_song) { 
 +      tft.fillScreen(ST77XX_BLACK);​ 
 +      tft.setTextColor(ST77XX_WHITE);​ 
 +      tft.setTextSize(1);​ 
 +      tft.setCursor(2,​ 10); 
 +      tft.println("​Redare Bluetooth:"​);​ 
 +      tft.setCursor(2,​ 30); 
 +      tft.setTextWrap(true);​ 
 +      tft.setTextSize(1);​ 
 +      tft.println(current_song);​ 
 +      tft.setCursor(2,​ 60); 
 +      tft.setTextSize(1);​ 
 +      tft.println("​Play=D12 | Pause=D14"​);​ 
 +      last_displayed_song = current_song;​ 
 +    } 
 +  } 
 + 
 +Definim urmatoarele 2 functii care vor declansa intreruperile corespunzatoare cand unul din cele 2 butoane este selectat: 
 +  void IRAM_ATTR isr_play() { 
 +    if ((millis() - lastDebouncePlay) > debounceDelay) { 
 +      playPressed = true; 
 +      lastDebouncePlay = millis(); 
 +    } 
 +  } 
 + 
 +  void IRAM_ATTR isr_pause() { 
 +    if ((millis() - lastDebouncePause) > debounceDelay) { 
 +      pausePressed = true; 
 +      lastDebouncePause = millis(); 
 +    } 
 +  } 
 + 
 +In functia **setup()** initializam interfata I2S cu un sample rate de 44.1 Mhz si un MCLK de 11.2896 Mhz, precum si pinii pe care ii folosim pentr DAC-ul CS4344. Mai apoi pornim receiver-ul Bluetooth A2DP si initializam o conexiune '​ESP32_Speaker'​. In final setam butoanele D12 si D14 ca intrari cu rezistenta de pull-up interna, pe care atasam 2 intreruperi. 
 +  void setup() { 
 +    Serial.begin(115200);​ 
 +    i2s_config_t i2s_config = { 
 +      .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),​ 
 +      .sample_rate = 44100, 
 +      .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,​ 
 +      .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,​ 
 +      .communication_format = I2S_COMM_FORMAT_STAND_I2S,​ 
 +      .intr_alloc_flags = 0, 
 +      .dma_buf_count = 8, 
 +      .dma_buf_len = 64, 
 +      .use_apll = true, 
 +      .tx_desc_auto_clear = true, 
 +      .fixed_mclk = 11289600 
 +    }; 
 +    i2s_pin_config_t pin_config = { 
 +      .mck_io_num = I2S_MCLK, 
 +      .bck_io_num = 26, 
 +      .ws_io_num = 25, 
 +      .data_out_num = 22, 
 +      .data_in_num = I2S_PIN_NO_CHANGE 
 +    }; 
 +    a2dp_sink.set_pin_config(pin_config);​ 
 +    a2dp_sink.set_avrc_metadata_callback(metadata_callback);​ 
 +    a2dp_sink.start("​ESP32_Speaker"​);​ 
 +    tft.initR(INITR_BLACKTAB);​ 
 +    tft.setRotation(1);​ 
 +    update_display();​ 
 +    pinMode(BTN_PLAY,​ INPUT_PULLUP);​ 
 +    pinMode(BTN_PAUSE,​ INPUT_PULLUP);​ 
 +    attachInterrupt(digitalPinToInterrupt(BTN_PLAY),​ isr_play, FALLING); 
 +    attachInterrupt(digitalPinToInterrupt(BTN_PAUSE),​ isr_pause, FALLING); 
 +  } 
 +   
 +In functia **loop()** se executa continuu si verifica daca butoanele D12 si D14 sunt apasate, precum actualizeaza si ecranul TFT: 
 +  void loop() { 
 +    unsigned long now = millis(); 
 +    if (playPressed) { 
 +      playPressed = false; 
 +      if (waitingForSecondClick && (now - lastPlayPressTime < doubleClickDelay)) { 
 +        a2dp_sink.next();​ 
 +        waitingForSecondClick = false; 
 +      } else { 
 +        lastPlayPressTime = now; 
 +        waitingForSecondClick = true; 
 +      } 
 +    } 
 +    if (waitingForSecondClick && (now - lastPlayPressTime > doubleClickDelay)) { 
 +      a2dp_sink.play();​ 
 +      waitingForSecondClick = false; 
 +    } 
 +    if (pausePressed) { 
 +      pausePressed = false; 
 +      a2dp_sink.pause();​ 
 +    } 
 +    update_display();​ 
 +    delay(50);​ 
 +  } 
 + 
 +===== Rezultate Obţinute ​=====
  
 <note tip> <note tip>
-Puteți avea și o secțiune ​de jurnal în care să poată urmări asistentul ​de proiect progresul proiectului.+Rezultatele obtinute au fost destul ​de satisfacatoare,​ am intampinat cateva probleme pe care nu am putut sa le rezolv din cauza DAC-ului ales, deoarece acesta are nevoie ​de un master clock extern care sa fie sincron cu celelalte semnale de pe ele, iar ESP-ul nu este capabil de a oferi corect un astfel de semnal, generand destul de mult zgomot (cred ca un MAX98357 ar fi rezolvat problema zgomotului). Rezultatul final poate fi observat in urmatorul link: 
 +https://​drive.google.com/​file/​d/​1erp1HS01shDhwGrpYLM5Av1lJeFgSRbM/​view?​usp=sharing
 </​note>​ </​note>​
  
 ===== Bibliografie/​Resurse ===== ===== Bibliografie/​Resurse =====
  
-<​note>​ +https://​github.com/​NullString1/​VWCDC 
-Listă cu documente, datasheet-uri,​ resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**+https://​schuett.io/​2013/​09/​avr-raspberry-pi-vw-beta-vag-cdc-faker
-</note> +https://itohi.com/​acoustics/​esp32-as-bluetooth-audio/​
- +
-<​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</a></html>+
  
pm/prj2025/cmoarcas/gheorghe.petrica.1747177951.txt.gz · Last modified: 2025/05/14 02:12 by gheorghe.petrica
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0