WM8805 receiver

Peter52

Established Member
25 November 2010
202
Όχι, είναι μέσα στο Loop και λειτουργεί σε ορισμένα χρονικά διαστήματα 2 δευτερολέπτων.

Code:
Loop
{

unsigned long currentMillis = millis();

  if (currentMillis - previousMillis_3 >= interval_3){
   
    checkWM8805();
    
    }


Απλά στα 2 δευτερόλεπτα προφταίνω να στείλω με το τηλεχειριστήριο το δεύτερο ψηφίο του αριθμού της εισόδου και να λειτουργούν επαναλήψεις πλήκτρων (πάτημα συνέχεια).
 

lemon

Supreme Member
3 March 2009
4,041
Οπότε με αυτό το κολπάκι έλυσες και το θέμα διψήφιου κωδικού από το τηλεχειριστήριο.
Ευχαριστώ Πέτρο.
 

Peter52

Established Member
25 November 2010
202
Re: Απάντηση: WM8805 receiver

Να προσθέσω ότι και οι ενκόντερς είχαν πρόβλημα γιατί έμπαινε το πρόγραμμα σε βρόγχο και δεν μπορούσα να ρυθμίσω τίποτα.

Η μεταβλητή που ορίζω είναι const long interval = 2000; στην δική μου περίπτωση. Δεν έχω δοκιμάσει μικρότερες τιμές, αλλά και κάθε 2 δευτερόλεπτα δεν είναι και τόσο κρίσιμο το διάστημα.
 

lemon

Supreme Member
3 March 2009
4,041
Ναι για τους encoder και το θέμα που είχες το είχαμε συζητήσει και προσωπικά εάν θυμάσαι.

Γενικά όταν ξεμπερδέψει ο καθένας μας με τα όποια μικροπροβλήματά του, θα πρέπει να ξαναδούμε τον κώδικα, με περισσότερη προσοχή γιατί έχει ζουμί η παραμετροποίηση του 8805.
Τόσο καιρό λέγαμε ότι δεν δύναται να κάνει δειγματοληψία, παρά μόνο μέσω SPDSTAT και αυτό με ομάδες και να που τώρα ξεπεράσαμε και αυτό το εμπόδιο...

Να βρούμε και τρόπο να κάνει stand by όταν δεν έχει σήμα, παραμετροποιήσιμο θα είναι και αυτό με κάποιον τρόπο. Είναι καλό να μη δουλεύει όταν για παράδειγμα σε σένα δουλεύει μια αναλογική πηγή ή μία usb πηγή γενικότερα.
Δεν είναι θέμα αλληλεπίδρασης καθότι ο πολυπλέκτης το κόβει το σήμα, είναι θέμα ότι κάθε ψηφιακό που δουλεύει εκπέμπει στο τριγύρω κύκλωμα και ανεβαίνει η όποια παρεμβολή...
 
Αν θυμάμαι καλά το να μη δουλεύει όταν δεν χρειάζεται είναι εύκολο.. απλά αλλάζεις την κατάσταση του reset pin όταν δεν το χρειάζεσαι (δεν θυμάμαι αν θέλει από high σε low ή το αντίθετο).

Αλλά συμφωνώ ότι θέλει ένα γερό ξανα-πέρασμα ο κώδικας.. λογικά θα μπορούν να γίνουν κι άλλα "χαριτωμένα" με λίγο ψάξιμο..
 

Peter52

Established Member
25 November 2010
202
Re: Απάντηση: WM8805 receiver

Για την περίπτωση που γνωρίζουμε σίγουρα ότι η είσοδος είναι αναλογική τότε στην εντολή επιλογής θα συμπεριλάβουμε και την εντολή POWER_OFF για το 8805 και ενδεχομένως να κάνουμε MUTE στο DAC ή και να του κλείνουμε τελείως την τροφοδοσία είτε με ρελέ είτε σήμα στην βάση του LDO. Έχω δει τέτοια κυκλώματα στα datasheet 1085.

Πάντως δεν έχω καταφέρει να έχω αξιόπιστες πληροφορίες από την R16. Μάλλον εξαρτάται από την συνδεδεμένη συσκευή όπου ο κάθε κατασκευαστής κάνει ότι θέλει. Για παράδειγμα ένα DVD PHILIPS (κατασκευής TOSHIBA) δίνει εναλλάξ πληροφορία Β1111 και Β0000 ή Β0010 ανάλογα αν είναι CD ή DVD.

Επίσης δεν έχω κάνει δοκιμές εκτός εργαστηρίου. Οι πληροφορίες που έχω είναι από το Serial Monitor.
 
Δεν έχω καταφέρει να βρω χρόνο να διαβάσω σωστά το datasheet.. Μπορεί να παίζει ρόλο κατά πόσο το datastream δηλώνεται ως pro ή consumer. Σε κάποια τσιπάκια παίζουν και τέτοια..

Πάντως άκρη θα βρεθεί, δεν είναι στο χέρι του.
 

lemon

Supreme Member
3 March 2009
4,041
Πέτρο είναι ακριβώς αυτό που έπαθα το ΣΚ, έπεφτα σε διαρκή λάθη εξαιτίας ατασθαλιών των πηγών και όπως είπα ενώ τα παράτησα στο εργαστήριο, στο σαλόνι βάζοντας το dvd του μικρού είδα τα 44/48 σωστά.

Έχω κάποιες απορίες που εάν γνωρίζετε θα ήθελα μια απάντηση.
1) Για παράδειγμα όταν στο 8805 δηλώνεται η registry 16, με την εντολή variable = (ReadRegister(wm8805, 16), αυτό σημαίνει ότι θα διαβάσει υποχρεωτικά τα bit 27...24 με την ανάστροφη σειρά και δεν θα μπερδευτεί καθόλου με τα λοιπά bit 28...?
2) Ακολούθως όταν έχουμε δήλωση της reg17 στα bit 39...36, θα διαβάσει και εδώ τα συγκεκριμένα (θυμάμαι ότι εκτός από μηδεν δεν είδα κάτι άλλο)
3) Λογικά ανάμεσα στα (1) & (2) θα πρέπει να προτιμήσουμε το (2) και όχι τη reg16 γιατί αναφέρεται στο original sampling
4) Γιατί μερικοί βάζουν μάσκα όταν διαβάζουν τα (1), (2)? Προσωπικά και που έβαλα μάσκα δεν είδα διαφορά...
 

