[MZ-700] Expérimentation avec le SDLEP-READER

Placez ici vos trucs et astuces, étalez sans retenue votre savoir-faire et votre science qui va nous permettre de redonner une apparence neuve et fonctionnelle à nos bouzes.

Modérateurs : Papy.G, fneck, Carl

Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Expérimentation avec le SDLEP-READER

Message par hlide »

Enfin il y aurait une autre solution que je n'ai pas testé :
- utiliser une interruption périodique pour alterner la sortie DATA IN (je passe les détails ici).
- utiliser un double-buffer d'octets lus depuis le SD de façon à ce que le SD puisse toujours lire un bloc en avance.

C'est a peu près ce que font certaines librariries qui permettent de sortir du WAV. Sauf que là, ce devrait être plus simple avec du LEP, car moins de lecture sur le SD, et juste alterner la sortie DATA IN quand la période de l'impulsion courante passe à 0 et lire l'octet suivant que quand cette période est à 0.

A partir de là, dans la boucle principale, tu peux gérer ton LCD et tes boutons comme bon te semble. Note toutefois que cette boucle doit en priorité lire à nouveau des octets LEP dans le bloc libéré quand l'interruption prévient qu'il passe au bloc suivant.
Avatar de l’utilisateur
gleike
Messages : 1341
Inscription : 16 oct. 2014 11:12
Localisation : Ludres (54710) Meurthe & Moselle

Re: [MZ-700] Expérimentation avec le SDLEP-READER

Message par gleike »

Merci pour les explications, je suis un grand débutant en arduino et langage C,
je me content pour l'instant de modifier a ma sauce les sketchs existants
et les subtilités de programmation et d'utilisation des librairies m’échappent.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Expérimentation avec le SDLEP-READER

Message par hlide »

Juste pour t'aiguiller. Le code qui suit ressemble à ce que j'ai dans l'Arduino (je n'y ais pas accès au source en dehors de mes weekends), j'ai juste détaillé la fonction 'play' qui émet les signaux DATA IN vers l'ordinateur. Repère le commentaire "moment non critique pour faire des choses qui prennent du temps". Les lignes qui suit ce commentaire peuvent pendre tout le temps qu'elles veulent - une seconde, un minute ou plus, bienque que ce ne soit pas conseillé pour le confort de celui qui l'utilise :D . Et donc à cet endroit, tu peux faire des choses un peu plus longues qui ne perturberont pas la lecture.

Code : Tout sélectionner

