53
Programmation C pour systèmes embarqués Sylvain MONTAGNY [email protected] Bâtiment chablais, bureau 13 04 79 75 86 86 Retrouver tous les documents de Cours/TD/TP sur le site www.master-electronique.com

Cours - Programmation C pour systèmes embarqués

Embed Size (px)

Citation preview

Page 1: Cours - Programmation C pour systèmes embarqués

Programmation C pour systèmes embarqués

Sylvain MONTAGNY [email protected]

Bâtiment chablais, bureau 1304 79 75 86 86

Retrouver tous les documents de Cours/TD/TP sur le sitewww.master-electronique.com

Page 2: Cours - Programmation C pour systèmes embarqués

Université de Savoie 2

Présentation des cours : Sommaire

Cours : 10.5 h en 7 séances1ère partie : Rappel sur le langage C (exercices de base)

2ème partie : La programmation en langage C avancée

3ème partie : Implémentation de code sur cible embarquée (DSP TMS 320C5416)

4ème partie : Présentation du TP : Réalisation d’un algorithme de compression de données.

Page 3: Cours - Programmation C pour systèmes embarqués

Université de Savoie 3

Présentation TP

TD : 20 h en 5 séances

Le but de ce projet est d'écrire un programme de compression de fichiers textes, sans perte d'information. On demande également d'écrire un décompresseur qui devra restaurer le fichier original.

L’algorithme proposé ici est l'algorithme de Huffman.

Page 4: Cours - Programmation C pour systèmes embarqués

Université de Savoie 4

Examen

Une note :

14 points : Le déroulement du TP/Projet jusqu’à la soutenance.6 points sur la soutenance (présentation de votre projet et de l’intégration sur le DSP)

Page 5: Cours - Programmation C pour systèmes embarqués

Université de Savoie 5

1ère partie : Rappel sur le langage C (exercices de base)

Donner l’exécution du code suivant :

#include <stdio.h>#include <stdlib.h>

int main(void){unsigned char i;unsigned char tab[5]={1,2,4,8,16};

for (i=0;i<5;i++) {printf("Le %d° elt est %d\n",i+1,tab[i]);} return EXIT_SUCCESS;

}

Page 6: Cours - Programmation C pour systèmes embarqués

Université de Savoie 6

1ère partie : Rappel sur le langage C (exercices de base)

Donner l’exécution du code suivant :

#include <stdio.h>

int main() {int i,j;

for(i=0;i<5;i++){for(j=5-i;j<5;j++){

printf("++");}

printf("\n");}

return EXIT_SUCCESS;}

Page 7: Cours - Programmation C pour systèmes embarqués

Université de Savoie 7

1ère partie : Rappel sur le langage C (exercices de base)

Écrire une fonction C calculant la longueur d'une chaîne de caractères, donnée en argument. Le prototype de la fonction est le suivant :

int longueur(char *s)

Page 8: Cours - Programmation C pour systèmes embarqués

Université de Savoie 8

1ère partie : Rappel sur le langage C (exercices de base)

Écrire une fonction C calculant la longueur d'une chaîne de caractères, donnée en argument.

#include <stdlib.h>

int longueur(char *s) {int n = 0;

while (s[n] != '\0') {n++;}

return n;}

Page 9: Cours - Programmation C pour systèmes embarqués

Université de Savoie 9

1ère partie : Rappel sur le langage C (exercices de base)

Soit un texte donné par une chaîne de caractères. Le but est de compter le nombre d'occurrences de chaque lettre minuscule.Question 1 : Réaliser les déclarations suivantes :

Le texte (chaîne de caractère constante) sera déclaré dans un tableau nommé « ch ». Vous afficherez la chaîne de caractère à l’écran.Un tableau d'entiers statique nommé « occ ». pour compter les occurrences de chaque lettre de l’alphabet dont la taille est fixée par une constante (correspondant au nombre de lettre de l’alphabet).Un pointeur nommé « p » pour parcourir le texte.

Page 10: Cours - Programmation C pour systèmes embarqués

Université de Savoie 10

1ère partie : Rappel sur le langage C (exercices de base)

Page 11: Cours - Programmation C pour systèmes embarqués

Université de Savoie 11

1ère partie : Rappel sur le langage C (exercices de base)

#include <stdio.h>#define NB_LETTRE 26;

void main(void) {

/* déclaration d'une chaîne <=> tableau de caractères. */char ch[]="ceci est une chaîne de test";

/* déclaration d'un pointeur sur une chaîne de caracteres. */char *p = ch;

/* déclaration d'un tableau de 26 cases */int occ[NB_LETTRE];

printf("Chaîne en mémoire : %s\n",ch);}

