Réception d’une erreur «symboles non définis» avec XC8 concernant les fonctions plib I2C

Salut StackOverflow!

Ma question concerne les erreurs de rapport dans le programme collé (loin) ci-dessous. Le périphérique cible est le PIC12LF1552 . Il comporte un périphérique série qui, je le supposais, pourrait être utilisé avec la bibliothèque fournie avec le compilateur XC8 de Microchip. Certaines sources sur Internet ont déclaré que seuls les appareils haut de gamme de la ligne PIC18 prendraient en charge les fonctions de bibliothèque, d’autres sources ont déclaré que les fonctions de bibliothèque fonctionnaient parfaitement. J’ai donc décidé que je ne voulais pas réécrire les fonctions I2C à partir de rien, ni écrire d’assemblage pour ce projet. Je me suis donc décidé à utiliser la bibliothèque de périphériques fournie, fournie avec XC8. J’ai lu sur la documentation du compilateur pour savoir comment les obtenir (comme indiqué dans i2c.h ci-dessous). Je sais qu’il y a des erreurs à vérifier sur ces commandes conformément à la documentation et à quelques exemples que j’ai vus, mais pour le moment, je suppose que le maître et l’esclave se comporteront parfaitement pour que je puisse obtenir cette information. le sol.

J’ai inclus tous les chemins pertinents, c’est pourquoi je suppose que cela va aussi loin dans le processus de compilation. Mon niveau de connaissance en ce qui concerne le fonctionnement interne d’un langage C et d’un compilateur est très limité. Je sais seulement comment utiliser ces outils à un niveau élémentaire. Il se peut donc que quelque chose de fondamental me manque ici.

Quoi qu’il en soit, lorsque je comstack ce code dans MPLABX v1.95, je reçois ceci:

:0: error: undefined symbols: _AckI2C(dist/pickit3/production\strobe.X.production.obj) _ReadI2C(dist/pickit3/production\strobe.X.production.obj) _IdleI2C(dist/pickit3/production\strobe.X.production.obj) _OpenI2C(dist/pickit3/production\strobe.X.production.obj) _StopI2C(dist/pickit3/production\strobe.X.production.obj) _NotAckI2C(dist/pickit3/production\strobe.X.production.obj) _WriteI2C(dist/pickit3/production\strobe.X.production.obj) _StartI2C(dist/pickit3/production\strobe.X.production.obj)

Je ne trouvais rien de pertinent sur Google, StackOverflow ou autre problème concernant ce problème dans mon contexte spécifique (un autre gars avait un problème très similaire lors du portage à partir du compilateur C18 de Microchip, mais j’avais déjà fait tout ce qu’il avait fait pour résoudre son problème) .