c++
void play()
{
  unsigned long period;                   // période d'un créneau
  unsigned long delta;                    // différence de temps écoulé max avant de passer au créneau suivant
  unsigned long lastEdge;                 // temps écoulé depuis le dernier front montant/descendant
  bool          level = HIGH;             // niveau du signal DATA IN en sortie du lecteur cassette
  bool          led = LOW;                // led bleu indiquant la fréquence de lecture des données
  char          data, next = 0;           // octets LEP lus depuis le SD
  unsigned long count = 0;                // nombre d'octets LEP lu progressivement
  unsigned long ledPeriod = 0;            // période de clignotement pour 512 octets LEP lus
  unsigned long total = file.fileSize();  // nombre total d'octets LEP à lire
  int oldProgress = -1;  // nombre de bâtons de progression précédente
  int newProgress; // nombre de bâtons de progression en cours
  
  digitalWrite(MZT_CS, LOW);  // le signal /SENSE à 0 pour prévenir le MZ que des données sont prêtes
  delayMicroseconds(2000); // laisser le temps au signal MOTOR de passer à 1 suite au signal /SENSE passé à 0

  digitalWrite(MZT_DO, level); // signal DATA IN à 1 initialement
  digitalWrite(MZT_LO, led); // témoin led éteint initialement

  lastEdge = micros(); // temps écoulé initial
  delta = 0;

  while (count < total) // lire tous les octets LEP du fichier
  {
    if (digitalRead(MZT_MI) == LOW) // MOTOR à 0, pause
    {
      digitalWrite(MZT_DO, HIGH); // signal DAT IN à 1
      digitalWrite(MZT_LO, LOW); // témoin led éteint
      
      while (digitalRead(MZT_MI) == LOW) // tant que MOTOR ne repart pas
      {
        if (Serial.available()) // mais si on demande de lire un autre fichier
        {
          digitalWrite(MZT_CS, HIGH); // signal /SENSE à 1 (lecteur non disponible)
          return; // on quitte
        }
      }
      
      lastEdge = micros(); // réinitialisation
      delta = 2000 / 16;
    }

    if (next) // l'octet LEP suivant est immediatement disponible
    {
      data = next; // le prendre
      next = 0;
      ++count;
    }
    else
    {
      data = file.read(); // sinon on le lit depuis le SD
      ++count;

      if (data < 0) // si le nouvel octet LEP annonce un front descendant à venir
      {
        // moment non critique pour faire des choses qui prennent du temps
        
        next = file.read(); // on lit en avance l'octet LEP suivant
        
        // on affiche ici la barre de progression (4 caractères avec 5 bâtons verticaux maximum par caractère)
        newProgress = (4 * 5 * count)  / total;
        if (oldProgress != newProgress)
        {
          lcd.setCursor(11 + (new_progress / 5), 1);
          lcd.write(0 + (newProgress % 5)); // les 5 caractères de code 0 à 4 représentent les bâtons de la barre de progression
          oldProgress = newProgress: 
        }
      }
    }

    /**/ if (data == 0) period = 127;   // période très longue...
    else if (data <  0) period = -data; // en valeur absolu
    else                period = +data; // en valeur absolu

    period *= 16; // convertit en microsecondes (unité 16 µs)
    
    /**/ if (data > 0) level = HIGH; // si octet LEP positif, prochain créneau à 1
    else if (data < 0) level = LOW;  // si octet LEP négatif, prochain créneau à 0
    
    while (micros() - lastEdge < delta); // on fait une pause dans la période souhaité
    
    digitalWrite(MZT_DO, level); // et on met à jour le créneau en sortie DATA IN
    
    lastEdge = micros(); // met à jour la référence de temps pour la période
    delta = period; // et la période suivante

    ++ledPeriod;
    
    if (ledPeriod & 512) // le led témoin est alterné tous les 512 octets LEP traités
    {
      led = !led; // on alterne le niveau du signal du témoin led
      digitalWrite(MZT_LO, led);
    }
  }
  digitalWrite(MZT_LO, 0); // c'est terminé, plus de témoin led.
  digitalWrite(MZT_CS, HIGH); // signal /SENSE à 1 (lecteur non disponible)
}
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Expérimentation avec le SDLEP-READER

Message par hlide »