Peter52

Established Member
25 November 2010
202
Re: Απάντηση: WM8805 receiver

Με την εντολή ReadRegister(wm8805, 16) διαβάζουμε όλη την R16 ή και όποια άλλη, ήτοι παίρνουμε 8 δυαδικά ψηφία Β10101010. Από το datasheet βλέπουμε ποια είναι τα ψηφία που μας ενδιαφέρουν. Στην R16 τα ψηφία που μας ενδιαφέρουν είναι, όπως το βλέπουμε, τα τρία τελευταία, γιαυτό και έχουμε συνολικά 16 αριθμούς 'η cases. Για να πάρεις συγκεκριμένο ψηφίο πρέπει να διαβάσεις μετά την μεταβλητή με την εντολή bitRead(Μεταβλητή, θέση) ή να προσθέσεις με &= και 0 στα σημεία που θέλεις να κρύψεις.

Παράδειγμα χ = Β10011011 και θέλεις τα τρία τελευταία, οπότε ψ = (χ &= Β00000111).
Αν θέλεις ένα μόνο ψηφίο μπορεί με το bitRead(χ, 2) αν ενδιαφέρεσαι για το δεύτερο ψηφίο.
 

lemon

Supreme Member
3 March 2009
4,041
Ωραίο Πέτρο κατανόησα τι θέλεις να γράψεις και πως πρέπει να παραμετροποιηθεί.

Αλλά έχω την εντύπωση ότι ο το pdf της προδιαγραφής που μας έβαλε ο Δημήτρης λέει στη σελ. 5 ότι για το μεν Sampling Frequency αναφέρεται όχι στα τελευταία αλλά στα πρώτα 4ρα (bit 24...27) και μάλιστα με ανάστροφη φορά. Για το δε Original Sampling Frequency είναι τα τέσσερα τελευταία bit [36...39].

Η ανάστροφη σειρά φαίνεται στη σελ.6, όπου για το Sampling Frequency για τα 48K ζητά το 0100 που νομίζω είναι με σειρά bit 27->24, ενώ για το Original Sampling Frequency στη σελ. 7, για τα 48K ζητά το 1011 που νομίζω είναι με σειρά bit 39->36.

