2015-08-08 2 views
2

fond Je travaille sur une application embarquée écrit en C en utilisant IAR Embedded Workbench IDE et toolchain qui fonctionne sur un micro-contrôleur STM32F091 (noyau ARM Cortex-M0). L'application écrit des données dans la mémoire flash intégrée des microcontrôleurs, dans laquelle seuls les mots de 32 bits peuvent être entrés (peut-être même des demi-mots fonctionnent).Coulée de tableau d'octets offsetted à INT32 tableau en C

Description du problème Les données sont stockées dans un tableau de type octet uint8_t précédé par des informations d'en-tête au début (dans ce cas, un AT code de réponse d'un modem embarqué) qui ne devrait pas être écrit en mémoire flash. Je voudrais envoyer un pointeur uint32_t vers où dans le tampon uint8_t les données réelles commencent. Mais si ce décalage n'est pas aligné sur 4 octets, mon application se bloque car elle essaie d'accéder à un type uint32_t non aligné.

Ce décrit ce que je suis en train de faire (pas le code réel, juste un exemple):

uint8_t modemResponseBuffer[MAX_MODEM_RESPONSE_SIZE]; 

/* Get the modem response data (including modem response header data) */ 
size_t modemResponseSize = GetModemResponseData(modemResponseBuffer); 

/* Get the actual data size from the header information */ 
size_t dataSize = GetActualDataSizeFromModemResponseHeader(modemResponseBuffer); 

/* Get the offset to where the actual data starts in the modem response */ 
size_t modemDataOffset = GetModemResponseDataOffset(modemResponseBuffer); 

/* Write the data part of the response to embedded flash memory. 
The modemDataOffset can be any number which messes up 4 byte data alignment */ 
ProgramFlashMemory(DATA_FLASH_STORAGE_ADDRESS, (uint32_t*)&modemResponseBuffer[modemDataoffset], 
dataSize); 

A l'intérieur du ProgramFlashMemory fonction, la FLASH_ProgramWord fonction périphérique bibliothèque standard est appelée dans un boucle.

Question (s) Comment résoudre ce problème efficacement? Je travaille sur un système où j'ai une quantité limitée de mémoire (32 Ko de RAM), donc je préférerais ne pas copier le contenu souhaité du buffer uint8_t dans un nouveau buffer de type uint32_t. En ce moment, j'ai aligné manuellement l'octet de données par octet en passant en boucle, mais cela me semble plutôt maladroit. Mais je n'ai pas encore trouvé de meilleure solution et je suis intéressé par les suggestions que je pourrais recevoir ici.

Aussi, si quelqu'un a la connaissance, je me demande aussi pourquoi l'application plante dans ce cas. Quelle est la raison pour laquelle mon noyau (ou n'importe quel noyau?) Ne peut pas gérer les types de données non alignés?

+0

Avez-vous besoin des données d'en-tête? – alk

+0

Eh bien, j'en ai besoin pour identifier le type de données que l'application reçoit et la taille de celle-ci. Je suis désolé si cela n'était pas clair de l'exemple que j'ai fait pour montrer le problème. – Stenis

+0

Avez-vous besoin de l'en-tête après avoir écrit dans la mémoire flash? Alors que – alk

Répondre

3

changement ProgramFlashMemory() prendre un void*, puis jeté en interne que pour une uint8_t* qui vous itérer puis en prenant quatre octets à la fois dans un unit32_t que vous écrivez au flash.

Le void* permet à l'adresse de tout objet à écrire sans avoir besoin d'un casting explicite.

Quelque chose comme:

int ProgramFlashMemory(uint32_t* addr, void* data, int length) 
{ 
    int byte = 0 ; 
    int word = 0 ; 

    while(byte < length) 
    { 
     uint32_t flash_word = 0 ; 

     // Copy four bytes to word 
     // Note: little-endian byte order assumed, 
     //  reverse for big-endian. 
     // If end is not aligned, fill with 0xff. 
     for(b = 0; b < 4; b++) 
     { 
      flash_word |= byte < length ? 
          (uint8_t*)data[byte] << (b<<3) : 
          0xFF ; 
      byte++ ; 
     } 

     ProgramFlashWord(addr[word], flash_word) ; 
     word++ ; 
    } 

    // Return bytes written - may be linger than `length` by up-to 
    // three for end-alignment. 
    return byte ; 
} 

Vous pouvez vouloir garder le ProgramFlashMemory() d'origine pour les écritures alignées efficaces, dans ce cas, peut-être ProgramFlashMemoryUnaligned(). Notez que ce n'est pas seulement l'alignement, mais que la longueur n'est pas nécessairement divisible par quatre dont vous devez vous occuper.

+0

Cela semble excellent, va essayer de faire mon propre ProgramFlashMemoryUnaligned la semaine prochaine. Peut-être même en créant une fonction CheckIfAligned. – Stenis

+0

Un problème potentiel avec la vérification dynamique de l'alignement et l'utilisation de différentes fonctions pour effectuer la programmation, est que les performances de votre application peuvent varier de façon non déterministe, ce qui peut être indésirable dans les applications en temps réel. Ma proposition était d'utiliser l'opération alignée pour les objets qui étaient toujours alignés, et les non alignés pour quand ils peuvent être non alignés - simplement pour que la performance soit déterministe. – Clifford

+0

... Cela dit sur STM32 c'est largement académique - la programmation sur puce flash sur STM32 bloque le bus et bloque donc les instructions de recherche pendant des périodes considérables (jusqu'à 40ms sur STM32F1 et un énorme 800ms sur STM32F2!), Donc sur puce La programmation de la mémoire flash sur STM32 est déjà non déterministe et inadaptée aux applications en temps réel. Vous devriez faire très attention à cette "caractéristique". – Clifford