Je suppose donc que la question est de savoir pourquoi cette erreur de compilation est générée et quel est le mécanisme sous-jacent à cette erreur dans le langage C ou la mise en oeuvre par Microchip.

 /* * File: i2c.h * Author: James * * Created on July 23, 2014, 9:02 PM */ #ifndef I2C_H #define I2C_H #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #include  #include  #define SLAVE_ADDRESS 0b11110000 void Connect(); void Disconnect(); void Read(unsigned char address, unsigned char * data, unsigned char length); void Write(unsigned char address, unsigned char * data, unsigned char length); #endif /* I2C_H */ #include "i2c.h" void Connect() { OpenI2C(MASTER, SLEW_OFF); } void Disconnect() { CloseI2C(); } void Read(unsigned char address, unsigned char * data, unsigned char length) { IdleI2C(); // Wait until the bus is idle StartI2C(); // Send START condition IdleI2C(); // Wait for the end of the START condition if (WriteI2C(SLAVE_ADDRESS | 0x01)) return; // Send slave address with R/W cleared for write IdleI2C(); // Wait for ACK if (WriteI2C(address)) return; // Send register address IdleI2C(); // Wait for ACK for(int i = 0; i < length; i++) { data[i] = ReadI2C(); // Write nth byte of data AckI2C(); // Wait for ACK } NotAckI2C(); // Send NACK StopI2C(); // Hang up, send STOP condition } void Write(unsigned char address, unsigned char * data, unsigned char length) { IdleI2C(); // Wait until the bus is idle StartI2C(); // Send START condition IdleI2C(); // Wait for the end of the START condition if (WriteI2C(SLAVE_ADDRESS | 0x01)) return; // Send slave address with R/W cleared for write IdleI2C(); // Wait for ACK if (WriteI2C(address)) return; // Send register address IdleI2C(); // Wait for ACK for(int i = 0; i < length; i++) { WriteI2C(data[i]); // Write nth byte of data IdleI2C(); // Wait for ACK } StopI2C(); // Hang up, send STOP condition } /* * File: main.c * Author: James * * Created on July 14, 2014, 11:00 PM */ /******************************************************************************/ /* Files to Include */ /******************************************************************************/ #if defined(__XC) #include  /* XC8 General Include File */ #endif #include  /* For uint8_t definition */ #include  /* For true/false definition */ #include  #include  #include  #include "i2c.h" /******************************************************************************/ /* Defines */ /******************************************************************************/ //#define SYS_FREQ 16000000L //#define FCY SYS_FREQ/4 #define _XTAL_FREQ 500000 __CONFIG ( MCLRE_ON & CP_OFF & BOREN_OFF & WDTE_OFF & PWRTE_OFF & FOSC_INTOSC ); void main(void) { ANSELA = 0; TRISA = 0b101111; OPTION_REG = 0b01111111; APFCONbits.SDSEL = 1; unsigned char state = 0; unsigned char count = 0; unsigned char data[8] = { 0 }; Connect(); Read ( 0x01, // System register data, // Data buffer 0x01 // Read length ); LATAbits.LATA4 = data[0]; while(1) { switch (state) { case 0: // IDLE/OFF if (LATAbits.LATA4) LATAbits.LATA4 = 0; break; case 1: // ON if (!LATAbits.LATA4) LATAbits.LATA4 = 1; break; case 2: // BLINK (slow) LATAbits.LATA4 = !LATAbits.LATA4; __delay_ms(100); break; case 3: // BLINK (fast) LATAbits.LATA4 = !LATAbits.LATA4; __delay_ms(50); break; case 4: // BEAT DETECT LATAbits.LATA4 = PORTAbits.RA5; break; default: state = 0; break; } if (TMR0 > 0) { while (count < 20) { if (!PORTAbits.RA2) count = 0; __delay_ms(10); count++; } TMR0 = 0; state++; } } } 

    Définition du problème

    Le problème principal est que la bibliothèque de périphériques Microchip XC8, à l’instar de son prédécesseur, la bibliothèque de périphériques C18 ne prend pas en charge les microcontrôleurs en dehors de la série PIC18. Donc, il y a tout un tas de fichiers d’en-tête qui configurent correctement les périphériques et toutes les macros de registre sont spécifiques à la ligne PIC18, bien qu’il existe de nombreuses similitudes.

    Solution / Contournement

    Cependant, comme Microchip fournit les sources à leur bibliothèque de périphériques dans ce répertoire: /path/to/xc8/install/directory/version/sources/pic18/plib

    Plus précisément dans mon cas pour les sources i2c sur une machine Windows x64: C:\Program Files (x86)\Microchip\xc8\v1.21\sources\pic18\plib\i2c

    Pour le PIC12LF1552 , la puce possède un MSSP. Vous devrez donc copier les sources i2c _ *. C et les concaténer. Si vous avez des utilitaires Linux / Unix sur votre PC, vous pouvez le faire: cat i2c_* > i2c.c

    Maintenant, commençons par commencer par extraire toutes les versions définies par I2C dans les fichiers ou, plus simplement, dans les parameters du compilateur xc8 sous votre profil de construction actuel et définir la macro de définition suivante: I2C_V1

    Ensuite, vous devrez apporter quelques modifications à partir de la version v1.21 des sources pour qu’elles soient compatibles avec le périphérique:

    • Dans le fichier d’en-tête de votre version de i2c.c insérez: #include pour que le rest du code dispose de tous les registres définis.
    • Ajoutez les éléments définis pour vos broches SDA et SCL dans i2c.h afin que OpenI2C () fonctionne ou changez simplement OpenI2C () pour qu’il soit spécifique au périphérique:
      • #define I2C_SCL TRISAbits.TRISA1
      • #define I2C_SDA TRISAbits.TRISA2 OU TRISAbits.TRISA3 fonction de votre paramètre APFCONbits.SDSEL . Bien que sur le PIC12LF1552, RA3 est toujours réglé sur entrée.
    • Les champs de registre suivants doivent être changés:
      • SSPSTATbits.R_W -> SSPSTATbits.R_nW
      • PIR1bits.SSPIF -> PIR1bits.SSP1IF
      • PIR2bits.BCLIF -> PIR2bits.BCL1IF
      • Les deux derniers que j’ai trouvés sont étranges, car la fiche technique les définit toujours sans le 1 avant le SI, mais qui sait, peut-être que Microchip a une raison interne spéciale à cela

    Après tout cela, vous aurez toujours besoin d’écrire vos propres wrappers pour exécuter les fonctions complètes de base pour les modes Maître / Esclave, comme je l’ai déjà dit dans ma question.

    Petite pièce d’opinion

    Tout ce processus était pire que tirer les dents, pour ainsi dire. La communauté de Microchip était arrogante ou dédaigneuse (“use assembly”, “écris-le toi-même”, etc.). Le soutien de Microchip n’a pas non plus été utile. Et en plus de cela, le code actuel nécessitait de très petites modifications orientées sur les détails qui n’ont presque aucun sens, IF -> 1IF sérieusement? Et après tout cela, vous devez écrire vos propres wrappers pour que ces fonctions puissent effectuer une transaction I2C logique, sans parler du test de l’appareil complet pour vous assurer qu’elle ne tombe pas sur le dessus. Pas étonnant que les gens qui n’ont pas de configuration et / ou de coûts personnalisés utilisent Arduinos.

    • Envisagez de réécrire le code i2c lib en utilisant le code MC plib comme sharepoint départ. Cela peut être plus rapide que de faire une conversion. En outre, considérez un autre compilateur comme celui de CCS – ils ont peut-être une bibliothèque plus robuste et mieux documentée (est-ce que quelqu’un ici a essayé cela?)

      Ouais, les documents de MC sont lamentables parfois. Je ne sais pas pourquoi un milliard de dollars co. ne peut pas faire mieux. Toutes les fonctions et les macros ne sont pas documentées et, parfois, les exemples ne sont pas réalistes, comme l’exemple du code eeprom i2c.

      J’ai également des problèmes avec cette bibliothèque, en ce sens que le code utilise le blocage des appels d’E / S et ne résout pas les problèmes de bus. Exemple: je fabrique un équipement d’essai qui teste les circuits imprimés avec des dispositifs i2c. Mais si la connexion est interrompue pendant une opération plib, le code plib ne peut plus accéder au port PIC18 i2c. C’est inacceptable pour un équipement d’essai.