Académique Documents
Professionnel Documents
Culture Documents
Optimiser Le C Embarque PDF
Optimiser Le C Embarque PDF
Embarque
Contraintes, particularits
1.
Gnralits ................................................................................................................................................. 2
2.
a.
b.
3.
Interruptions ................................................................................................................................................ 5
4.
5.
6.
a.
b.
7.
Christian Dupaty
Professeur dlectronique
christian.dupaty@ac-aix-marseille.fr
C embarqu
1. Gnralits
Programmer un microcontrleur en langage C dans, quelles diffrences avec un ordinateur, quelles
contraintes ?
Le compilateur C pour microcontrleur est gnralement compatible C ANSI, il gnre un fichier en
assembleur propritaire qui aprs assemblage produit un fichier de codes machines et oprandes pour la
cible.
Le langage C a t conu il y a plus de 30 ans pour de gros systmes informatiques puis a t standardis
pour une utilisation sur ordinateur personnel. Les langages objets (en particulier le C++) lont vite remplac
sur ces derniers.
Le langage C nest aujourdhui pratiquement utilis que pour le dveloppement de programmes sur
microcontrleurs (pour lesquels il na donc pas t conu au dpart).
Les programmes sur microcontrleurs ne sont pas placs en RAM comme dans un ordinateur mais en
ROM. En effet, il ny a pas de systme dexploitation (Windows, MAC, LINUX) ni de BIOS sur un
microcontrleur, le programme de ce dernier est lanc la mise sous tension et ne finit jamais, il y a
donc une boucle sans fin.
Dans un ordinateur, programme, variables et constantes sont tous chargs depuis la mmoire de masse
(disque dur) par le systme dexploitation dans la RAM de la machine avant excution les zones
programmes et constantes tant interdites en criture. Dans un microcontrleur, le programme et les
constantes sont logs dfinitivement en ROM.
Les systmes embraqus fonctionnent sur batterie, le principal objectif de dveloppement est
lautonomie maximale. Le microcontrleur doit donc pouvoir tre plac en mode veille le plus souvent
possible. Une programmation vnementielle par interruption est donc indispensable.
- Un programme C embraqu devra toujours contenir une boucle sans fin : while(1)
Cette boucle contiendra un code minimum (ou pas de code). while(1) { }
- Si le microcontrleur le permet la boucle contiendra une instruction de mise en veille et basse
consommation, le microcontrleur se rveillant lors dun vnement dclenchant une interruption.
- Les constantes seront places en ROM.
- La programmation sera vnementielle (interruptions).
2. Gestion de la mmoire
Les microcontrleurs possdent une mmoire ROM (souvent EEPROM FLASH) importante (32KO 1024
KO) mais une mmoire RAM ne dpassant que rarement les 2KO. (Les transistors intgrs sur la puce sont
consacrs de prfrence aux priphriques plutt qu la mmoire) Il faut donc conomiser lespace
RAM.
Le linker place le module CRT (C Run Time) en dbut de programme avant la fonction main. Le CRT
initialise la/les piles, les variables et les constantes. Les valeurs dinitialisation des constantes se trouvent
forcement en ROM et sont recopies par le CRT en RAM. Cela na aucun intrt pour les constantes, qui par
essence ne seront jamais modifies, cependant le C ANSI en raison de son histoire place les constantes en
RAM.
Dans un microcontrleur les constantes doivent systmatiquement tre places en ROM. Il existe en
C embarqu un qualificatif indiquant la mmoire cible.
const unsigned int i =1234 ;
ram const unsigned int i =1234 ;
rom const unsigned int i =1234 ;
christian.dupaty@ac-aix-marseille.fr
optimiser le C embarque
2/9
C embarqu
Exemple de compilation pour une adition 8bits+8bits en C18, le processeur cible est un P18F2620
8bits
Dans les PIC18 le registre W est laccumulateur (8bits) destin aux oprations arithmtiques et logiques
00CE
00D0
00D2
00D4
00D6
0100
518A
258B
0100
6F8C
00D8
D7FF
Exemple dadition 16bits+16bits en C18, le processeur cible est un P18F2620 8bits, le calcul est
beaucoup plus long !!!
00CE
00D0
00D2
00D4
00D6
00D8
00DA
00DC
00DE
00E0
0100
518A
258C
0100
6F8E
0100
518B
218D
0100
6F8F
00E2
D7FF
int a=2;
int b=3;
int c;
void main(void)
{
c=a+b;
MOVLB 0
MOVF 0x8a, W, BANKED
ADDWF 0x8c, W, BANKED
MOVLB 0
MOVWF 0x8e, BANKED
MOVLB 0
MOVF 0x8b, W, BANKED
ADDWFC 0x8d, W, BANKED
MOVLB 0
MOVWF 0x8f, BANKED
while(1);
BRA 0xe2
}
christian.dupaty@ac-aix-marseille.fr
optimiser le C embarque
3/9
C embarqu
L'inconvnient des variables globales "dynamiques" est leur temps daccs. Le principal avantage est
l'optimisation de l'utilisation de l'espace mmoire RAM souvent petit sur les microcontrleurs.
Voici trois exemples du mme programme qui met en vidence la ncessit d'un compromis "vitesse
d'excution" "taille du code" "scurit des donnes"
Cadre de gauche , le source en C, cadre de gauche, l'assembleur gnr par le compilateur (C18)
Addition sur des variables globales - Un programmeur en assembleur aurait produit le mme code
//3 globales
char a;
char b;
char c;
void main (void)
{
a=0;
b=2;
c=3;
a=b+c;
while(1);
}
; a a t plac en 0x8a
; b a t plac en 0x8b
; c a t plac en 0x8c
; b dans w
; b+c dans w
; w dans a
La mme addition mais sur des variables locales automatiques, cela devient beaucoup plus compliqu
en raison des accs par pointeurs dans la pile
0000CA
0000CC
0000CE
0000D0
0000D2
0000D4
CFD9
FFE6
CFE1
FFD9
0E03
26E1
0000D6 6ADF
void main (void)
{
// 3 locales
char a=0;
char b=2;
char c=3;
a=b+c;
while(1);
}
0000D8 52DE
0000DA 0E02
0000DC 6EDD
0000DE
0000E0
0000E2
0000E4
0000E6
0E03
6EF3
0E02
CFF3
FFDB
0000E8
0000EA
0000EC
0000EE
0000F0
0000F2
0000F4
CFDB
FFE6
0E01
50DB
52E5
24E7
6EDF
0000F6 D7FF
christian.dupaty@ac-aix-marseille.fr
void main
MOVFF 0xfd9, 0xfe6
NOP
MOVFF 0xfe1, 0xfd9
NOP
MOVLW 0x3
ADDWF 0xfe1, F, ACCESS
{ char a=0;
CLRF 0xfdf, ACCESS
char b=2;
MOVF 0xfde, F, ACCESS
MOVLW 0x2
MOVWF 0xfdd, ACCESS
char c=3;
MOVLW 0x3
MOVWF 0xff3, ACCESS
MOVLW 0x2
MOVFF 0xff3, 0xfdb
NOP
a=b+c;
MOVFF 0xfdb, 0xfe6
NOP
MOVLW 0x1
MOVF 0xfdb, W, ACCESS
MOVF 0xfe5, F, ACCESS
ADDWF 0xfe7, W, ACCESS
MOVWF 0xfdf, ACCESS
while(1);
BRA 0xf6
optimiser le C embarque
(void)
; b dans 0xfdd
; c dans 0xfdb
; c dans fe6
; c dans w
; w+ ? dans s w
; w dans a
4/9
C embarqu
Addition sur des variables locales statiques on retrouve le mme code assembleur que pour les
variables globales
Les variables locales statiques sont gres comme les variables globales, elles restent cependant invisibles
en dehors de la fonction qui les dclare.
3. Interruptions
Le C ne sait pas traiter les interruptions. Lors de sa standardisation, la programmation vnementielle
tait beaucoup moins dveloppe quaujourdhui. (Beaucoup moins de priphriques embarqus)
La gestion des interruptions impose :
- De placer le code de traitement une adresse impos par le microcontrleur (vecteur dinterruption)
- De terminer le sous programme dinterruption par une instruction retour dinterruption la place dun
simple retour . (Lors dune interruption, gnralement tout le contexte des registres du microcontrleur est
sauv dans la pile, ce qui nest pas le cas lors de lappel dun simple de sous programme)
Le C possde une directive de compilation #pragma qui permet lditeur du compilateur dadapter le C la
cible. Ces directives ne sont pas standards et leur nom change dun diteur lautre.
Il existe une directive #pragma forcer_adresse qui force le linker placer le code une adresse prcise.
Il existe une directive #pragma cette_fonction_est_une_interruption qui indique au compilateur de placer
la fin de la fonction une instruction de retour de sous programme dinterruption.
Exemple en C18 (Microchip)
#pragma code vecteur_d_IT=0x08
void une_fonction(void)
{
_asm goto traite_IT _endasm
}
#pragma code
christian.dupaty@ac-aix-marseille.fr
optimiser le C embarque
5/9
C embarqu
NAME=vectors START=0x0
END=0x29
PROTECTED
NAME=page
START=0x2A
END=0x7DBF
NAME=debug START=0x7DC0
END=0X7FFF
PROTECTED
NAME=idlocs
START=0x200000
END=0x200007
PROTECTED
NAME=config
START=0x300000
END=0x30000D
PROTECTED
christian.dupaty@ac-aix-marseille.fr
optimiser le C embarque
6/9
C embarqu
CODEPAGE
CODEPAGE
NAME=devid
NAME=eedata
START=0x3FFFFE
START=0xF00000
END=0x3FFFFF
END=0xF000FF
PROTECTED
PROTECTED
char c;
void main (void)
{
drap1.bit2=1;
// le bit 2 de drap1 est mis 1
c=drap2.bit5;
// c prend la valeur du bit 5 de drap2 ( o ou 1)
if (drap1.bit5) drap2.bit4=0;
// le bit 4 de drap2 est mis 0 si le bit 5 de drap1 est 1
while(1);
}
christian.dupaty@ac-aix-marseille.fr
optimiser le C embarque
7/9
C embarqu
Les broches dun microcontrleur peuvent trs souvent changer de fonction et donc de nom suivant la
configuration choisie.
Pour grer cette particularit il est possible par une union de donner plusieurs noms un bit.
volatile near union {
struct {
unsigned RE0:1;
unsigned RE1:1;
unsigned RE2:1;
unsigned RE3:1;
unsigned RE4:1;
unsigned RE5:1;
unsigned RE6:1;
unsigned RE7:1;
} ;
struct {
unsigned ALE:1;
unsigned OE:1;
unsigned WRL:1;
unsigned WRH:1;
unsigned :3;
unsigned CCP2:1;
PORTEbits.RE0
PORTEbits.ALE
PORTEbits.AN5
Partagent le mme bit physique
} ;
struct {
unsigned AN5:1;
} ;
} PORTEbits ;
while (!PORTAbits.RA0);
ou
christian.dupaty@ac-aix-marseille.fr
while (PORTAbits.RA0);
optimiser le C embarque
8/9
C embarqu
char *) 0x10)
// equivalence de dcalage
// positionne le bit b de l'octet p 1
// positionne le bit b de l'octet p 0
//
//
//
//
//
//
le
le
le
un
le
le
bit 3
bit 3
bit 3
test
bit 5
bit 5
de mamem passe 1
de mamem passe 0
de mamem bascule
de mamem passe 1
de mamem passe 0
7. Tableaux ou Pointeurs
Les faibles espaces mmoires des microcontrleurs peuvent parfois tre rsolus grce une meilleure
gestion de la RAM et de la ROM La dclaration d'un tableau rserve la taille mmoire (RAM ou ROM)
dclare. La dclaration d'un pointeur ne rserve rien.
Exemple, la fonction char *mois(char i); qui retourne un pointeur sur une chane de caractres.
a) criture avec un tableau
char *mois(char i)
{
const char nomdumois[12 ][10]={"janvier","fvrier","mars","avril",...};
return nomdumois[i];
}
Occupation mmoire 12 mois de 10 caractres max = 120 octets, on rserve de la place inutilement,
exemple pour le mois de mai le tableau contient
m a i \0 \0 \0 \0 \0 \0 \0
donc 6 octets inutiliss
b) criture avec un tableau de pointeurs
char *mois(char i)
{
const char *nomdumois[ ] = { "janvier","fvrier","mars","avril", ..};
return nomdumois[i];
}
nomdumois
janvier\0
nomdumois +1 fvrier\0
nomdumois +2 mars\0
nomdumois +3 avril\0
nomdumois +4 mai\0
....
8 octets
8 octets
5 octets
6 octets
4 octets
Occupation mmoire : 8 + 8 + 5 +6 + 4 +.... L'occupation mmoire correspond la somme des tailles des
chanes, la gestion mmoire est bien meilleure.
christian.dupaty@ac-aix-marseille.fr
optimiser le C embarque
9/9