Page 12: Cours - Programmation C pour systèmes embarqués

Université de Savoie 12

1ère partie : Rappel sur le langage C (exercices de base)

Question 2 : Initialiser le tableau d’occurrence à zéro :

Page 13: Cours - Programmation C pour systèmes embarqués

Université de Savoie 13

1ère partie : Rappel sur le langage C (exercices de base)

Question 2 : Initialiser le tableau d’occurrence à zéro :

/* initialisation du tableau des occurrences à 0. */int i=0;for (i=0; i<NB_LETTRE;i++)occ[i]=0;

Page 14: Cours - Programmation C pour systèmes embarqués

Université de Savoie 14

1ère partie : Rappel sur le langage C (exercices de base)

Question 3 : Compter les occurrences jusqu’àla fin de la chaîne de caractère :

Page 15: Cours - Programmation C pour systèmes embarqués

Université de Savoie 15

1ère partie : Rappel sur le langage C (exercices de base)

Question 3 : Compter les occurrences jusqu’àla fin de la chaîne de caractère :

/* parcours de la chaîne jusqu’au ‘\0’ */while (*p != '\0'){if ( (*p >= 'a‘) && (*p <= 'z‘) ) {occ[*p-'a'] = occ[*p-'a'] + 1;}p++;}

Page 16: Cours - Programmation C pour systèmes embarqués

Université de Savoie 16

1ère partie : Rappel sur le langage C (exercices de base)

Question 4 : Afficher le contenu du tableau occ

Page 17: Cours - Programmation C pour systèmes embarqués

Université de Savoie 17

1ère partie : Rappel sur le langage C (exercices de base)

Question 4 : Afficher le contenu du tableau occ

for (i=0; i<nb_lettres; i++) {printf("Nombre de %c : %d\n", 'a'+i,occ[i]);}

Page 18: Cours - Programmation C pour systèmes embarqués

18

2ème partie : La programmation en langage C avancée

Lisibilité du code, les types de variables,les typedef, occupation mémoire, porté des variables, les opérateurs, manipulation de registre, les structures, les pointeurs, le main(), pointeurs, la pile, type de fonction, allocation dynamique, les options d’optimisations à la compilation, les erreurs classiques du C…

Page 19: Cours - Programmation C pour systèmes embarqués

Université de Savoie 19

Lisibilité du code C

Exercice :Réaliser un code qui imprime les N premiers éléments d'un tableau d’entier A[] en insérant un espace entre les éléments et en commençant une nouvelle ligne après chaque dixième chiffre.

Page 20: Cours - Programmation C pour systèmes embarqués

Université de Savoie 20

Lisibilité du code C

void main(void){int A[80],N,i;

scanf(’’%d’’,&N);

for (i=0; i<N; i=i+1){printf("%d", A[i]);if ((i%10) == 9)

printf("\n");elseprintf(" ");

}}

Page 21: Cours - Programmation C pour systèmes embarqués

Université de Savoie 21

Lisibilité du code CVoici une deuxième façon de coder, très pratique mais beaucoup moins lisible.

void main(void){int A[80],N,i;

scanf(’’%d’’,&N);

for (i=0; i<n; i++)printf("%d%c", a[i], (i%10==9)?'\n':' ');}

Page 22: Cours - Programmation C pour systèmes embarqués

Université de Savoie 22

Lisibilité du code C

Quelques équivalences… parfois à éviterOp. Fonction Exemple Equivalence += Addition et

affectation nombre += 5; nombre=nombre+5

-= Soustraction et affectation

nombre -= 6;

*= Multiplication et affection

nombre *= 3;

/= Division et affectation

nombre /= 2;

%= Modulo et affectation

nombre %= 4; nombre = nombre % 4

++ Incrémentation nombre++;

nombre = nombre + 1;

-- Décrémentation nombre--;

nombre = nombre - 1;

y = x++ y = x x = x + 1

y = ++x x = x + 1 y = x

Page 23: Cours - Programmation C pour systèmes embarqués

Université de Savoie 23

Lisibilité du code C#include <stdio.h>main(t,_,a)char*a;{return!0<t?t<3?main(-79,-13,a+main(-87,1-

_,main(-86,0,a+1)+a)):1,t<_?main( t+1, _, a ):3,main( -94, -27+t, a )&&t == 2 ?_<13 ?main ( 2, _+1, "%s %d %d\n" ):9:16:t<0?t<-72?main( _, t,"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l,+,/n{n+,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# ){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#n'wk nw' iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c ;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# }'+}##(!!/"):t<-50?_==*a ?putchar(31[a]):main(-65,_,a+1):main((*a == '/') + t, _, a + 1 ):0<t?main ( 2, 2 , "%s"):*a=='/'||main(0,main(-61,*a, "!ek;dci@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"),a+1);}