Totor le Butor a écrit : 18 févr. 2018 19:16 Il y a une toute petite subtilité dans le montage, la sortie du LS00 est toujours à 1 car on a toujours un 0 sur au moins une des 2 entrées SAUF quand SENSE passe à 0.
En effet, l'entrée 13 du LS00 reste à 1 pendant environ 2 mS à cause de C220 et R33.
A ce moment on récupère un 1 sur la pin 12 du LS00 (et donc un 0 sur le PRESET) ainsi que sur le CLEAR du 7474 ce qui positionne Q à 1 et /Q à 0, après ~2 ms le PRESET repasse à 1, le CLEAR est lui à 1, ce qui met la bascule en position pour accepter l'horloge et faire bouger les sorties Q et /Q au rythme de l'horloge /2 (la bascule est câblée en diviseur par 2, /Q reliée à l'entrée D).
On parle bien de 2 millisecondes là ?

Ok, je vais avoir besoin de tes conseils. Je m'explique.

Je voudrais implémenter sur l'Arduino et ce spécifiquement pour un MZ une alternative pour le transfert. Le LEP reste en place car il a son utilité (les modes turbos ne peuvent pas fonctionner avec le MZ-80 K avec le turboloader mais le mode conventionnel fonctionne), mais je compte pouvoir transférer aussi du MZF via un autre protocole passant au moins par les mêmes signaux, à savoir : READ (DATA IN), WRITE (DATA OUT), SENSE et MOTOR.

Au lieu d'un signal READ en sortie d'Arduino, j'aimerais utiliser deux en sortie d'Arduino, l'un servirait à placer les bits d'un octet à transférer et l'autre à cadencer le passage au bit suivant.

Légende:
SC : /SENSE
SD : READ (DATA IN)

|-| : période la plus courte possible pour que l'Arduino positionne la nouvelle valeur de SD après avoir basculé la valeur de SC et que le MZ puisse lire la nouvelle valeur de SD juste après la détection du front sur SC.
|+| : période suffisamment longue pour laisser le temps au MZ de lire la nouvelle valeur de SD ou à l'Arduino de récupérer l'octet suivant. Cette période peut servir à faire des mises à jour IHM.

Code : Tout sélectionner

  __         _____         _____         _____         _____
SC  \   0  \/  1  \/  0  \/  1  \/  0  \/  1  \/  0  \/  1  \/ ...
     \_____/\     /\_____/\     /\_____/\     /\_____/\     /\
      
     |++++++|-|++++|-|++++|-|++++|-|++++|-|++++|-|++++|-|++++|-| ...
  ____         _____  _____                _____         _____
SD    \   0  \/  1  \/  1  \/  0  \/  0  \/  1  \/  0  \/  1  \/ ...
       \_____/\     /\     /\_____/\_____/\     /\_____/\     /\
       |           6h              |           5h              |


La bascule SC pourrait également se faire après le changement de la valeur de SD et non avant mais je ne sais pas ce qui est plus avantageux.

Dans un premier temps, je pensais utiliser le signal /SENSE. Sauf que le MZ ne peut lire directement la valeur de /SENSE. Le seul signal qu'il peut lire, c'est MOTOR (PC4 du 8255) qui lui est connecté au LS74. Sauf qu'il y a cette histoire de 2 millisecondes quand /SENSE passe de H à L.

Questions :

1) Si /SENSE passe de L à H, la sortie Q passe à L "immédiatement" ?

2) Si /SENSE passe de H à L, la sortie Q passe à H "immédiatement" pour toute la période de 2 millisecondes qui suit la bascule de /SENSE, indépendemment du signal CL du LS74 ?

Si oui pour les deux questions, je peux alors :

- utiliser /SENSE comme signal SC et READ comme signal SD,
- utiliser PC4 du 8255 (MOTOR) pour lire le signal SC sur le MZ en signal inversé,
- utiliser PC5 du 8255 (READ) pour lire le signal SD sur le MZ,
- si la bascule SC se fait APRES la nouvelle valeur SD, une simple lecture sur le MZ donnerait à la fois la détection d'un front et la nouvelle valeur.

J'ai tout bon ?
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [MZ-700] Expérimentation avec le SDLEP-READER

Message par hlide »

Dans le même ordre d'idée mais optionnel, si je veux sauver un fichier, je pourrais utiliser le même principe :

- Durant le transfert, /SENSE à 0
- SC : MOTOR en sortie du MZ et en entrée de l'Arduino
- SD : WRITE (DATA OUT) en sortie du MZ et en entrée de l'Arduino

Sur le MZ, on lance une routine qui attend que le signal /SENSE passe à 0, puis lance le tranfert. L'Arduino capte les fronts du SC provoqué par le MZ qui bascule PC3 du 8255 à 0 puis à 1 pour créer le front du SC. L'arduino lit la valeur de SD depuis le PC1 du 8255. Cependant, je vois un léger problème avec les delais dont l'Arduino peut être coupable (le MZ lui ne fait ques des accès mémoire donc il n'est pas sujet à des delais indéterminés).

L'autre possibilité, c'est de considérer que l'Arduino est toujours le maître et que c'est lui qui donne la cadence à cause des delais dûs aux accès du SD et des mises à jour IHM. Et donc ce serait le même signal SC pour la lecture ou l'écriture :

- SCK =/SENSE en sortie de l'Arduino et en entrée du MZ (PC4 du 8255)
- SDI = READ (DATA IN) en sortie de l'Arduino et en entrée du MZ (PC5 du 8255)
- SDO = WRITE (DATA OUT) en entrée de l'Arduino et en sortie du MZ (PC1 du 8255)
Répondre