Για ρίξτε μια ματιά για ανατροφοδότηση... και στην περίπτωση που το έχω κατανοήσει σωστά πως αλλάζεις σε ανάστροφη σειρά το read? Μήπως με y=(x <=B00001111) για παράδειγμα;
 
Για αρχή, όπως το καταλαβαίνω, μας ενδιαφέρει να διαβάσουμε το "sampling frequency" και όχι το "original sampling frequency" γιατί το δεύτερο είναι ουσιαστικά προαιρετικό και αναφέρεται στην αρχική δειγματοληψία του σήματος πριν το επεξεργαστεί η πηγή που το δίνει στο 8805.. οπότε, δεν μας κάνει.

Όσο αφορά τη σειρά των bits, το 60958-3 τα δίνει "ανάποδα", σε σχέση με το πως αποθηκεύονται στους registers. Δηλαδή για παράδειγμα:

Τα 32KHz αντιστοιχούν στα Bits 24 - 27 : "1100"

Στον κώδικα βλέπουμε ότι για να δείξει "32KHz" πρέπει να διαβάσει στον register 16 το value "B0011".

Αυτό γίνεται επειδή το πρώτο bit (στην περίπτωσή μας το 24) είναι τέρμα δεξιά.

Επίσης απ' ότι βλέπω, όλα αυτά ισχύουν αν το σήμα είναι τύπου consumer (όπως φαίνεται στο πρώτο bit του R13). Αν είναι pro, το ίδιο το 8805 λέει ότι μπορεί να μην το υποστηρίζει σωστά και να δείχνει λάθος ενδείξεις.
 

lemon

Supreme Member
3 March 2009
4,041
Οπότε τι εστί consumer και τι εστί pro, στο πρωτόκολλο επικοινωνίας spdif?

Με λίγα λόγια θα αναμένουμε σωστή δειγματοληψία από ένα εμπορικό cd ή dvd player αλλά, άλλα τι άλλων σε μια προ συσκευή όπως η emu0404 και τα συναφή;
Μάλλον ναι, αν και καλό θα ήταν να ξέραμε εάν τα προ έχουν και αυτά συγκεκριμένες τιμές (θα μπορούσε να προβλεφθεί όπως έκανα στην περίπτωση της emu).
 
Πρακτικά είναι ίδια πράγματα (σαν data payload), ένα flag αλλάζει στα pro (και κάποιες λεπτομέρειες ακόμα, π.χ. δεν υπάρχει copyright bit).

Αλλά το 8805 σου λέει ότι είναι consumer εξάρτημα, οπότε "YMMV" που λένε και οι φίλοι μας..

Προσωπικά έχω πετύχει s/pdif transmitters να δίνουν "pro" σήμα, είτε με λόγο είτε χωρίς.. είναι λίγο χάος..

Οπότε το πιο φρόνιμο είναι να διαβάζουμε το bit του pro και ανάλογα να δίνουμε σήμα για το κατά πόσο είναι αξιόπιστες οι πληροφορίες που βλέπουμε από τους λοιπούς registers.

--- Αυτόματη συγχώνευση μηνύματος ---

Btw, κατά σύμπτωση αυτές τις μέρες την ψάχνω λίγο για receiver με AK4118, το οποίο υποστηρίζει κανονικά και consumer και pro modes.. Εύκολο φαίνεται στην υλοποίηση..
 

Peter52

Established Member
25 November 2010
202
Τελικά έφτασα σε κάποιο σημείο το ψάξιμο και τουλάχιστον σε συνθήκες εργαστηρίου με τρεις πηγές 44.1, 48 και 96 KHz έχω κανονικές ενδείξεις στην οθόνη, καθώς επίσης και σε περίπτωση που δεν υπάρχει σήμα (Unlocked). Επισυνάπτω την ρουτίνα ελέγχου του 8806 για δικές σας δοκιμές. Απαιτείται προφανώς προσαρμογή.