Page 24: Cours - Programmation C pour systèmes embarqués

Université de Savoie 24

Lisibilité du code C

Règle à respecter :Mettre des commentaires explicitesNe pas trop compresser le codeRespecter une homogénéité dans votre façon de coder.Organiser la mise en page de votre code, ou respecter celle déjà existante.

Page 25: Cours - Programmation C pour systèmes embarqués

Université de Savoie 25

Les types de variables

char = 1 octet (signed ou unsigned)Int, long, double, float dépendent de la cible processeur utilisée.

Afin de connaître la taille (en octet) d’une variable, on utilise la fonction sizeof() :

printf(’’ int=%d octets ’’, sizeof(int));

Note : Il n’existe pas de type Booléen en C

Page 26: Cours - Programmation C pour systèmes embarqués

Université de Savoie 26

Les types de variablesCas d’une compilation pour processeur 32 bits

Voir le cas d’un compilateur C pour PIC16F ou PIC18F (microchip)

Voir le cas d’un compilateur C pour DSP TMS320 (Texas Instruments) (page suivante)

Page 27: Cours - Programmation C pour systèmes embarqués

Université de Savoie 27

Les types de variables

Page 28: Cours - Programmation C pour systèmes embarqués

Université de Savoie 28

Les types de variablesDonner la représentation binaire des nombres suivants :

char a=64;unsigned char b=64;char c=128;unsigned char d=128;

Quel est l’affichage des fonctions suivantes?printf(’’%d », a);printf(’’%d », c);printf(’’%u », a);printf(’’%u », c+a);

Note : Une déclaration est signed par défaut. Note : %d -> entier signed / %u -> entier unsigned

Page 29: Cours - Programmation C pour systèmes embarqués

Université de Savoie 29

Les types de variables

Conversion explicite :La conversion de type consiste à transformer un type de valeur en un autre, en respectant la syntaxe suivante(<type>) <expression>

Conversion implicite : Lorsque les deux opérandes sont de type différent, le compilateur prévoit une conversion implicite suivant l'ordre : { char -> int -> long -> float -> double } et { signed -> unsigned }

Page 30: Cours - Programmation C pour systèmes embarqués

Université de Savoie 30

Les types de variablesDécrivez le conversion du type, ainsi que les affectations du code suivant :

int main(void){int n, m, l;double d;d = 5; n = (int) 3.4; n = 1;m = 5;d = 2;l = (int) (m / d); d = n / m; d = n / ((double) m); d = 'A' * 6.0 – m + 0xA2CL;return 0;}

Page 31: Cours - Programmation C pour systèmes embarqués

Université de Savoie 31

Portée des variablesstatic : permet à une variable locale d’être persistante et donc de conserver sa valeur pendant les appels successifs de la fonction.

#include <stdio.h>void f(void) {static int i = 0; /* i ne sera initialisé qu’une fois*/int j = 0; /* j sera initialisé à chaque fois */;

i++;j++;printf("i vaut %d et j vaut %d.\n", i, j);}

int main(void) {f();f();f();return 0;

}

Page 32: Cours - Programmation C pour systèmes embarqués

Université de Savoie 32

Portée des variables

static : Cas des variables globales.

Une variable globale est déjà persistante. L’objectif de la nommer en « static » est simplement de la « privatiser » au fichier où elle est déclarée. C’est-à-dire qu’elle ne pourra pas être utilisée depuis un autre fichier.

Page 33: Cours - Programmation C pour systèmes embarqués

33

Portée des variablesextern : permet de spécifier que la variable a été déclarer dans un autre fichier. Si on omet ce terme, une nouvelle variable estcréer avec une nouvelle allocation mémoire.

/* File : ext.c */

#include <stdio.h>

void next(void);void next1(void);int a1=1; /* definition of external (non static)*/

void main(void){a1=2;printf("a1=%d\n",a1); // a1=2next(); next1();printf("a1=%d\n,a1);

}

Page 34: Cours - Programmation C pour systèmes embarqués

34

Portée des variables/* File file1.c */int b1=0;void next(void){

char a1;a1='a';b1=77;

}

/* File file2.c */extern int a1;void next1(void){

float b1;b1=19.2;a1=13;

}

Page 35: Cours - Programmation C pour systèmes embarqués

Université de Savoie 35

Qualificateur de variablesLe C définit des qualificateurs pouvant influer sur une variable :

