IMA4 2018/2019 EC3

De Wiki d'activités IMA

Présentation du projet

Contexte

L'élève continue son semestre S8 à l'école.

Objectif

Le but est de concevoir une partie d'une platine de travaux pratiques pour l'ordonnancement. Il faut aussi programmer le micro-contrôleur intégré.

La platine sera constituée de 3 parties bien distinctes :

  • la partie "contrôle" composée d'un ATMega328p, d'un FT232, d'un connecteur USB, de deux LED et de deux boutons, l'ordonnanceur doit être chargé sur ce micro-contrôleur ;
  • la partie matrice de LED, il s'agit d'une matrice de 8x8 LED CMS monochromes contrôlées par un ATMega328p et 3 pilotes de LED TLC5947 ;
  • la partie afficheur 7-segments, il s'agit de 6 afficheurs 7-segments implantés avec des LED CMS monochromes et contrôlés par un ATMega328p et 2 pilotes de LED TLC5947.

La communication entre la partie "contrôle" et les deux autres parties s'effectue via un bus SPI. Les trois parties sont conçues et réalisées séparément mais doivent s'interconnecter facilement. Les 3 PCB sont rectangulaires et doivent s'assembler aussi sous la forme d'un rectangle. Pour passer les lignes SPI et l'alimentation, des connecteurs doivent être prévus sur les 3 PCB. Vous commencerez par vous mettre d'accord sur les dimensions des PCB et sur l'emplacement des connecteurs. Une première phase de conception des PCB avec placement des composants peut être nécessaire pour cette étape.

Vous êtes chargé de réaliser l'afficheur 7-segments. Vous trouverez, sur les Wiki IMA, des exemples de cartes avec ATMega328p et TLC5947. Partez de l'un de ces exemples. Utilisez le logiciel Fritzing pour la conception de la carte. N'oubliez pas le connecteur ICSP pour la première programmation du micro-contrôleur.

Une fois la carte fonctionnelle vous programmerez le micro-contrôleur pour attendre l'état des LED par communication SPI. Votre ATMega328p doit donc être configuré dans le mode SPI esclave. Utilisez le même protocole de transmission des données que l'afficheur 7-segments de SparkFun. Il suffira d'adapter ce protocole pour passer de 4 symboles (module SparkFun) à 6 (votre module). Par défaut, une séquence de 6 octets va provoquer l'affichage de ces octets sur chaque afficheur. Des octets particuliers (valeurs supérieures ou égales à 0x76) sont des commandes permettant d'effectuer des actions particulières comme éteindre toutes les LED. Si la partie contrôle n'est pas opérationnelle, il sera possible de tester votre afficheur avec un Arduino Uno et l'exemple de programme disponible sur le site de SparkFun (adaptez le programme pour passer de 4 à 6 afficheurs).

Description du projet

Matériel nécessaire

Description Fabricant Référence Fabricant Fournisseur Quantité Lien fournisseur
Afficheur 7 segments KINGBRIGHT SA39-11SURKWA Farnell 6 https://fr.farnell.com/kingbright/sa39-11surkwa/display-0-39-cmn-anode-red/dp/2080050?st=7%20segment#anchorTechnicalDOCS
Régulateur 3.3V TEXAS INSTRUMENTS LM1117MP Farnell 1 https://fr.farnell.com/texas-instruments/lm1117mp-5-0-nopb/regulateur-ldo-0-8a-5v-sot-223/dp/2435815?st=LM1117

Planning prévisionnel

  • Semaine 1 (semaine du 18 au 24 février)  : étude du sujet, prise en main du logiciel Fritzing, début de conception du schematic;
  • Semaine 2 : conception et validation du schematic, liste des composants;
  • Semaine 3 : routage et réalisation du PCB , test;
  • Semaine 4 : routage et réalisation du PCB , test;
  • Semaine 5 : programmation microcontrôleur;
  • Semaines suivantes : programmation microcontrôleur, tests, finalisation;

Travail effectué

La première étape du projet est de concevoir le PCB de la partie afficheur. Chaque afficheur 7 segments utilise 8 inputs, soit un total de 48 inputs au total. Pour gérer autant d'entrées, on utilise 2 TLC5947. Le composant TLC5947 n'est pas disponible dans la bibliothèque de base de Fritzing. Par chance Lirui Zhang et Lihe Zhang, pour le projet IMA4 2017/18 P18, avaient rencontré le même problème et ont conçue l'empreinte du TL5947 ; j'ai donc utilisé leur empreinte pour réaliser le schematic.

shematic

La carte est composé d'un ATmega328p, de 2 TLC5947, 6 afficheurs 7-segments reliées aux TLC, un régulateur 3,3 V pour alimenter les afficheurs, un connecteur SPI pour la communication lors de la programmation et de ports pour l'alimentation et la communication ISP.

Une fois le schematic terminé et validé, la carte doit être routée. Voici le routage proposé par Xavier Redon, intégrant la carte dans l'ensemble du projet :

Carte routée

