Appareil: dsPIC33FJ128GP802
J'ai quelques fichiers * .s comme suit
.global _D1
.section .speex, code
_D1:
.pword 0x66C821, 0x1B0090, 0xD96C36, 0x9B60B0, 0xDD4E36, 0xBF4E53
.pword 0xD1098B, 0x719BD9, 0x873989, 0x003B69, 0x279035, 0xED4244
.pword 0xE1403C, 0x54D439, 0x826550, 0xC59627, 0xDD0432, 0x88FA29
J'ai déclaré la même chose dans un * .h
extern void D1(void);
Maintenant, je passe le D1 à une fonction de lecture de table
nowPlaying.file1 = (unsigned long) D1;
function(nowPlaying.file1);
Mon problème est que, si l'adresse de D1 est supérieure à 0X8000, la routine n'est pas correcte. J'ai essayé des modèles de code petits et grands, mais le résultat est le même. Je pense que cela est dû à la limitation de 16 bits des pointeurs Existe-t-il une méthode pour accéder à l'adresse absolue de D1 directement à partir du code. Peut être quelque chose comme une fonction intégrée ou des macros.
microcontroller
pic
microchip
compiler
Saneesh AT
la source
la source
D1
censées représenter une fonction ou un tableau de données?const short D1[]
.Réponses:
Les données que vous décrivez (utilisation complète de 24 bits de la mémoire du programme pour stocker les données) ne peuvent pas être définies et initialisées en C, et ne peuvent pas être lues directement via C; la seule façon d'y accéder est d'encapsuler dans une fonction d'assemblage appelable C ou intrinsèque.
Il y a vraiment deux questions ici:
comment bien jouer avec le compilateur, l'assembleur et l'éditeur de liens, de sorte que lorsque vous définissez vos données 24 bits dans un fichier d'assemblage en tant que données déplaçables avec un nom symbolique
D1
, plutôt que des données sans nom à une adresse fixe, le compilateur peut voir cette variable pour déterminer son adressecomment accéder aux données
La deuxième question (comment accéder aux données) est répondue pour les pièces 33EP dans DS70613C et doit être répondue pour les pièces 33FJ dans DS70204C (mais les exemples dans le manuel 33FJ n'utilisent que les 16 bits bas). Voici un exemple d'extrait de code du manuel de référence 33EP qui fonctionne pour les pièces 33EP + devrait pour 33FJ (je n'ai pas de périphérique 33FJ facilement disponible):
(Remarque: le code utilise
int
, alors qu'il serait préférable d'utiliseruint16_t
et#include <stdint.h>
)Vous remarquerez que les fonctions intégrées
__builtin_tblrdl()
et__builtin_tblrdh()
sont utilisées pour lire les mots de données bas et hauts de 16 bits à partir d'un emplacement de mémoire de programme, et__builtin_tblpage() and __builtin_tbloffset()
peuvent être utilisées pour extraire la page et le décalage de l'adresse. Dans cet exemple particulier, le tableau highWord est toujours 0 et le tableau lowWord correspond au prog_data défini et initialisé en C.Veuillez noter qu'aucun pointeur n'est utilisé ici! Bien qu'il soit possible d'utiliser des variables normales qui sont étiquetées avec
const
, afin qu'elles soient localisées par l'éditeur de liens dans l'espace programme en lecture seule, et que vous puissiez lire la mémoire en utilisant des techniques de pointeur C standard, le compilateur gérant automatiquement les registres de pagination pour vous, vous ne pouvez stocker que des données 16 bits. Vous devez accéder aux fonctions intégrées TBLRDL et TBLRDH pour obtenir les 24 bits de données.Quant à savoir comment bien jouer avec le compilateur / éditeur de liens / etc, vous devez tromper le compilateur et lui dire qu'il ne voit que des données 16 bits. Voici un exemple qui a fonctionné pour obtenir la variable D1 déclarée ailleurs:
Cela lit correctement les valeurs 24 bits et les stocke dans les 24 derniers bits d'un uint32_t. La variable extern D1 déclaré dans C est une variable factice qui ne sert à obtenir à l'adresse de départ en tirant parti de la façon dont le compilateur / assembleur / éditeur de liens de travail ensemble. Les fonctions intégrées gèrent le reste du travail.
Ce que je ne sais pas, c'est comment obtenir automatiquement la taille des données, car elles sont définies + initialisées en assembleur.
la source
Ne le convertissez pas en long et en arrière non signé. Demander des ennuis. Vous mentez au compilateur. La déclaration correcte pour nowPlaying.file1 est
Et de même pour function ():
et supprimez toutes les typecasts.
Ou, si @PeterJ le suggère, ce sont des données, elles doivent être déclarées comme externe short D1 [] aux deux endroits: et vous n'avez pas vraiment besoin de l'assembleur; vous auriez pu tout déclarer en C comme const short D1 [] = {...}; Le compilateur doit le placer dans le segment de code tel qu'il est const.
la source
Il semble que la réponse simple soit d'écrire le sous-programme dans l'assembleur. Si je me souviens bien, le C30 n'accède pas à la mémoire du programme en tant que données à l'aide de pointeurs 24 bits. Au mieux, il peut accéder à la mémoire de programme via la fenêtre PSV, mais vous ne pouvez alors voir que les 16 bits les plus faibles de chaque mot de mémoire de programme de 24 bits.
Il serait très simple d'écrire une routine d'assembleur qui peut être appelée à partir de C30 qui renvoie les 24 bits de données à une adresse de mémoire de programme de 24 bits. Cependant, vos données sont-elles une collection de valeurs de 24 bits ou vraiment une liste d'octets qui se trouvent être emballés 3 par mot? Si ce dernier, c'est encore plus facile. Écrivez une routine d'assembleur qui vous donne une vue des adresses d'octets de la mémoire du programme. L'adresse devrait toujours être de 24 bits, mais les valeurs de données ne sont plus que de 8 bits.
Ou écrivez simplement la routine entière dans l'assembleur. Si vous effectuez ce type de frappe d'octets de bas niveau et de mémoire, c'est probablement plus facile. Dans l'assembleur, vous pouvez simplement faire ce que vous voulez de la façon dont la machine veut le faire. En C, vous devez déterminer quelles incantations murmurer au compilateur pour qu'il écrive le code machine pour vous. Parfois, il est simplement plus facile de le faire directement. L'architecture dsPIC est particulièrement facile à écrire pour le code assembleur, certainement plus facile qu'un PIC 16.
la source
__builtin_tblrdX()
fonctions. Je suis d'accord avec vous + vous avez tiré un coup de pied de votre phrase "En C, vous devez comprendre quelles incantations murmurer au compilateur". Ironiquement, cependant, si vous essayez vraiment de réduire les performances maximales, les__builtin()
fonctions sont parfois meilleures, car le compilateur peut optimiser la façon dont il génère du code, alors qu'il doit traiter les fonctions d'assemblage codées à la main comme des boîtes noires qu'il ne peut pas modifier. .