Code:
void checkWM8805()
{
    previousMillis_3 = millis();

    SPDSTAT = ReadRegister(wm8805, 12);
    
    SR = ReadRegister(wm8805, 16);
    srt = (SR &= B00001111);

    switch (srt) {
      
      case B0001:
        Serial.println("not indicated");
        break;

      case B0011:
        /////Serial.println("32 kHz");
        if (strType != "32 kHz") {
            strType = "32 kHz";
            Serial.println(strType);
            screenCurrent(); }
        break;

      case B1110:        
          ///Serial.println("192 kHz");
          if (strType != "192 kHz") {
            strType = "192 kHz";
            Serial.println(strType);
            screenCurrent(); }
        break;

      case B1010:
        ///Serial.println("96 kHz");
        if (strType != "96 kHz") {
            strType = "96 kHz";
            Serial.println(strType);
            screenCurrent(); }        
        break;

      case B0010:
        ///Serial.println("48 kHz");
        if (strType != "48 kHz") {
            strType = "48 kHz";
            Serial.println(strType);
            screenCurrent(); }
        break;

      case B0110:
        ///Serial.println("24 kHz");
        if (strType != "24 kHz") {
            strType = "24 kHz";
            Serial.println(strType);
            screenCurrent(); }
        break;
      
      case B1100:       
        ///Serial.println("176.4 kHz");
        if (strType != "176.4 kHz") {
            strType = "176.4 kHz";
            Serial.println(strType);
            screenCurrent(); }
        break;

      case B1000:
        ///Serial.println("88.2 kHz");
        if (strType != "88.2 kHz") {
            strType = "88.2 kHz";
            Serial.println(strType);
            screenCurrent(); }
        break;

      case B0000:
      
        if (SPDSTAT == 80) {
          ///Serial.println("88.2 kHz");
          if (strType != "88.2 kHz") {
            strType = "88.2 kHz";
            Serial.println(strType);
            screenCurrent(); }
          break;
          }
        if (SPDSTAT == 4) {
          ///Serial.println("176.4 kHz");
          if (strType != "176.4 kHz") {
            strType = "176.4 kHz";
            Serial.println(strType);
            screenCurrent(); }
           break;
          }
        if (SPDSTAT == 64) {
          ///Serial.println("192 kHz");
          if (strType != "192 kHz") {
            strType = "192 kHz";
            Serial.println(strType);
            screenCurrent(); }
           break;
          }
       else {
            ///Serial.println("44.1 kHz");
            if (strType != "44.1 kHz") {
            strType = "44.1 kHz";
            Serial.println(strType);
            screenCurrent(); }
          }       
        break;
    }
    uint8_t INTSTAT = ReadRegister(wm8805, 11); // poll (and clear) interrupt register;
    uint8_t SPDSTAT = ReadRegister(wm8805, 12);
    uint8_t SampleRate = (SPDSTAT >> 4) & 0x07;
    if (INTSTAT != 0 || SampleRate != SampleRateOld) {
      // If something has changed do a screen refresh.
      Serial.print("INTSTAT:");Serial.println(INTSTAT,HEX);
      Serial.print("SPDSTAT:");Serial.println(SPDSTAT,HEX);
      Serial.print("Sample rate:");
      switch (SampleRate) {
        case 0x03:
          ///Serial.println("32 kHz");
          if (strType != "32 kHz") {
            ///strType = "32 kHz";
            ///Serial.println(strType);
            ///screenCurrent(); 
            }
          break;
        case 0x02:
          ///Serial.println("44/48 kHz");
          
          
          if (strType != "44/48 kHz") {
            ///strType = "44/48 kHz";
            ///Serial.println(strType);
            ///screenCurrent(); 
            }
          break;
        case 0x01:
          ///Serial.println("88/96 kHz");
          if (strType != "88/96 kHz") {
            ///strType = "88/96 kHz";
            ///Serial.println(strType);
            ///screenCurrent(); 
            }
          break;
        case 0x00:
          ///Serial.println("192 kHz");
          if (strType != "192 kHz") {
            ////strType = "192 kHz";
            ///Serial.println(strType);
            ///screenCurrent(); 
            }
          break;
        default:
          ///Serial.println("Unlocked");
          if (strType != "Unlocked") {
            strType = "Unlocked";
            Serial.println(strType);
            screenCurrent(); 
            }
          break;
      }
      
      SampleRateOld = SampleRate;
    }
    if (SampleRate & 0x04) {

      strType = "Unlocked";
       screenCurrent();



        
      // If this is unlocked then try and switch around normal and 192khz mode
      // until it locks. That is kinda hackish but it seems to work.
      if (toggle) {
        Serial.println("trying 192 kHz mode...");
        ///strType = "Unlocked";
        ///screenCurrent();
        WriteRegister(wm8805, 6, 8);    // set PLL_N to 8
        WriteRegister(wm8805, 5, 12);   // set PLL_K to 0C49BA (0C)
        WriteRegister(wm8805, 4, 73);   // set PLL_K to 0C49BA (49)
        WriteRegister(wm8805, 3, 186);  // set PLL_K to 0C49BA (BA)
        WriteRegister(wm8805, 29, 1);   // This might not be needed set SPD_192K_EN to 1
        toggle = 0;
      } else {
        Serial.println("trying normal mode...");
        ////strType = "Unlocked";
        WriteRegister(wm8805, 6, 7);    // set PLL_N to 7
        WriteRegister(wm8805, 5, 54);   // set PLL_K to 36FD21 (36)
        WriteRegister(wm8805, 4, 253);  // set PLL_K to 36FD21 (FD)
        WriteRegister(wm8805, 3, 33);   // set PLL_K to 36FD21 (21)
        WriteRegister(wm8805, 29, 0);   // This might not be needed set SPD_192K_EN to 0
 
        toggle = 1;
      } // if toggle
      delay(100);  // Give some time for WM8805 to lock
    }
  }