1

Cela suppose que les données d'en-tête ne sont plus nécessaires après avoir écrit les données utiles.

Pour vous assurer est correcte l'alignement du tampon, vous pouvez le déclarer comme ceci:

uint32_t modemResponseBuffer[(MAX_MODEM_RESPONSE_SIZE * sizeof (uint8_t)/sizeof (uint32_t)) + 1]; 

Il suffit de déplacer les données de charge utile au début de la mémoire tampon avant d'appeler l'auteur-fonction:

memmove(modemResponseBuffer, modemResponseBuffer + modemDataoffset, dataSize); 

Veuillez noter que memcpy() ne fonctionnerait pas ici comme destination et source de chevauchement.

appellent alors l'écrivain comme ceci:

ProgramFlashMemory(DATA_FLASH_STORAGE_ADDRESS, modemResponseBuffer, dataSize); 
+0

Merci pour votre suggestion, l'utilisation de memmove fonctionnera probablement. Cependant, comme la mémoire se chevauche (comme vous l'avez noté), memmove créera une copie temporaire des données. Ce n'est pas souhaitable car les données peuvent aller jusqu'à 2048 octets. – Stenis

+0

@Stenis: Ensuite, utilisez une boucle en utilisant 'memcpy()', juste copier seulement comme beaucoup d'octets par itération que l'en-tête utilisé pour utiliser. – alk

+0

Oui, j'ai une solution similaire en place pour le moment, mais elle ne fait que copier les octets. Penser que c'est peut-être la meilleure façon de le faire après tout, avec la modification que vous avez suggérée. – Stenis

1

La raison pour laquelle le noyau ARM Cortex-M0 se bloque sur l'accès unaligned est parce que that's what it's designed to do. La prise en compte de l'exception de panne dure est en fait une amélioration par rapport à certains anciens cœurs qui accèderaient incorrectement à la valeur et continueraient ensuite à s'exécuter avec la valeur corrompue. Certains nouveaux noyaux ARM ont un support matériel limité pour les accès non alignés.

Voici une copule de suggestions.

Redessiner ProgramFlashMemory() afin qu'il accepte un uint8_t* plutôt qu'un . Pour programmer les mots, il faut copier les octets individuels du tampon dans une variable locale qui a l'alignement correct. Ensuite, écrivez la copie de variable locale pour flasher.

Remaniement GetModemResponseData() de sorte qu'il analyse l'en-tête comme en-tête est en cours de lecture à partir du flux. Il déterminera la longueur de l'en-tête et le point de départ des données avant que les données ne soient lues dans le flux. Lorsque le flux est au début des données, il doit commencer à copier les données dans un nouveau tampon séparé de l'en-tête et correctement aligné.

+0

J'apprécie votre suggestion, ce serait certainement une option viable pour garder l'utilisation de la mémoire faible (pas minimale, mais assez faible) en utilisant des tampons séparés pour l'en-tête et les données. – Stenis

+0

Si d'autres sont intéressés par l'alignement des données et les processeurs, j'ai trouvé une question dédiée sur StackOverflow en ce qui concerne ici: http: // stackoverflow.com/questions/3025125/cpu-and-data-alignement – Stenis