mercredi 7 août 2013

msp430 launchpad, partie 11

génération signal NTSC 256x230 pixels

Dans la conclusion de la partie 8 de cette série de chroniques, je mentionnais que j'entrevoyais la possibilité d'utiliser une mémoire RAM SPI Microchip 23K256 comme mémoire vidéo pour augmenter la résolution. Dans cette chronique je présente le résultat des mes expérimentations à ce sujet. Avec le circuit et le logiciel présenter ici j'obtiens une résolution de 256x2301 pixels en noir et blanc. La mémoire 23K256 possède 32Ko mais le buffer vidéo n'en utilise que 256/8*230=7360. Tous les fichiers du projet sont sur https://github.com/Picatout/ntsc-3

Le circuit


P2.1 est la sortie synchronisation NTSC qui se trouve à utiliser la minuterie TIMER_A1 pour générer un signal PWM à la fréquence du balayage horizontal. La sortie P2.0 est utilisée pour générer un signal de blanking qui consiste à mettre la cathode de D1 à 0 volt pendant la phase de synchronisation. La diode D1 a pour rôle d'empêcher que le voltage du signal vidéo n'abaisse le niveau de tension en bas du niveau noir puisque le signal à la sortie SO du 23K256 peut tirée la sortie vidéo vers le haut mais pas vert le bas. Le signal vidéo est récupéré à la sortie de la mémoire 23K256 à la broche 2. P1.5 est le signal clock qui contrôle l'interface SPI de la RAM tandis que P1.7 est le MOSI ( MCU vers RAM) et P1.6 le MISO ( RAM vers MCU). P2.2 contrôle le chip select de la RAM.

Voici une capture à l'oscilloscope du signal vidéo qui est générer par ce circuit.


Le niveau plus que noir représente les seuils avant (front porch) et arrière (back porch) du standard NTSC. Le balayage est de type progressif 263 lignes mais seulement 230 lignes sont visible à l'écran. Le fichier main.h contient les constantes reliées au signal vidéo.

Logiciel

Le fichier spi-ram.c contient le code pour l'interface avec la RAM SPI et peut-être utilisé dans d'autres projets sans changement. Le démo ne s'en sert que pour l'initialisation de l'interface SPI.

Le démo consiste à copier l'image (fonction copy_img_2_sram dans le fichier main.c) qui est en mémoire flash du MCU dans la mémoire 23K256 pour l'afficher et ensuite à imprimer une ligne de texte en bas de l'écran. Le message est MSP430G2553 B/W NTSC VIDEO DEMO. 256X230. l'image du loup est contenu dans le fichier loup.h et fait 176x233 pixels on a donc 2 bandes noires de chaque côté. Voici une photo prise de mon téléviseur montrant le résultat.


Dans le dossier images du dépôt github se trouve l'image originale loup.bmp, le fichier loup.txt qui est le data extrait de loup.bmp et finalement le script openEuphoria que j'ai utilisé pour convertir loup.txt en loup.h, cvt-loup.ex. L'image en tons de gris est convertie en noir et blanc en utilisant l'algorithme de Floyd-Steinberg.

Contrairement au démo de la partie 8 celui-ci a recours à la programmation assembleur (nstsc-isr.asm) pour les interruptions du TIMER A1 et ce afin d'optimiser la vitesse d'exécution car l'essentiel du temps processeur se passe dans ta1_ccr0_isr et ta1_ccrx_isr.

Limitations

Le principal problème avec ce système est la vitesse (lenteur) avec laquelle on peut mettre à jour la mémoire SRAM. En effet on ne peut l'accéder que pendant la phase de synchronisation verticale. Ce qui donne environ 1 milliseconde à toute les 16 millisecondes. Et pendant cette milliseconde on ne lit/écris qu'un maximum de 32 octets par interruption ta1_ccr0_isr. Dans la première version du démo, la fonction draw_char utilisait les fonctions dot et erase_dot pour écrire dans la mémoire SPI RAM un pixel à la fois. Ça prenait plusieurs secondes pour écrire une seule ligne de texte. J'ai donc modifier le code pour utiliser un tampon en mémoire MCU (disp_buffer) où la chaîne complète est écrite avant de transférer le disp_buffer dans la 23K256 ligne par ligne. Avec cette méthode ça prend une fraction d'une seconde. A cause de cette lenteur écrire un jeux vidéo sur ce système présenterais un défis. Une solution possible est d'aligner les sprites sur les octets et d'utiliser une dimension horizontale multiple de 8 bits, i.e. 8x8, 8x16, 16x16. Il faut comprendre cependant que ça prend le même temps de mettre à jour une grille de 8x8 que 16x8. Le transfert entre MCU et SPI RAM se faisant par ligne de 32 octets. Comme le programme principal dispose de très peut de temps pour faire son travail aligner les sprites sur les octets éviterais d'avoir à shifter les bits à gauche ou à droite comme c'est fait dans draw_char. On peut aussi utiliser un buffer vidéo double dans la SRAM puisqu'il y a suffisamment de mémoire libre.

Finalement la vitesse de transfert SPI est augmentée (diviseur 2 au lieu de 3) pendant les opérations vidéo video_op. Ceci afin de laisser du temps à la boucle de code programme principal. Il n'en reste vraiment pas beaucoup entre chaque interruption.

Autre avenue à explorer

Microchip vend une mémoire RAM sérielle SPI (23LC512) qui peut utiliser un bus 1,2,4 bits. A 4 bits on pourrait fabriquer un D.A.C. avec 16 niveaux de gris en conservant la même résolution. 32Ko (29440 Octets en fait) suffirait pour un buffer simple ou 64Ko pour un double.

Mise à jour 2013-08-09

Il y avait des bugs dans ntsc-isr.asm qui ont été corrigés. J'ai aussi modifié le démo pour utilisation de pages vidéo. Maintenant le démo utilise 2 pages vidéos. Une copie l'image du loup est faite d'une page à l'autre et les 2 pages sont affichées en alternance avec le numéro de la copie en bas de l'écran. Ça prends environ 5 secondes par copie!!


NOTES:
1) En fait j'ai obtenu une résolution de 384x230 pixels en diminuant le diviseur de l'interface SPI à 2. Mais le haut de l'image était quelque peut distortionnée. Je suis donc redescendu à 256x230 (SMCLK_DIV=3) pour obtenir une meilleur stabilité.

Aucun commentaire:

Publier un commentaire