La carte entière (EC1-2-3) est usinée, une fois reçue je soude les composants CMS de ma partie. Pour que les afficheurs soient réutilisables pour d'autres projets, je ne les soude pas directement, j'utilise des connecteurs.

Carte soudée

Ma partie de carte à pour but final d'être connectée à la partie EC1, pour l'instant, pour pouvoir travailler seul dessus je rajoute un fil pour l'alimentation et un autre pour le 'chip select'.

La deuxième étape du projet est maintenant de coder la carte. Pour ce faire j'utilise une arduino uno pour téléverser les programmes sur l'atmega par ISP. Il nous est fournis quelques fonctions et bibliothèques de base. La fonction set_LED_Drivers() prend un paramètres un tableau dans lequel sont découper 3 octets pour les envoyer au TLC5947 qui transmet aux 3 afficheurs qui lui sont connectés. Chaque bit d'un octet correspond à un segment de l'afficheur. Une subtilité est que les segments de chaque afficheurs ne sont pas connectés dans le même ordre au TLC, ainsi un même octet n'affiche pas la même chose sur les 3 afficheurs. Le but est donc d'écrire une fonction qui décompose un octet et le réarrange dans un tableau afin de pouvoir utiliser la fonction set_LED_Drivers() et que chaque afficheurs affichent la même chose pour un même octet. C'est ce que fait la fonction octetToDisplay() :


void octetToDisplay(unsigned char msg, int *display[8])
{
    unsigned char octet=msg;
    int i;
    for(i=0; i<8;i++)
    {
        *(display[7-i])=(octet%2)*4095;
        octet=octet/2;
    }
}

Pour remettre en ordre les bit dans les octets j'utilise des pointeurs :

//Remise en odre afficheur 1
int display1[8]; int *pt_disp1[8];
pt_disp1[0]=&display1[6];
pt_disp1[1]=&display1[5];
pt_disp1[2]=&display1[3];
pt_disp1[3]=&display1[2];
pt_disp1[4]=&display1[1];
pt_disp1[5]=&display1[7];
pt_disp1[6]=&display1[0];
pt_disp1[7]=&display1[4];
//Remise en odre afficheur 2
int display2[8]; int *pt_disp2[8];
pt_disp2[0]=&display2[5];
pt_disp2[1]=&display2[6];
pt_disp2[2]=&display2[0];
pt_disp2[3]=&display2[1];
pt_disp2[4]=&display2[2];
pt_disp2[5]=&display2[4];
pt_disp2[6]=&display2[3];
pt_disp2[7]=&display2[7];
//Remise en odre afficheur 3
int display3[8]; int *pt_disp3[8];
pt_disp3[0]=&display3[6];
pt_disp3[1]=&display3[5];
pt_disp3[2]=&display3[0];
pt_disp3[3]=&display3[1];
pt_disp3[4]=&display3[2];
pt_disp3[5]=&display3[7];
pt_disp3[6]=&display3[3];
pt_disp3[7]=&display3[4];

On peut alors déjà tester cette partie de code en imposant la valeurs des octets dans le programme de l'atmega. Ca fontionne :

Affichage de 8 . (8,rien,point décimal)

Reste maintenant à coder la partie communication SPI avec l'atemega en esclave. Pour cela j'initialise l'atmega en esclave et j'écris la fonction pour recevoir de octets :

void init_spi(void){
    sei();
    DDRB = (1<<CS)|(1<<MOSI)|(1<<SCK);
    SPCR = (1<<SPE)|(1<<SPR0);

}

uint8_t spi_exch(uint8_t output){
    SPDR = output;
    while(!(SPSR & 1<<SPIF));
    return SPDR;
}


Sur l'IDE arduino j'utilise la bibliothèque SPI.h :

void setup(){
  Serial.begin(19200);
  Serial.println("Setup");
  SPI.begin();
}

void sendSPI(unsigned char octet){
    Serial.print("j'envoie : ");
    Serial.print(octet,BIN);
    digitalWrite(slave, LOW);
    int result = SPI.transfer(octet);
    digitalWrite(slave,HIGH);
    Serial.print(" et j'ai precedement recu : ");
    Serial.println(result,BIN);    
}

Sur le programme de l'atmega je code alors une boucle qui reçoit constamment des octets et les traite :

while(1)
{
    octet1=spi_exch(octet3);
    octet2=spi_exch(octet1);
    octet3=spi_exch(octet2);
    octetToDisplay(octet1,pt_disp1);
    octetToDisplay(octet2,pt_disp2);
    octetToDisplay(octet3,pt_disp3);
    int i;
	//concaténation des 3 tableaux en un seul pour utiliser set_LED_Drivers
    for (i=0;i<8;i++)
    {
        groupes[i]=display1[i];
        groupes[i+8]=display2[i];
        groupes[i+16]=display3[i];
    }
    set_LED_Drivers(groupes,NB_DRIVERS);
}

Le programme fonctionne :

Correspondance entre les octets envoyés et reçus

Documents

Les codes sont disponibles dans le fichier suivant : Fichier:EC3.zip