const : pour définir une variable dont la valeur ne devrait jamais changer ; volatile : désigne une variable pouvant être modifiée notamment par une source externe indépendante du programme.

Une variable peut avoir plusieurs qualificateurs

Page 36: Cours - Programmation C pour systèmes embarqués

Université de Savoie 36

Qualificateur de variables

Qualificateur 'const'La classe const indique au compilateur que la valeur de la variable ne doit pas changer. Il est donc impératif d'assigner une valeur à la déclaration de la variable, sans quoi toute tentative de modification ultérieure entraînera une erreur de la part du compilateur :

Étudier les codes suivants :

const int i = 0;i = 1;

Page 37: Cours - Programmation C pour systèmes embarqués

Université de Savoie 37

Qualificateur de variables

char * const pointeur = "Salut tout le monde !";pointeur = "Hello world !";

void fonction( const char * pointeur ){

pointeur[0] = 0;pointeur = "Nouvelle chaîne de caractères";

}

const char * const pointeur = "Salut tout le monde !";pointeur = "Hello world !";pointeur[0] = 0;

Page 38: Cours - Programmation C pour systèmes embarqués

Université de Savoie 38

Qualificateur de variables

Qualificateur 'volatile'Ce mot-clé sert à spécifier au compilateur que la variable peut être modifiée à son insu. Cela annule toute optimisation que le compilateur pourrait faire, et l'oblige à procéder à chaque lecture ou écriture dans une telle variable tel que le programmeur l'a écrit dans le code.

On peut combiner const et volatile dans certaines situations. Par exemple :

extern const volatile int horloge_temps_reel; >>déclare une variable entière, qu'on ne peut modifier à partir du

programme, mais dont la valeur peut changer quand même. Elle pourrait désigner une valeur incrémentée régulièrement par une horloge interne.

Page 39: Cours - Programmation C pour systèmes embarqués

Université de Savoie 39

Évaluation des expressions booléennes (1)

Le C ne possède pas de type booléen dédié. Dans ce langage, n'importe quelle valeur différente de zéro est considérée vraie, zéro étant considéré comme faux. Ce qui veut dire que n'importe quelle expression peut être utilisée à l'intérieur des tests (entier, réels, pointeurs, tableaux, etc.). Cela peut conduire à des expressions pas toujours très claires, comme :

On préférera :

Attention :

int a;a = une_fonction();if (a) { /* ... */ }

int a;a = une_fonction();if (a != 0) { /* ... */ }

int a = 0; b = 2;if (a = b) { /* Le code qui suit sera toujours exécuté ... */ }

Page 40: Cours - Programmation C pour systèmes embarqués

Université de Savoie 40

Évaluation des expressions booléennes (2)

Les opérateurs logiques de comparaisons (&& et ||, similaires sémantiquement à leur équivalent binaire & et |) ont une exécution totalement différente.Dans le cas du ET logique (&&), si l'opérande gauche s'évalue àfaux (valeur zéro), on sait déjà que le résultat du ET sera faux et donc ce n'est pas la peine d'évaluer l'opérande droite. De la même manière si l'opérande gauche d'un OU logique (||) est évalué à vrai, le résultat sera aussi vrai (valeur !=0) et donc l'évaluation de l'opérande droite est inutile.

if (z != 0 && a / z < 10){printf("Tout va bien\n");}

Page 41: Cours - Programmation C pour systèmes embarqués

Université de Savoie 41

Les manipulations de bits (1)Les manipulations de bits sont beaucoup utilisées dans l’embarqué. Pour contrôler un périphérique matériel, on retrouve des registres de 8, 16 ou 32 bits qu’il faut modifier.Mettre à 1 le bit 4 de a :

Mettre à zéro le bit 3 de a :

unsigned a = 0x000F; /* 0000 0000 0000 1111 */

unsigned a = 0x000F; /* 0000 0000 0000 1111 */

Page 42: Cours - Programmation C pour systèmes embarqués

Université de Savoie 42

Les manipulations de bits (1)Les manipulations de bits sont beaucoup utilisées dans l’embarqué. Pour contrôler un périphérique matériel, on retrouve des registres de 8, 16 ou 32 bits qu’il faut modifier.Mettre à 1 le bit 4 de a :

Mettre à zéro le bit 3 de a :

unsigned a = 0x000F; /* 0000 0000 0000 1111 */ unsigned b = 0x0010; /* 0000 0000 0001 0000 */ unsigned c = a | b; /* 0000 0000 0001 1111 soit 0x001F */

