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.
[MZ-700] Expérimentation avec le SDLEP-READER
Modérateurs : Papy.G, fneck, Carl
- gleike
- Messages : 1349
- Inscription : 16 oct. 2014 11:12
- Localisation : Ludres (54710) Meurthe & Moselle
Re: [MZ-700] Expérimentation avec le SDLEP-READER
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.
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.
Re: [MZ-700] Expérimentation avec le SDLEP-READER
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 . 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)
}
Re: [MZ-700] Expérimentation avec le SDLEP-READER
On parle bien de 2 millisecondes là ?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).
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 ?
Re: [MZ-700] Expérimentation avec le SDLEP-READER
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)
- 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)