Lecteur MP3 à base de PIC32MX
From Eric
m |
m |
||
Line 1: | Line 1: | ||
= Objectifs = | = Objectifs = | ||
+ | Réaliser un lecteur MP3 sur la base d'un décodeur hard, utiliser un écran graphique tactile, utiliser un PIC32. | ||
+ | |||
= Réalisation = | = Réalisation = | ||
+ | |||
== L'unité de traitement == | == L'unité de traitement == | ||
Line 11: | Line 14: | ||
[[File:tool_pickit3.jpg|200px|thumb|none]]. | [[File:tool_pickit3.jpg|200px|thumb|none]]. | ||
- | == L' | + | Le debugging in-situ fonctionne assez bien pour ce qui concerne la mise en oeuvre de point d'arrêt ; ça ne marche pas très bien pour ce qui concerne la visualisation des variables (parfois ça marche, parfois pas, et quand ça fonctionne, les capacités de navigation dans l'ensemble des variables est très très réduite [ou bien je ne sais pas l'utiliser...]). |
+ | |||
+ | == L'architecture de l'application == | ||
Comme pour ma précédente carte à [[caméra OV7670]], j'utilise l'OS temps-réel [http://www.freertos.org/ FreeRTOS]. | Comme pour ma précédente carte à [[caméra OV7670]], j'utilise l'OS temps-réel [http://www.freertos.org/ FreeRTOS]. | ||
+ | |||
+ | L'application comprend trois tâches : | ||
+ | * une tâche de gestion des dispositifs de saisie (pour l'instant, le seul dispositif est l'écran tactile) | ||
+ | * une tâche de gestion de l'IHM | ||
+ | * une tâche de gestion de la lecture MP3 et du tuner FM. | ||
+ | |||
+ | Ces tâches sont créés dans le programme principal (fichier "main.c"). | ||
+ | |||
+ | Les tâches communiquent entre-elles au moins de deux files (définies dans le module "comm") | ||
+ | * file "hQVGAQueue" pour les messages relevant de l'IHM émis par la tâche d'IHM à destination d'elle-même, | ||
+ | *+ file "hPlayQueue" pour les messages relevant du contrôle de la lecture MP3 et du tuner FM ; ils sont émis par la tâche d'IHM. | ||
+ | |||
+ | La structure des messages est définie dans le fichier "comm.h" : | ||
+ | * stucture "GRAPHICS_MSG pour les messages d'IHM | ||
+ | * structure "PLAY_MSG" pour les messages de contrôle MP3/tuner | ||
+ | |||
+ | D'une manière générale, les tâches d'IHM et de décodage MP3/tuner attendent la réception d'un message pour réaliser les traitement afférents. | ||
== La gestion de l'écran == | == La gestion de l'écran == | ||
- | L'IHM est réalisée au moyen de la [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2680&dDocName=en543091 bibliothèque graphique de Microchip]. | + | L'IHM est réalisée au moyen de la [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2680&dDocName=en543091 bibliothèque graphique de Microchip]. |
+ | |||
+ | Quelques lignes de codes ont été nécessaire pour réaliser le driver spécifique à l'écran ILI. Elles se trouvent dans les fichiers "Microchip\Graphics\Drivers\ILI9325P_16BIT.c/.h". | ||
+ | |||
+ | Le code du driver se contente d'initialiser le périphérique (fonction "ResetDevice") et d'implémenter quelques fonctions très simples ("PutPixel", "Bar",...). L'implémentation est actuellement très très peu performante car je ne suis pas parvenu à utiliser le mode PMP du PIC32MX, qui permet d'accéder de façon très simple à des périphériques se comportant comme une mémoire (en gros, ça émule le comportement des bus adresses/données d'un microprocesseur classique). Pour l'instant, j'accède à l'écran en utilisant les opérations d'IOs standards. En outre, les bits du PMP étant "distribués" sur plusieurs ports, les bits d'adresse ne peuvent pas être transmis en une seule opération. | ||
+ | |||
+ | Ainsi, voici un extrait de la macro "SetIndex" (fichier "ILI9325P_16BIT.h") dont le rôle est de positionner l'adresse du prochain accès : | ||
+ | <code> | ||
+ | LATGbits.LATG0 = (index & 0b0000000100000000) >> 8; \ | ||
+ | LATGbits.LATG1 = (index & 0b0000001000000000) >> 9; \ | ||
+ | LATFbits.LATF1 = (index & 0b0000010000000000) >> 10; \ | ||
+ | LATFbits.LATF0 = (index & 0b0000100000000000) >> 11; \ | ||
+ | LATDbits.LATD12 = (index & 0b0001000000000000) >> 12; \ | ||
+ | LATDbits.LATD13 = (index & 0b0010000000000000) >> 13; \ | ||
+ | LATDbits.LATD6 = (index & 0b0100000000000000) >> 14; \ | ||
+ | LATDbits.LATD7 = (index & 0b1000000000000000) >> 15; \ | ||
+ | </code> | ||
+ | |||
+ | Il me faudra tôt ou tard regarder de plus près la gestion du PMP. | ||
== La gestion de la carte SD == | == La gestion de la carte SD == | ||
Line 25: | Line 65: | ||
Voici, par exemple, la page d'accueil sur laquelle on voit la liste des fichiers contenus dans la carte SD : | Voici, par exemple, la page d'accueil sur laquelle on voit la liste des fichiers contenus dans la carte SD : | ||
[[File:mp3_lecture_sdcard.jpg|400px|thumb|none]]. | [[File:mp3_lecture_sdcard.jpg|400px|thumb|none]]. | ||
- | |||
== Le décodeur MP3 == | == Le décodeur MP3 == | ||
Line 32: | Line 71: | ||
Voici un gros plan de la carte de décompression MP3 et tuner FM : [[File:mp3-avec-tuner.jpg|400px|thumb|none]]. | Voici un gros plan de la carte de décompression MP3 et tuner FM : [[File:mp3-avec-tuner.jpg|400px|thumb|none]]. | ||
+ | |||
+ | === Configuration === | ||
+ | |||
+ | Le STA013 nécessite d'être configuré avant de pouvoir être utilisé. Cette configuration consiste à charger "certaines" valeurs dans "certains" registres du chip. La liste des paires (registre, valeur) est fournie par ST, sans explications. | ||
+ | |||
+ | En vérité, cette liste comprend deux parties, l'une très obscure et fixe, l'autre destinée à programmer la PLL et dont les valeur dépendent de la fréquence du quartz utilisé. Ces couples (adresse,valeur) sont donnés dans la datasheet du STA013 pour certaines fréquences d'horloge ; dans les autres cas, il faut utiliser le programme fourni par ST ("cpll.exe"). | ||
+ | |||
+ | Le fichier "sta013_config.c' contient les deux séquences d'initialisation. | ||
+ | |||
+ | === Décodage === | ||
+ | Le décodage d'un fichier MP3 est on ne peut plus simple puisqu'il suffit d'en transmettre le contenu complet (y compris les tags) via la ligne SPI. Le contrôle de flux est réalisé par le STA013 au moyen d'une | ||
+ | sortie dédiée. La boucle de décodage est ainsi : | ||
+ | <code> | ||
+ | static portTASK_FUNCTION( play_task, pvParameters ) | ||
+ | { | ||
+ | // Pour éviter les warnings... | ||
+ | ( void ) pvParameters; | ||
+ | for(;;) | ||
+ | { | ||
+ | // Attente (bloquante) d'un message en provenance de la queue. | ||
+ | if (xQueueReceive(hPlayQueue, &msg, portMAX_DELAY) == pdTRUE) { | ||
+ | // Traitement des messages | ||
+ | switch (msg.cmd) { | ||
+ | case MSG_PLAY: | ||
+ | // On coupe le tuner | ||
+ | tea5767_mute_on(); | ||
+ | tea5767_send_config(); | ||
+ | // On joue le morceau... | ||
+ | sta013_play(msg.data.filename); | ||
+ | msg.cmd = 0; | ||
+ | break; | ||
+ | [...] | ||
+ | default: | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | La fonction de décodage proprement dite est simplement : | ||
+ | <code> | ||
+ | void sta013_play( char* file_name) { | ||
+ | FIL mp3_file; | ||
+ | BYTE data; // Buffer de transmission | ||
+ | FRESULT res; // Code de retour des fonctions FatFs | ||
+ | UINT br; // Nombre d'octets lus | ||
+ | FATFS fatfs; | ||
+ | |||
+ | // Reset du STA (on ne sait jamais...) | ||
+ | reset(); | ||
+ | |||
+ | // Montage du système de fichiers | ||
+ | f_mount(0, &fatfs); | ||
+ | |||
+ | res = f_open(&mp3_file,file_name, FA_OPEN_EXISTING | FA_READ); | ||
+ | if (res) die(__FILE__, 111); | ||
+ | |||
+ | abort_play = FALSE; | ||
+ | |||
+ | while (!abort_play) { | ||
+ | // Lecture d'un octet | ||
+ | res = f_read(&mp3_file, &data, sizeof(data), &br); | ||
+ | if (res || br == 0) break; | ||
+ | // Transmission de l'octet | ||
+ | SpiChnPutC(MP3_SPI_CHANNEL, data); | ||
+ | // On attend la disponibilité du chip. | ||
+ | while ( MP3_DATA_REQ_IO == 0 ); | ||
+ | } | ||
+ | |||
+ | // Fermeture du fichier | ||
+ | f_close(&mp3_file); | ||
+ | } | ||
+ | </code> | ||
== La radio FM == | == La radio FM == | ||
Line 40: | Line 153: | ||
Voici la carte TEA5767 montée sur la carte décodeur : | Voici la carte TEA5767 montée sur la carte décodeur : | ||
[[File:mp3-tuner.jpg|400px|thumb|none]] | [[File:mp3-tuner.jpg|400px|thumb|none]] | ||
+ | |||
+ | Ce chip est très puissant : il ne requiert que très peu de composant annexes et offre même une fonction de recherche automatique de stations. Pour ma part, je me suis contenté de définir une liste de stations que j'ai stockée sur la SDCARD (fichier "stations.txt"). Ce fichier contient une série "nom de station", "donnée de configuration PLL", ..., "nom de station", "donnée de configuration PLL". La donnée de configuration est calculée à partir de la fréquence à synthoniser conformément aux formules données dans la datasheet. (Voir feuille excel, "stations.xls"). | ||
+ | |||
+ | Voilà un extrait du fichier de définition des stations : | ||
+ | <code> | ||
+ | France Inter | ||
+ | 10782 | ||
+ | RTL2 | ||
+ | 10855 | ||
+ | France Culture | ||
+ | 11075 | ||
+ | France Musique | ||
+ | 11148 | ||
+ | Rire et Chansons | ||
+ | 11551 | ||
+ | Le Mouv' | ||
+ | 11649 | ||
+ | RFM 12125 | ||
+ | Nostalgie | ||
+ | 12173 | ||
+ | Skyrock | ||
+ | 12234 | ||
+ | </code> | ||
+ | |||
= Conclusions et leçons = | = Conclusions et leçons = | ||
- | + | De l'art de faire un monstrueux lecteur MP3 alors que ça coûte au plus 10 euros sur eBay... |
Revision as of 13:26, 21 August 2011
Contents |
Objectifs
Réaliser un lecteur MP3 sur la base d'un décodeur hard, utiliser un écran graphique tactile, utiliser un PIC32.
Réalisation
L'unité de traitement
Un PIC32 est utilisé comme unité centrale. J'utilise une version vendue sur plaquette (30$). C'est cher mais ça m'évite les soucis de soudage de CMS (et ça me permet d'avoir les capas de découplage au plus près du chip.
.J'utilise un clone chinois du Pickit3 pour programmer le chip et debuguer mes programmes in-situ. Coût de la chose : une trentaine de dollars :
.Le debugging in-situ fonctionne assez bien pour ce qui concerne la mise en oeuvre de point d'arrêt ; ça ne marche pas très bien pour ce qui concerne la visualisation des variables (parfois ça marche, parfois pas, et quand ça fonctionne, les capacités de navigation dans l'ensemble des variables est très très réduite [ou bien je ne sais pas l'utiliser...]).
L'architecture de l'application
Comme pour ma précédente carte à caméra OV7670, j'utilise l'OS temps-réel FreeRTOS.
L'application comprend trois tâches :
- une tâche de gestion des dispositifs de saisie (pour l'instant, le seul dispositif est l'écran tactile)
- une tâche de gestion de l'IHM
- une tâche de gestion de la lecture MP3 et du tuner FM.
Ces tâches sont créés dans le programme principal (fichier "main.c").
Les tâches communiquent entre-elles au moins de deux files (définies dans le module "comm")
- file "hQVGAQueue" pour les messages relevant de l'IHM émis par la tâche d'IHM à destination d'elle-même,
- + file "hPlayQueue" pour les messages relevant du contrôle de la lecture MP3 et du tuner FM ; ils sont émis par la tâche d'IHM.
La structure des messages est définie dans le fichier "comm.h" :
- stucture "GRAPHICS_MSG pour les messages d'IHM
- structure "PLAY_MSG" pour les messages de contrôle MP3/tuner
D'une manière générale, les tâches d'IHM et de décodage MP3/tuner attendent la réception d'un message pour réaliser les traitement afférents.
La gestion de l'écran
L'IHM est réalisée au moyen de la bibliothèque graphique de Microchip.
Quelques lignes de codes ont été nécessaire pour réaliser le driver spécifique à l'écran ILI. Elles se trouvent dans les fichiers "Microchip\Graphics\Drivers\ILI9325P_16BIT.c/.h".
Le code du driver se contente d'initialiser le périphérique (fonction "ResetDevice") et d'implémenter quelques fonctions très simples ("PutPixel", "Bar",...). L'implémentation est actuellement très très peu performante car je ne suis pas parvenu à utiliser le mode PMP du PIC32MX, qui permet d'accéder de façon très simple à des périphériques se comportant comme une mémoire (en gros, ça émule le comportement des bus adresses/données d'un microprocesseur classique). Pour l'instant, j'accède à l'écran en utilisant les opérations d'IOs standards. En outre, les bits du PMP étant "distribués" sur plusieurs ports, les bits d'adresse ne peuvent pas être transmis en une seule opération.
Ainsi, voici un extrait de la macro "SetIndex" (fichier "ILI9325P_16BIT.h") dont le rôle est de positionner l'adresse du prochain accès :
LATGbits.LATG0 = (index & 0b0000000100000000) >> 8; \ LATGbits.LATG1 = (index & 0b0000001000000000) >> 9; \ LATFbits.LATF1 = (index & 0b0000010000000000) >> 10; \ LATFbits.LATF0 = (index & 0b0000100000000000) >> 11; \ LATDbits.LATD12 = (index & 0b0001000000000000) >> 12; \ LATDbits.LATD13 = (index & 0b0010000000000000) >> 13; \ LATDbits.LATD6 = (index & 0b0100000000000000) >> 14; \ LATDbits.LATD7 = (index & 0b1000000000000000) >> 15; \
Il me faudra tôt ou tard regarder de plus près la gestion du PMP.
La gestion de la carte SD
La gestion de la carte SD est réalisé au moyen de la bibliothèque FatFs. Je n'ai eu qu'à configurer les quelques signaux d'accès à la SDCARD (bus SPI) pour que ça fonctionne, out-of-the-box.
Voici, par exemple, la page d'accueil sur laquelle on voit la liste des fichiers contenus dans la carte SD :
.Le décodeur MP3
Le décodage du flux MP3 est réalisé par le chip ST013 de STMicro et le convertisseur DAC CS4334 sur I2C. Un ampli TDA1308 est ajouté pour piloter les écouteurs.
Voici un gros plan de la carte de décompression MP3 et tuner FM : .Configuration
Le STA013 nécessite d'être configuré avant de pouvoir être utilisé. Cette configuration consiste à charger "certaines" valeurs dans "certains" registres du chip. La liste des paires (registre, valeur) est fournie par ST, sans explications.
En vérité, cette liste comprend deux parties, l'une très obscure et fixe, l'autre destinée à programmer la PLL et dont les valeur dépendent de la fréquence du quartz utilisé. Ces couples (adresse,valeur) sont donnés dans la datasheet du STA013 pour certaines fréquences d'horloge ; dans les autres cas, il faut utiliser le programme fourni par ST ("cpll.exe").
Le fichier "sta013_config.c' contient les deux séquences d'initialisation.
Décodage
Le décodage d'un fichier MP3 est on ne peut plus simple puisqu'il suffit d'en transmettre le contenu complet (y compris les tags) via la ligne SPI. Le contrôle de flux est réalisé par le STA013 au moyen d'une
sortie dédiée. La boucle de décodage est ainsi :
static portTASK_FUNCTION( play_task, pvParameters ) { // Pour éviter les warnings... ( void ) pvParameters; for(;;) { // Attente (bloquante) d'un message en provenance de la queue. if (xQueueReceive(hPlayQueue, &msg, portMAX_DELAY) == pdTRUE) { // Traitement des messages switch (msg.cmd) { case MSG_PLAY: // On coupe le tuner tea5767_mute_on(); tea5767_send_config(); // On joue le morceau... sta013_play(msg.data.filename); msg.cmd = 0; break; [...] default: break; } } } }
La fonction de décodage proprement dite est simplement :
void sta013_play( char* file_name) { FIL mp3_file; BYTE data; // Buffer de transmission FRESULT res; // Code de retour des fonctions FatFs UINT br; // Nombre d'octets lus FATFS fatfs; // Reset du STA (on ne sait jamais...) reset(); // Montage du système de fichiers f_mount(0, &fatfs); res = f_open(&mp3_file,file_name, FA_OPEN_EXISTING | FA_READ); if (res) die(__FILE__, 111); abort_play = FALSE; while (!abort_play) { // Lecture d'un octet res = f_read(&mp3_file, &data, sizeof(data), &br); if (res || br == 0) break; // Transmission de l'octet SpiChnPutC(MP3_SPI_CHANNEL, data); // On attend la disponibilité du chip. while ( MP3_DATA_REQ_IO == 0 ); } // Fermeture du fichier f_close(&mp3_file); }
La radio FM
Cerise sur le gâteau, le lecteur dispose d'une fonction radio FM, réalisée par le TEA5767 de Philips. Pour information, le chip est vendu sur une petite carte pour une bouchée de pain (moins de 3 euros en 2011!!!), la voici :
.Voici la carte TEA5767 montée sur la carte décodeur :
Ce chip est très puissant : il ne requiert que très peu de composant annexes et offre même une fonction de recherche automatique de stations. Pour ma part, je me suis contenté de définir une liste de stations que j'ai stockée sur la SDCARD (fichier "stations.txt"). Ce fichier contient une série "nom de station", "donnée de configuration PLL", ..., "nom de station", "donnée de configuration PLL". La donnée de configuration est calculée à partir de la fréquence à synthoniser conformément aux formules données dans la datasheet. (Voir feuille excel, "stations.xls").
Voilà un extrait du fichier de définition des stations :
France Inter 10782 RTL2 10855 France Culture 11075 France Musique 11148 Rire et Chansons 11551 Le Mouv' 11649 RFM 12125 Nostalgie 12173 Skyrock 12234
Conclusions et leçons
De l'art de faire un monstrueux lecteur MP3 alors que ça coûte au plus 10 euros sur eBay...