Καλές δοκιμές!!!
 

Peter52

Established Member
25 November 2010
202
Τελικά μάλλον το πρόβλημα βρήκε την λύση του.
Το σύστημα δουλεύει απρόσκοπτα και για όσες συσκευές το δοκίμασα παίρνω την σωστή συχνότητα δειγματοληψίας.
Βέβαια δεν έχω συσκευές για όλες τις συχνότητες αλλά πιστεύω αν βρει κάποιος περίπτωση που δεν λειτουργεί ο κώδικας να μας το πει να το ψάξουμε.

Η αλήθεια είναι ότι ο κώδικας είναι λίγο χύμα και θέλει κάποιο συμμάζεμα από πιο ειδικούς.
 

lemon

Supreme Member
3 March 2009
4,041
Σήμερα σε δοκιμές που έκανα παρατήρησα για πρώτη φορά, αυτό που είχες γράψει παλιότερα Πέτρο, δηλ. ότι ακούς κρότους ακόμη και όταν είναι ξεκλείδωτο.
Για πρώτη φορά παρατήρησα το ίδιο φαινόμενο μετά από αλλαγές που έκανα σε δοκιμαστικό κώδικα.
Τελικά αυτό οφείλεται σε στιγμιαία κλειδώματα-ξεκλειδώματα της παρακάτω ρουτίνας:
Code:
 if (SampleRate & 0x04) {
      // If this is unlocked then try and switch around normal and 192khz mode
      // until it locks. That is kind a hackish but it seems to work.
      if (toggle) {
        Serial.println("trying 192 kHz mode...");
        WriteRegister(wm8805, 6, 8);    // set PLL_N to 8
        WriteRegister(wm8805, 5, 12);   // set PLL_K to 0C49BA (0C)
        WriteRegister(wm8805, 4, 73);   // set PLL_K to 0C49BA (49)
        WriteRegister(wm8805, 3, 186);  // set PLL_K to 0C49BA (BA)
        //WriteRegister(wm8805, 29, 1);   // This might not be needed set SPD_192K_EN to 1
        toggle = 0;
        delay(500);
      } 
      else {
        Serial.println("trying normal mode...");
        WriteRegister(wm8805, 6, 7);    // set PLL_N to 7
        WriteRegister(wm8805, 5, 54);   // set PLL_K to 36FD21 (36)
        WriteRegister(wm8805, 4, 253);  // set PLL_K to 36FD21 (FD)
        WriteRegister(wm8805, 3, 33);   // set PLL_K to 36FD21 (21)
        WriteRegister(wm8805, 29, 0);   // This might not be needed set SPD_192K_EN to 0
        toggle = 1;
        delay(500);
      } // if toggle
     }

