Fonctions pour la gestion de la mémoire Flash

Dans le document en fr (Page 170-176)

capteurs sans fil

4.2 Implémentation de la gestion de données

4.2.2 Fonctions pour la gestion de la mémoire Flash

La première fonctionnalité attribuée au système LiveFile est la gestion de l’écriture et de la lecture de la mémoire Flash [De Sousa 2007a] [De Sousa 2007b]. Ces deux opérations font appel à des primitives bas niveau propres à la mémoire Flash utilisée qui, dans notre cas, est celle embarquée dans le microcontrôleur AT91SAM7S256.

L’accès à la mémoire Flash en lecture est obtenu en se positionnant à l’adresse mémoire où sont stockées les données recherchées (voir Figure 4.6). Les données peuvent être lues directement ou copiées dans un buffer de lecture. L’emploi d’un tel buffer permet la manipulation d’un certain nombre de registres (Figure 4.7). Avant toute écriture, les différents

CemOA : archive ouverte d'Irstea / Cemagref

verrous de protection doivent être levés. La constante « FLASH_START_ADDRESS » est fixée à « 0x00100000 ».

Figure 4.6 – Lecture de la mémoire Flash

Figure 4.7 – Ecriture dans la mémoire Flash

unsigned int flash_read(unsigned int address, void *data, unsigned int length) {

unsigned int *paddress, *padata;

paddress = (unsigned int *)address;

pdata = (unsigned int *)data;

/* lecture page par page */

if (length <= FLASH_PAGE_SIZE) { while (length > 0) {

unsigned int flash_write(unsigned int address, void *data, unsigned int length) {

/* Récupération de l’identifiant d’une page à partir de son adresse */

page = (address - (unsigned int)FLASH_START_ADDRESS) / FLASH_PAGE_SIZE;

paddress = (unsigned int *)address;

pdata = (unsigned int *)data;

/* Déverrouillage des protections de la page */

AT91C_BASE_MC->MC_FCR = AT91C_MC_CORRECT_KEY |

AT91C_MC_FCMD_CLR_GP_NVM | (AT91C_MC_PAGEN & (page << 8)) ;

/* Ecriture des données */

if (length <= FLASH_PAGE_SIZE) { while (length > 0) {

AT91C_MC_FCMD_START_PROG | (AT91C_MC_PAGEN & (page << 8) ) ;

while(!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY));

return 0;

}

CemOA : archive ouverte d'Irstea / Cemagref

Comme indiqué dans le chapitre 3, suivant les cas, un ou plusieurs buffers de pré-programmation (ou buffer cache d’écriture) sont utilisés pour insérer les données dans la mémoire Flash. La taille de ces buffers est choisie pour contenir une quantité de données en accord avec les caractéristiques de la mémoire Flash au niveau de la programmation. Dans le cas du microcontrôleur AT91SAM7S256, la taille de ces buffers peut contenir une quantité de données multiples de 4 octets. Si les données sont plus petites que le buffer, des éléments dits de bourrage (« padding ») sont ajoutés. Ce bourrage est en fait réalisé à l’initialisation du buffer. Le caractère de bourrage utilisé doit être choisi en fonction de l’application. Il doit naturellement être différent des valeurs qui peuvent être potentiellement collectées. Pour des grandeurs physiques variant de 0 à 50, le caractère « @ » (valeur ASCII de 64) peut, par exemple, être utilisé.

Avant d’effectuer des opérations sur la mémoire Flash, une étape d’initialisation est nécessaire (voir Figure 4.8).

Figure 4.8 – Initialisation de la mémoire Flash

Ces opérations d’écriture et de lecture de la mémoire Flash sont intégrées respectivement dans la primitive Out() et dans la primitive In() liées au concept LINDA étendu. Le système LiveFile gère deux formats de données : les enregistrements de données et les flux de données ou fichiers. La sauvegarde d’informations système est obtenue à l’aide de points de sauvegarde appelés « checkpoint ». Une fonction est dédiée à l’insertion de ces différents types de données. Celles-ci sont appelées à partir de la primitive Out() (voir Figure 4.9, Figure 4.10 et Figure 4.11).

L’insertion d’un fichier diffère de celle d’un enregistrement par le fait qu’elle peut requérir plusieurs pages de mémoire Flash. A l’aide de l’argument « size » qui fournit la taille du fichier à insérer, le nombre de pages de mémoire Flash nécessaires va être recherché.

Après l’écriture des données dans la mémoire Flash, les pages utilisées pour stocker le fichier seront répertoriés pour pouvoir le récupérer par la suite. Seules les pages totalement remplies sont programmées. Les données restantes sont stockées dans un buffer de pré-programmation.

Cependant, la page devant stocker ces données est connue et fait partie de la liste de celles utilisées pour stocker le fichier.

L’attribut « data_owner » est facultatif. Son utilisation est nécessaire si la fonctionnalité de sauvegarde des données sur plusieurs capteurs est activée. Pour éviter la multiplication des buffers de pré-programmation, les données issues d’un autre capteur seront directement stockées dans la mémoire Flash même si leur taille n’atteint pas le seuil d’écriture. Dans le cadre des points de sauvegarde, les données sont également écrites directement dans la mémoire Flash.

Comme indiqué précédemment, pour économiser de la mémoire, plusieurs caractères de type « char » d’une taille d’un octet peuvent être utilisés à la place d’un entier de type

« int » d’une taille de quatre octets. L’adresse d’une page au format « 0x00100000 » peut être ainsi stockée sur trois caractères plutôt qu’un entier de type long. Le stockage de l’adresse d’une page plutôt que son numéro permet de se détacher de l’organisation propre au microcontrôleur AT91SAM7S256 avec ces 1024 pages de mémoire Flash.

void flash_init() {

AT91C_BASE_MC->MC_FMR = (((MCK / 666666) << 16) & AT91C_MC_FMCN) | AT91C_MC_FWS_1FWS;

}

CemOA : archive ouverte d'Irstea / Cemagref

Figure 4.9 – Description de la fonction « record_insert() » La fonction « savepage_search() » est en charge de deux opérations :

• la recherche de pages libres ;

• la préservation des pages trop utilisées.

Pour la recherche d’une page libre, un appel à la fonction « freepage_search() » est réalisé.

Figure 4.10 – Fonctionnement de la fonction « file_insert() »

int file_insert(unsigned char* data, unsigned int size) {

Estimation du nombre de pages nécessaires au stockage du fichier Réservation des pages nécessaires au stockage

Stockage des données dans la mémoire Flash Ecriture des pages pleines

Liste des pages utilisées pour le stockage du fichier

Stockage dans le buffer de pré-programmation des données restantes Conservation de la dernière page en attente d’être programmée}

int record_insert(unsigned char *data, unsigned int size) {

/* Initialisation du pointeur d’écriture du buffer */

if (pbuffcour->indice == 0)

pbuffcour->indice = FLASH_PAGE_HEADER;

/* Test du seuil d’écriture */

if ((pbuffcour->indice + size) <= WRITE_THRESHOLD) { /* Insertion des données au buffer de pré-programmation */

} else {

/* Recherche d’une page libre */

if (savepage_search(&page_address) == -1) return -1;

/* Récupération de l’espace de la page libre après l’insertion des données */

if (pbuffcour->indice < FLASH_PAGE_SIZE)

tab_free_block[ind_free_block++] = FLASH_PAGE_SIZE – pbuffcour->indice ;

while(flash_write(page_address,(void*)pbuffcour->buff, pbuffcour->indice));

Figure 4.11 – Description de la primitive Out()

Une page contenant un point de sauvegarde est divisée en plusieurs parties dont le nombre dépend de la configuration du système LiveFile. Ces parties sont relatives aux types d’information suivants :

• la liste des pages libres ;

• la liste des emplacements libres ;

• la liste des pages préservées ;

• la liste des pages utilisées par un fichier ;

• la liste des informations liées à la gestion des propriétés.

void Out(unsigned char *Key, unsigned char *data, unsigned int size) {

explode_key(Key, data_type, data_owner, ip_address);

/* Insertion d'un enregistrement */

if (strcmp(data_type,"RECORD") == 0)

record_insert(data, size, data_owner, ip_address);

/* Insertion d'un fichier */

if (strcmp(data_type,"FILE") == 0)

file_insert(data, size, data_owner, ip_address);

/* Insertion d'un point de sauvegarde */

if (strcmp(data_type,"CHECKPOINT") == 0) checkpoint_insert();

if (tupleptr->tuple_wptr >= (unsigned char *) tupleptr ->tuple_endadr) tupleptr ->tuple_wptr = (unsigned char *) tupleptr ->tuple_staadr;

/* Insertion des données dans le tuple */

if (tupleptr->tuple_state == TUPLE_NOUSED ) tupleptr->tuple_state = TUPLE_USED ;

D’autres types d’informations pourront être rajoutés suivant l’évolution des fonctionnalités du système LiveFile. La quantité d’informations système stockée dans la mémoire Flash doit être proportionnellement faible par rapport à la quantité de données collectées. L’importance des différentes informations système et donc, de la nécessité de les sauvegarder ou non dans la mémoire Flash est établie en étudiant les caractéristiques de l’application supportée.

Au niveau de la lecture des données, l’argument « Key » est de nouveau mis à contribution (voir Figure 4.12).

Figure 4.12 – Description de la fonction In()

void In(unsigned char* Key, unsigned char* data, unsigned int* size) {

if ((Key[0] == 'f') || (Key[0] == 'r')) {

explode_key(Key, command, data_owner, ip_address);

/* lecture de données */

if (tupleptr->tuple_rptr >= (unsigned char *)tupleptr->tuple_endadr) tupleptr->tuple_rptr = (unsigned char *)tupleptr->tuple_staadr;

*data++ = *tupleptr->tuple_rptr;

tupleptr->tuple_state = TUPLE_NOUSED;

}

Le format de l’argument « Key » tel qu’il est défini dans le système LiveFile permet un accès aux données d’une page, d’un enregistrement ou d’un fichier. La primitive In() est, en fait divisée en trois parties :

• accès à la mémoire Flash ;

• interrogation des données ;

• gestion des tuples associés aux événements ou processus.

L’utilité de pouvoir récupérer le jième enregistrement d’une page « i » est à évaluer en fonction de l’application supportée. En règle générale, certains traitements associés à une fonctionnalité jugée non indispensable pour un type d’applications donné, peuvent être retirés pour réduire la taille du système LiveFile. Des fonctionnalités restent à ajouter aux différentes procédures de recherche présentées afin de prendre en compte les paramètres « data_owner » et « ip_address ». Il serait ainsi possible de récupérer à partir du capteur A, les données du capteur C (« data_owner ») qui pourrait être stockées au sein du capteur B (« ip_address »).

Dans le document en fr (Page 170-176)