[AUDIO_VIDE] Bonjour. Nous allons voir comment nous sommes limités parfois par les microcontrôleurs lorsque nous devons piloter des matrices de grande taille et comment la technique du DMA, accès direct en mémoire, permet de repousser un peu ces limites. Nous allons voir l'architecture du DMA, nous allons tenter d'écrire un programme très simple mettant en œuvre du DMA et nous allons voir comment cela peut s'appliquer au pilotage de matrices de LED. On comprend que des matrices comportant beaucoup de LED exigent des vitesses de rafraîchissement extrêmement élevées. Naturellement on va pouvoir utiliser des microcontrôleurs dont la fréquence du processeur est plus élevée pour avoir des débits plus importants, mais la technique qu'on appelle l'accès direct en mémoire permet de repousser encore un peu plus loin cette limite. Quelle est l'idée qui se cache derrière le DMA? C'est de ne pas avoir à exécuter des instructions du processeur pour chaque transfert de données. C'est une idée qui n'est pas nouvelle. Je me souviens qu'en 1981, le circuit Intel 8253 est sorti. Et ce qui est amusant, c'est qu'on retrouve des traces de ce circuit dans des PC récents. Donc, c'est une technologie qui a survécu et que vous utilisez régulièrement dans vos ordinateurs. Regardons d'un peu plus près l'architecture d'un système informatique. On se souvient qu'il y a le processeur cadencé par son horloge, qu'il va placer des adresses sur le bus d'adresses pour pouvoir échanger des données avec des mémoires du type mémoire morte ou mémoire vive ainsi qu'avec des circuits d'entrées-sorties. Admettons qu'on souhaite transférer des données depuis la mémoire jusque sur les sorties. il va falloir charger en mémoire morte une instruction qui va donner l'ordre d'aller chercher en mémoire vive une donnée, puis d'adresser en écriture le circuit de sortie. On voit que c'est relativement compliqué. L'architecture du DMA permet de libérer le processeur, c'est le DMA qui prend le contrôle et qui va lui-même adresser la mémoire vive au bon endroit, chercher des données, et les réécrire directement sur les entrées et sorties. Donc, on a un accès direct en mémoire, Direct Memory Access en anglais. Ce système peut paraître extrêmement simple. il n'est en effet pas très compliqué sur le principe. Par contre, il amène généralement à des programmes complexes parce que la documentation de ces circuits DMA est compliquée, énormément de modes différents sont fournis par les fabricants, et finalement on se retrouve dans une situation où on a des programmes relativement compliqués et difficiles à mettre au point. Tous les microcontrôleurs n'offrent pas du DMA. Certains microcontrôleurs offrent des DMA relativement limités à certains périphériques, c'est le cas de certains microcontrôleurs de la famille MSP430. Par contre, dans une bonne partie des processeurs de la famille des processeurs ARM, on trouve des DMA relativement complexes et qui sont assez puissants. Mais il y a également d'autres processeurs comme par exemple PIC32 qui ont également des circuits DMA. J'ai essayé de réaliser un programme le plus simple possible. Il a l'air simple ici, mais vous ne voyez malheureusement que l'appel d'un certain nombre de procédures. Essayons d'en comprendre le rôle. Tout d'abord ici, HAL_Init( ). Ce programme est écrit pour un processeur STM30 de STMicroelectronics et ils ont un hardware abstraction layer, une couche d'abstraction matérielle qui permet de simplifier la gestion des périphériques. Et ici, on doit initialiser ce module. Puis ensuite, on va appeler une procédure qui va initialiser les périphériques, rien de très particulier, on va mettre ici un seul port en sortie. On va également créer une trame en mémoire qui sera envoyée sur notre unique sortie et là où ça devient relativement intéressant, c'est c'est InitDMA, et il y aura également InitTimer, et ces deux procédures vont permettre au mécanisme d'accès direct en mémoire de s'exécuter et de s'exécuter avec un bon timing, avec une gestion temporelle liée aux contraintes de la matrice. Tentons de regarder un peu plus en détail cette procédure d'initialisation de l'accès direct en mémoire. Tout d'abord, il faut que l'horloge du DMA, on a utilisé le DMA numéro 2, soit enclenchée. On a choisi un canal parce que le système permet d'avoir plusieurs canaux de DMA simultanés. On indique qu'on souhaite faire de l'accès depuis une mémoire vers un périphérique. Donc, on va bien faire sortir des données de microcontrôleurs, données qui sont stockées en mémoire vive. On va demander que pour la mémoire, on ait incrémentation automatique MINC_ENABLE, c'est-à -dire qu'on ira envoyer la donnée qui se trouve à une adresse, puis à l'adresse suivante, puis à l'adresse suivante, etc. Alors que pour les périphériques, on aura le mode d'incrémentation qui sera désélectionné, donc on écrira toujours sur le même périphérique. Par ailleurs, on signale au système qu'on veut transférer des caractères, donc il y a un alignement qui doit se faire avec des caractères, donc des mots 8 bits et non pas des mots de 16 bits ou des mots de 32 bits puisque le processeur ARM est capable de manipuler des octets, des mots de 16 bits et des mots de 32 bits. Même chose pour l'alignement, donc périphérique et mémoire toujours des octets. On choisit le mode normal du DMA, il y a plusieurs modes, on lui donne une priorité maximale. Dans ce cas, on est tout seuls à utiliser du DMA, ce n'est pas un vrai problème. Ensuite, on va décider de ne pas utiliser le mode qui correspond à l'enclenchement d'un FIFO, ça veut dire First In First Out, il s'agit donc d'une mémoire tampon, d'un buffer. Et on ne l'utilise pas dans ce cas là . Ici, on va dire que les transferts se font single, c'est-à -dire un seul caractère, un seul octet à la fois, et finalement donc tant pour la mémoire que pour les périphériques. Donc voilà un certain nombre de réglages qu'il faut connaître, qu'il faut comprendre. C'est facile de décrire ce programme, c'est un peu plus difficile de l'écrire. Et généralement d'ailleurs, on ne va pas l'écrire soi-même, on va essayer de reprendre des exemples fournis par les fabricants et de l'adapter à ce qu'on cherche à faire. Finalement, on va créer ce qu'ils appellent une instance de DMA et l'initialiser, ce qui va permettre de préparer à l'activité notre système d'accès direct en mémoire. Mais il reste encore son cadencement. Dans ce cas là , le cadencement est assuré par un Timer. Donc on va de nouveau enclencher l'horloge du Timer numéro un qu'on a choisi d'utiliser, on va lui préciser comme on a l'habitude sa prédivision, son mode de travail COUNTERMODE_UP, sa période, la division de l'horloge, le fait qu'on va répéter à l'infini, et on va de nouveau initialiser une instance du Timer comme on l'avait fait pour le DMA. Et finalement, ces dernières instructions ici vont permettre d'enclencher les transferts DMA qui sont cadencés par le Timer. Et vous avez remarqué tout à l'heure que la boucle principale du programme était totalement vide, et on va avoir des données qui étaient placées dans une zone mémoire, donc une trame, qui vont être envoyées sur une sortie du microcontrôleur sans aucune intervention du processeur, donc le programme pourra faire tout autre chose en même temps. Le DMA se produit de manière indépendante et à une vitesse extrêmement intéressante. Comment appliquer ce DMA au pilotage des matrices de LED? On se souvient qu'on utilise des registres série-parallèles qui nécessitent l'envoi de signaux de données mais également d'horloges. Vous vous souvenez par exemple du timing ici d'un afficheur multiplexé. On a des données avec une horloge qui passe de 0 à 1, de 0 à 1, de 0 à 1 pour chaque donnée. On va effectivement pouvoir écrire par exemple en mémoire différentes données à envoyer suivies de l'horloge à l'état 0 des mêmes données suivies de l'horloge à l'état 1, puis d'une nouvelle série de données avec l'horloge à 0 et les mêmes données à l'état 1 pour l'horloge. On va donc placer tout cela en mémoire et ensuite demander l'envoi de toutes ces données par DMA. Cela semble un peu fastidieux, mais une fois qu'on a écrit la procédure, ça peut s'exécuter extrêmement rapidement et c'est ça qui est intéressant. Donc, les horloges peuvent être placées en mémoire comme les données sont placées. A noter que certains microcontrôleurs offrent des circuits programmables capables de générer de telles horloges. Cela pourrait éventuellement simplifier la génération en mémoire et surtout économiser aussi un peu de place en mémoire vive. Ensuite, évidemment les détails de cette programmation sont relativement complexes. On trouve de jolis exemples sur Internet, des hackers en particulier qui ont réalisé des projets de ce type-là en utilisant le DMA en particulier des microcontrôleurs SDM32. Je ne souhaite pas aller plus loin dans l'explication du DMA, c'est un domaine relativement complexe. On a vu donc que les limites du microcontrôleur peuvent être dépassées par l'usage de l'accès direct en mémoire qui permet d'éviter les cycles des instructions sur les bus de données et d'adresses. On a vu avec un exemple simple qu'il aboutissait quand même à des programmes relativement compliqués et difficiles à écrire. Mais vous allez trouver sur Internet de jolies applications, en particulier qui ont été faites par des hackers qui donnent de jolis projets en particulier avec les microcontrôleurs SDM32 et qui permettent de piloter des afficheurs relativement grands avec des processeurs à faible coût avec des performances tout à fait intéressantes. A noter qu'il y a quand même une limite qu'on ne pourra pas dépasser. Et si on veut aller encore plus loin que le DMA, il va falloir utiliser des circuits logiques programmables, les fameuses FPGA, et c'est ce que nous allons voir dans une des prochaines leçons.