unsigned a = 0x000F; /* 0000 0000 0000 1111 */ unsigned b = 0xFFF7; /* 1111 1111 1111 0111 */ unsigned c = a & b; /* 0000 0000 0000 0111 soit 0x0007 */

Page 43: Cours - Programmation C pour systèmes embarqués

43

Les manipulations de bits (2)

Tester si le bit 2 de a est à 1 :

Tester si le bit 3 de a est à 1 et si le bit 15 est à 0 :

unsigned a = 0x000F; /* 0000 0000 0000 1111 */

unsigned a = 0x000F; /* 0000 0000 0000 1111 */

Page 44: Cours - Programmation C pour systèmes embarqués

44

Les manipulations de bits (2)

Tester si le bit 2 de a est à 1 :

Tester si le bit 3 de a est à 1 et si le bit 15 est à 0 :

unsigned a = 0x000F; /* 0000 0000 0000 1111 */if (a & (1u << 2)) { printf("bit 2 = 1"); }

else { printf("bit 2 = 0");

}

unsigned a = 0x000F; /* 0000 0000 0000 1111 */if ( (a & (1u << 3)) && (a&(1u<<15))==0 ) { printf("bit 2 = 1 et bit 15=0"); }

else { printf("bit 2 = 1 et bit 15=0 n’est pas vérifié");

}

Page 45: Cours - Programmation C pour systèmes embarqués

Université de Savoie 45

Le main()Le main() est le point d’entrée d’une application. Dans un système embarquée sans système d’exploitation, le point d’entrée du programme sera précisé dans la phase d’édition de liens par l’initialisation du vecteur d’interruption nommé RESET.

Page 46: Cours - Programmation C pour systèmes embarqués

Université de Savoie 46

A quoi sert un pointeur ?

Page 47: Cours - Programmation C pour systèmes embarqués

Université de Savoie 47

Les tableaux (1)Un tableau est un regroupement consécutif de donnée de même type et de taille fixe.

// Tableau à 1 dimension

void main(void){

int tableau[4];int i;

for(i=0i<4;i++){tableau[i]=0;}

}

// Tableau à 2 dimensions

void main(void){

int tableau[4][3];jnt i,j;

for(i=0i<4;i++){for(j=0;j<3;j++){tableau[i][j]=0;}

}}

Page 48: Cours - Programmation C pour systèmes embarqués

Université de Savoie 48

Les tableaux (2)

tableau[3]tableau[2]tableau[1]tableau[0]

tableau[3][2]tableau[3][1]

tableau[2][2]tableau[2][1]

tableau[1][2]tableau[1][1]

tableau[0][2]tableau[0][1]

tableau[3][0]

tableau[2][0]

tableau[1][0]

tableau[0][0]

Page 49: Cours - Programmation C pour systèmes embarqués

Université de Savoie 49

Les tableaux (3)

Passage de paramètre des tableaux àdes fonctions :Un tableau n’est jamais passé en paramètre, c’est son adresse qui est fournie.

Page 50: Cours - Programmation C pour systèmes embarqués

Université de Savoie 50

Organisation logicielle

0x00000000

0xFFFFFFFF

address space

code segment(=program)

Data : (static and global)

heap(dynamically allocated)

stack

PC (Program Counter)

SP (Stack Pointer)

data segment

Page 51: Cours - Programmation C pour systèmes embarqués

Université de Savoie 51

Organisation logicielleCode segment : Emplacement ou se trouve le code compilé.Data segment :

Data : contient toutes les variables « static » et « globales »(initialisées ou non)Heap : Le tas est géré dynamiquement. C’est une zone de donnée qui grossi à la réservation de zone mémoire (malloc) et qui se réduit lors de la libération (free).

Stack : C’est une zone de stockage de type LIFO. Elle contient les adresses de retour des fonctions et les variables locales. Cette zone mémoire est beaucoup plus rapide que l’utilisation du Heap.

Page 52: Cours - Programmation C pour systèmes embarqués

Université de Savoie 52

Optimisation du codeDans le contexte de l’embarqué, il est important de connaître les options de compilation d’optimisation. Il y a en effet un compromis àtrouver entre la taille de l’exécutable produit et le temps d’exécution.

Page 53: Cours - Programmation C pour systèmes embarqués

Université de Savoie 53

Optimisation du codeOption -O0 (niveau 0)

Allocates variables to registersPerforms loop rotationEliminates unused codeSimplifies expressions and statements

Option -O1 (niveau 1)Performs all -O0 optimizations, and:Removes unused assignmentsEliminates local common expressions

Option -O2 (niveau 2) (default optimization level)Performs all -O1 optimizations, and:Performs loop optimizations