Δεν είχα παραπάνω χρόνο, το έχω αφήσει επίτηδες ως είχε για να το δω καλύτερα, αλλά υποψιάζομαι ότι έχει σχέση με την εντολή της γραμμής WriteRegister(wm8805, 29, 0); // This might not be needed set SPD_192K_EN to 0
Αυτή συνήθως την έχω comment.

Αυτή η ρουτίνα στον κώδικα που είχαμε εξ'αρχής είναι λίγο διαφορετική και ποτέ δεν συμπεριλάμβανε τις δύο γραμμές παραμετροποίησης SPD_192K_EN

Code:
if (bitRead(INTSTAT, 0)) {                                         // UPD_UNLOCK
    SPDSTAT = ReadRegister(wm8805, 12);
    Serial.print("UPD_UNLOCK: ");
    if (bitRead(SPDSTAT,6)) {
      delay(500);
       // try again to try to reject transient errors
      SPDSTAT = ReadRegister(wm8805, 12);
      if (bitRead(SPDSTAT,6)) {
      
        Serial.println("S/PDIF PLL unlocked");
        
        // switch PLL coeffs around to try to find stable setting
        
        if (toggle) {
          Serial.println("trying 192 kHz mode...");
          fs = 192;
          WriteRegister(wm8805, 6, 8);                  // set PLL_N to 8
          WriteRegister(wm8805, 5, 12);                 // set PLL_K to 0C49BA (0C)
          WriteRegister(wm8805, 4, 73);                 // set PLL_K to 0C49BA (49)
          WriteRegister(wm8805, 3, 186);                // set PLL_K to 0C49BA (BA)
          toggle = 0;
          delay(500);
        }
        else {
          Serial.println("trying normal mode...");
          WriteRegister(wm8805, 6, 7);                  // set PLL_N to 7
          WriteRegister(wm8805, 5, 54);                 // set PLL_K to 36FD21 (36)
          WriteRegister(wm8805, 4, 253);                // set PLL_K to 36FD21 (FD)
          WriteRegister(wm8805, 3, 33);                 // set PLL_K to 36FD21 (21)
          toggle = 1;
          delay(500);
        } 
      }

Οπως θα δεις επαναλαμανει δυο φορές το
Code:
SPDSTAT = ReadRegister(wm8805, 12);
      if (bitRead(SPDSTAT,6)) {
και όπως αναφέρει το κάνει αυτό για να εξαλείψει λάθη κατά τη μετάβαση...
 
Last edited:

Peter52

Established Member
25 November 2010
202
Re: Απάντηση: WM8805 receiver

Χτές έκανα μια δοκιμή με μερικά αρχεία που βρήκα σε διάφορες αναλύσεις. Ο κώδικας όπως τον έχουμε, αν αυτό φταίει, δεν δείχνει πάνω από 96 KHz. Δεν ξέρω ακόμη αν φταίει το Touch που δίνει το spdif σήμα. Έχουμε ψάξιμο για του χρόνου.

Καλή χρονιά σε όλους.
 

lemon

Supreme Member
3 March 2009
4,041
Καλή Χρονιά σε όλους.

Πέτρο, ούτε και θα βγάλουμε άκρη.
Ο κώδικας έτσι όπως είναι τώρα, σε κόνσουμερ dvd player λειτουργεί άψογα για δειγματοληψίες 44.1/48KHz.
Όταν όμως πας σε κατασκευές που δίνουν το εύρος 44-192 από spdif, ξεφεύγεις από τις τυπικές εμπορικές κατασκευές και πηγαίνεις, συνήθως σε συσκευές όπως είναι οι κάρτες ήχου, τα media player, το touch κ.ο.κ
Και σε αυτά από ότι είδα, μάλλον γίνεται της "ελευθέρας".
Σε emu0404 δίνει σωστά πάντα τα 48 & 96, τα λοιπά είναι σε μια μόνιμη τυχαία κατάσταση, σε δύο media player που δοκίμασα αυτά δίνουν καρφωτή έξοδο στα 48KHz.

Οπότε μάλλον καλά είναι ως έχει...διαφορετικά ξεχνάμε τη χωριστή δειγματοληψία και επικεντρωνόμαστε στις διπλές 44/48, 88/96, 176/192 ως εύρος και είμαστε πάντα 100% μέσα!