Streaming à 58824 octets par seconde

L'accès à une carte SD peut atteindre environ 6 Ko/s quand la liaison SPI est assurée par le processeur 6809 d'un ordinateur Thomson. L'objectif de ce projet est d'atteindre un débit dix fois plus élevé.

Auteur : Daniel Coulom - Site internet : Emulateur DCMOTO - Dernière mise à jour le 11 juin 2015

previous Retour à la page Bricolage

Présentation du matériel utilisé


01

Le moyen de décharger le processeur 6809 de la génération de l'horloge pour la liaison SPI est l'utilisation d'un Arduino pour lire la carte SD. L'ordinateur Thomson gère la liaison avec l'Arduino pour récupérer les échantillons de son sur 6 bits, et les joue avec le convertisseur numérique-analogique intégré à l'ordinateur (ou à l'extension musique et jeux).

La transmission est assurée par les deux ports joysticks, permettant une liaison parallèle sur 8 bits avec le port D de l'Arduino (bits D0 à D7). Le signal de contrôle permettant à l'ordinateur Thomson d'assurer le bon débit est la ligne du bouton d'action de la manette 0, utilisée dans ce cas en sortie numérique vers l'entrée D8 de l'Arduino.

Le modèle d'Arduino utilisé est ici un Mini Pro, le moins cher de la gamme équipée du processeur ATmega328P. Les autres modèles, en particulier Nano et Uno, conviennent aussi très bien. Il suffit d'adapter le schéma de câblage à la disposition des entrées-sorties.

L'interface avec la carte micro SD est un module Catalex, le même que celui des interfaces SDMOTO et SDMO. Tout autre modèle compatible avec l'Arduino convient également. Il est connecté à l'Arduino en mode SPI (entrées/sorties numériques D10 à D13).


Réalisation du montage


montage

La photo montre le montage terminé. Les composants nécessaires sont listés ci-dessous. Les prix sont donnés à titre indicatif, sans aucune garantie. Ils ont été relevé sur un site d'enchères le 9 juin 2015, avec l'option monde entier, en achat immediat port gratuit. On trouve moins cher en utilisant la version américaine du même site d'enchères.

- Arduino Mini Pro en kit  : 1,76 €
- 10 DB9 femelles a souder : 1,28 €
- Module micro SD Catalex  : 1,11 €
- 40 fils Dupont Fem-Fem.  : 1,04 €
                     Total : 5,19 €  

Pour programmer l'Arduino Mini Pro il faut ajouter l'interface USB :
- Convertisseur USB CH340  : 1,48 €

Version sans soudure :

connecteurs

Les connecteurs DB9 peuvent être des modèles à souder (à droite sur la photo), ou des modèles à picots droits pour circuit imprimé (à gauche), sur lesquels on peut connecter les fils Dupont femelles sans soudure. Notez que les coquilles métalliques des connecteurs de gauche n'ont pas été retirées. C'est acceptable pour la plupart des ordinateurs Thomson, sauf le TO8D. Les connecteurs manettes du TO8D sont en retrait par rapport au boîtier, il faut retirer les coquilles métallique des fiches DB9, comme à droite de la photo, en perçant les deux rivets.

La version sans soudure nécessite donc l'utilisation de connecteurs DB9 à picots droits (plus chers) et d'un Arduino Mini Pro avec les connecteurs déjà soudés (plus cher), ce qui double le prix du montage. Ci-dessous les connecteurs DB9F à souder et à picots droits, les fils Dupont femelle-femelle, l'Arduino Mini Pro en kit, le convertisseur USB à base de CH340 et le module Catalex pour carte micro SD.

db9f-soude     db9f-picots
dupont-wire mini-pro ch340 catalex

Programme exécuté par l'Arduino


La bibliothèque standard de l'Arduino pour accéder à la carte SD est trop lente pour atteindre des débits élevés. A la place j'utilise les modules sd_l0, sd_l1 et sd_l2 de la bibliothèque SimpleSDAudio

Ils sont utilisés pour rechercher le fichier à jouer dans le répertoire de la carte SD (dans l'exemple ce fichier est ccr.sd). On obtient l'adresse physique du début du fichier. Ensuite, pour des raisons de performances, la carte est lue séquentiellement avec la commande CMD18 (lecture multiblocs). Cette méthode est la plus rapide, mais nécessite que le fichier ne soit pas fragmenté. Chaque octet est transmis à la demande de l'ordinateur Thomson, quand le signal de contrôle passe à l'état bas.


/**************************************************\
*                S D P L A Y 5 8                   * 
*           (c) 2015 - Daniel Coulom               *  
*           http://dcmoto.free.fr/                 *
*           http://forum.system-cfg.com/           *
*--------------------------------------------------*
* Ce code est distribue gratuitement dans l'espoir *
* qu'il sera utile, mais sans aucune  garantie  et *
* sans  engager  la  responsabilité  de  l'auteur. *
* Vous  pouvez  l' utiliser,  le  modifier  et  le *
* diffuser librement, en conservant cette  licence *
* et les références de l'auteur dans   toutes  les *
* copies. L'exploitation commerciale est interdite.*
\**************************************************/

/***************************************************
*                Version 2015.06.03                *
****************************************************
Historique
2015.06.03 optimisation du code
2015.06.02 desactivation des interruptions
2015.05.23 n'utilise plus SimpleSDAudio.cpp
2015.05.19 premiere version operationnelle

Communication parallele avec un ordinateur Thomson
Lecture des donnees dans un fichier sur carte SD
Envoi des octets sur le port D a destination du
port manettes de l'ordinateur Thomson.

Connexion module Catalex pour carte micro SD
 GND --> GND
 SCK --> D13
MISO --> D12
MOSI --> D11
 VCC --> VCC (5V)
  CS --> D10

Connexion DB9 de la manette 0
   1 --> D0 (RX)
   2 --> D1 (TX)
   3 --> D2
   4 --> D3
   5 --> VCC (+5V)
   6 --> D8
   7 --> non connecte
   8 --> non connecte
   9 --> GND
   
Connexion DB9 de la manette 1
   1 --> D4
   2 --> D5
   3 --> D6
   4 --> D7
   5 --> non connecte
   6 --> non connecte
   7 --> non connecte
   8 --> non connecte
   9 --> non connecte
 
 This sketch uses the SimpleSDAudio library for SD card access.
 Visit SimpleSDAudio website for more information:
 http://www.hackerspace-ffm.de/wiki/index.php?title=SimpleSDAudio
*/

#include 
#include 
#include 

#define SD_FILE "ccr58.sd"

uint8_t  SD_L1_CardCommand(uint8_t cmd, uint32_t arg);
SD_L2_File_t AudioFileInfo;  
uint8_t string[1024];

void setup()
{
 int i;         // compteur de boucle
 int index;     //index dans le buffer
 int wait0xfe;  // indicateur d'attente octet 0xfe
 //desactiver les interruptions 
 noInterrupts(); 
 // Configure pin8 as an input (thomson request)
 pinMode(8, INPUT);
 // Configure port D as an output
 PORTD = 0x00;
 DDRD = 0xff;
 // Initialize SD card
 SD_L0_CSPin = 10;
 SD_L2_Init(string);
 SD_L0_SpiSetHighSpeed();
 // Search for file SD_FILE in Rootdir (=cluster 0),
 // search shortname files only (0x00,0x18)
 SD_L2_SearchFile((uint8_t *)SD_FILE, 0UL, 0x00, 0x18, &AudioFileInfo);
 // send CMD18 (multiblock read)
 uint32_t offset = AudioFileInfo.ActSector;    // offset = secteur
 if (SD_L1_GetCardType() != SD_CARD_TYPE_SDHC) // si carte non SDHC
     offset <<= 9;                             // offset = octet
 SD_L1_CardCommand(18, offset);         // lance CMD18
 while(SD_L0_SpiRecvByte() != 0xfe);    // attente octet $FE de debut de bloc
 uint32_t count = 0;                    // compteur d'echantillons

 while(count < AudioFileInfo.Size)      // tant qu'il reste des echantillons
 {
  // remplir le buffer avec deux octets a chaque boucle
  // (512 octets de donnees et 2 octets de CRC)
  // et envoyer un seul octet par boucle sur le port D
  index = 0;
  for(i = 0; i < 257; i++)                // boucle 257 fois
  {
   string[index++] = SD_L0_SpiRecvByte(); // octet lu sur la carte
   while(digitalRead(8) == LOW);          // wait Thomson acknowledge
   string[index++] = SD_L0_SpiRecvByte(); // octet lu sur la carte
   PORTD = string[i];                     // write byte to output port
   while(digitalRead(8) == HIGH);         // wait Thomson request
  }

  // envoyer les octets suivants (lus dans le buffer)
  // tout en attendant l'octet 0xfe
  wait0xfe = 1;
  for(i = 257; i < 512; i++)
  {
   while(digitalRead(8) == LOW);   // wait Thomson acknowledge
   if(wait0xfe)
   if(SD_L0_SpiRecvByte() == 0xfe) // lire un octet, tester 0xfe
   wait0xfe = 0;                   // raz flag d'attente 0xfe                  
   PORTD = string[i];              // write byte to output port
   while(digitalRead(8) == HIGH);  // wait Thomson request
  }
  count += 512;                    // 512 echantillons par boucle 
 }
}

void loop(void) {
}

Programme exécuté par l'ordinateur Thomson


L'initialisation consiste à masquer les interruptions et à configurer le port B du PIA6821 "musique et jeux" en sortie pour les bits 0 à 5 (entrée du convertisseur numérique-analogique), et en entrée pour le bit 6 (signal de contrôle).

La boucle de lecture envoie le signal "request to send" (bit 6 à zéro), lit un octet, le joue, remet le bit 6 à un en prévision de la prochaine transmission. Cette boucle comporte 17 cycles et joue donc 58824 échantillons par seconde.


/**************************************************\
*                S D P L A Y 5 8                   * 
*           (c) 2015 - Daniel Coulom               *  
*           http://dcmoto.free.fr/                 *
*           http://forum.system-cfg.com/           *
*--------------------------------------------------*
* Ce code est distribue gratuitement dans l'espoir *
* qu'il sera utile, mais sans aucune  garantie  et *
* sans  engager  la  responsabilité  de  l'auteur. *
* Vous  pouvez  l' utiliser,  le  modifier  et  le *
* diffuser librement, en conservant cette  licence *
* et les références de l'auteur dans   toutes  les *
* copies. L'exploitation commerciale est interdite.*
\**************************************************/

* Communication parallele 8 bits avec un Arduino
* Lecture des octets par le port manette
* Joue les echantillons 6 bits a 58824 Hz

/**************************************************\
*                Version 2015.06.03                *
\**************************************************/
* Historique
* 2015.06.03 retour au Basic en fin de morceau
* 2015.06.03 compatibilite MO et TO
* 2015.05.23 ajout de l'initialisation du PIA 6821
* 2015.05.19 suppression temporisation
* 2015.05.11 suppression du test arduino ready
* 2015.05.10 debut du projet

*------------------------------------------------------
* INITIALISATIONS
*------------------------------------------------------
  ORG   $9000     

  PSHS  U,Y,X,DP,B,A,CC  empile les registres
  ORCC  #$D0      masque les interruptions
  LDA   #$E7      valeur initialisation DP pour TO
  LDX   #$1F40    adresse pour test RAM ou ROM
  LDB   ,X        lecture adresse X
  COM   ,X        tente de modifier adresse X
  CMPB  ,X        test modification adresse X
  BEQ   INIT1     pas de difference -> TO
  COM   ,X        retablissement adresse X
  LDA   #$A7      valeur initialisation DP pour MO
INIT1
  TFR   A,DP      initialisation DP
  CLRA            A=$00 
  CLRB            B=$00 
  STD   <$CE      selectionne DDRA et DDRB
  LDB   #$7F      B=$7F 
  STD   <$CC      PA b0-7 en entree, PB b0-7 en sortie
  ORA   #$04      set b2
  STA   <$CE      selectionne PORTA
  STA   <$CF      selectionne PORTB

*------------------------------------------------------
* LECTURE SEQUENTIELLE
* 17 cycles = 58824 Hz
*------------------------------------------------------
LECT0
  ANDA  #$3F      (2) clear bit 6
  STA   <$CD      (4) request to send
  LDA   <$CC      (4) lecture octet avec b6=1
  STA   <$CD      (4) acknowledge
  BPL   LECT0     (3) nouvelle lecture

*------------------------------------------------------
* RETOUR AU BASIC
*------------------------------------------------------
  PULS  CC,A,B,DP,X,Y,U,PC retour au Basic
   
  END

Préparation du fichier de musique et utilisation du système


Pour obtenir une bonne qualité, il faut partir d'un enregitrement à plus de 58800 échantillons par seconde. Dans l'exemple c'est un fichier .wav remasterisé à 88200 échantillons par seconde. Avec CoolEdit2000 ou tout autre logiciel de traitement audio, on le transforme en mono 8 bits à 58824 échantillons par seconde. Pour le passer en 6 bits, il faut ensuite l'amplifier de 25%, puis le décaler pour que les échantillons soient dans la plage 64-127. Avec CoolEdit2000 c'est le paramètre "DC Bias adjust -25%". Il vaut mieux l'enregistrer au format .raw, de préférence au format .wav qui produirait quelques parasites lors de la lecture de l'en-tête. Vous pouvez aussi utiliser le fichier ayant servi au développement de ce projet : ccr58.zip

Le programme Basic suivant permet de jouer la musique sur un ordinateur MO ou TO. Le programme s'arrête en fin de fichier. Pour jouer à nouveau il suffit de réinitialiser l'Arduino en appuyant sur le bouton RESET et de relancer le programme Basic.

1 '================================
2' SDPLAY58.BAS
3 '================================
10 A=&H9000
20 READX$:IFX$="**"THEN90
30 POKEA,VAL("&H"+X$):A=A+1:GOTO20
90 EXEC&H9000:END
100 DATA 34,7F,1A,D0,86,E7,8E,1F
101 DATA 40,E6,84,63,84,E1,84,27
102 DATA 04,63,84,86,A7,1F,8B,4F
103 DATA 5F,DD,CE,C6,7F,DD,CC,8A
104 DATA 04,97,CE,97,CF,84,3F,97
105 DATA CD,96,CC,97,CD,2A,F6,35
106 DATA FF,**

La qualité du son produit est exceptionnelle pour un ordinateur 8 bits. Je vous conseille vivement de réaliser ce petit montage pour juger vous-même du résultat obtenu.


Complément d'information


Ci-dessous la photographie du premier prototype opérationnel et le montage définitif en fonctionnement.

01

01

Grâce au débit de transmission élevé, le même montage a aussi été utilisé pour de la vidéo avec son. Rechercher à la section Programmes du site dcmoto les démonstrations SDANIM3 Cat & Mouse et SDANIM3 Brassens.

La source principale d'informations sur ce projet de streaming avec un Arduino est le forum system-cfg : system-cfg
Vous pouvez y relire toute la genèse et demander de l'aide en cas de difficulté.