MPLAB X XC32 - Seltsames Build-Problem mit flüchtigen Variablen

Ich kämpfe mit einem Problem, das mich bereits 2 Tage produktive Arbeit kostet.

Der Code von main.c am Ende der Frage ist eine abgespeckte Version des gesamten Projekts und enthält den relevanten Code, der sich auf das besprochene Problem bezieht.

Eine kurze Zusammenfassung des gesamten Setups: Mikrocontroller: PIC32MX250F128B PICkit3 MPLAB X v4.20 XC32-Compiler v1.34 Windows 10 64-Bit

Ich habe ein Projekt, bei dem Daten über den UART empfangen und bestimmte Funktionen basierend auf den empfangenen Daten ausgeführt werden. Ein Software-FIFO-Puffer wird verwendet, um die empfangenen Daten zur Verarbeitung vorübergehend zu speichern (da der Hardware-FIFO zu klein für die Rate ist, mit der Daten empfangen werden). Das Soft-FIFO wird mit den empfangenen Daten gefüllt, indem eine Interrupt-Routine verwendet wird. Ich habe ein sehr eigenartiges Problem beim Versuch, das Projekt zu erstellen (sowohl im Debug- als auch im Release-Modus).

Zuerst dachte ich, dass das unten beschriebene Problem auf ein Hardwareproblem (fehlerhaftes PICkit3) zurückzuführen ist, aber das Problem bleibt bestehen, auch wenn ich den Simulator anstelle des PICkit3 verwende. Dann habe ich mögliche Probleme mit MPLAB X untersucht, aber das gleiche Problem besteht auch in mehreren Versionen von MPLAB X (ich habe dies mit v4.05, v4.15 und v4.20 getestet). Ich habe dies auch in Windows 7 und Windows 10 getestet, mit genau den gleichen Ergebnissen. Nach weiteren Untersuchungen habe ich es auf das Soft-FIFO und die Funktion main() in main.c eingegrenzt.

Das Soft-FIFO ist wie folgt definiert (relevante Schnipsel aus main.c):

/* Software FIFO buffer size */
#define FIFO_BUFFER_SIZE (2100u)

/* Software FIFO buffer type */
typedef struct
{
    char dataBuffer[FIFO_BUFFER_SIZE];
    int firstByteIndex;
    int lastByteIndex;
    int numBytes;
} SOFT_FIFO;

/* Variables used with FIFO */
static SOFT_FIFO rxFifo = {{0}, 0, 0, 0};
static volatile BOOL fifoFlagBufEmpty = TRUE;
static volatile BOOL fifoFlagFull = FALSE;
static volatile BOOL fifoFlagOverflow = FALSE;

Hier ist der Teil in main.c, den ich weiter eingegrenzt habe, um sich auf das Problem zu beziehen:

void main(void)
{ 
    char c;

    /* ... initialisation code is here (see full main.c file)... */

    /* ... higher-level infinite loop is here (see full main.c file)... */

    /* While there is data in the software FIFO buffer */
    while (fifoFlagBufEmpty == FALSE)
    {
        /* Process data in the FIFO buffer */
        c = getByte();
        processGeneralMessage(&c);
    } /* while */

} /* main() */

Immer wenn ich das Projekt zum Debuggen erstelle (sowohl für PICKit3 als auch für den Simulator), bleibt der gesamte Erstellungsprozess einfach hängen und wird nie abgeschlossen. Es muss manuell im Windows Task-Manager beendet werden, indem der Prozess "cc1.exe" beendet wird. Nachdem ich es mehr als 2 Stunden lang versuchen und bauen ließ, denke ich, dass es ziemlich sicher ist, zu dem Schluss zu kommen, dass es den Bau überhaupt nicht abschließen wird.

Die offensichtliche Ursache des Problems scheint damit zusammenzuhängen, wie die Variable fifoFlagBufEmpty definiert und deklariert wird. Wenn ich den "flüchtigen" Bezeichner aus seiner Definition entferne:

//static volatile BOOL fifoFlagBufEmpty = TRUE; /* Old definition */
static BOOL fifoFlagBufEmpty = TRUE;

Dann wird das Projekt perfekt erstellt und der Debugger beginnt mit der Ausführung des Codes. Wenn ich den "flüchtigen" Bezeichner zurücksetze, hängt der Build wieder und wird nie abgeschlossen.

Noch bizarrer ist, wenn ich eine der folgenden zwei Zeilen im while-Block auskommentiere:

c = getByte();
processGeneralMessage(&c);

Das Projekt wird vollständig erstellt und normal ausgeführt (genau wie wenn ich den "flüchtigen" Bezeichner entferne)!

Ich habe absolut keine Erklärung dafür, warum dies geschieht. Das frustrierendste Problem ist, dass ich genau dieselbe Definition und Verwendung des Soft-FIFO in einem anderen Projekt habe, das einen anderen PIC (PIC32MX664F128H) verwendet, und es funktioniert dort perfekt. Kann mir bitte jemand dabei helfen und herausfinden, warum das passiert?

Hier ist die vollständige main.c-Datei:

/*------------------------------------------------------------------------------

    Module           : main.c

    Microcontroller  : PIC32MX250F128B

------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
                              CONFIGURATION BITS
------------------------------------------------------------------------------*/
// DEVCFG3
// USERID = No Setting
#pragma config PMDL1WAY = ON            // Peripheral Module Disable Configuration (Allow only one reconfiguration)
#pragma config IOL1WAY = ON             // Peripheral Pin Select Configuration (Allow only one reconfiguration)
#pragma config FUSBIDIO = ON            // USB USID Selection (Controlled by the USB Module)
#pragma config FVBUSONIO = ON           // USB VBUS ON Selection (Controlled by USB Module)

// DEVCFG2
#pragma config FPLLIDIV = DIV_2         // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_20         // PLL Multiplier (20x Multiplier)
#pragma config UPLLIDIV = DIV_12        // USB PLL Input Divider (12x Divider)
#pragma config UPLLEN = OFF             // USB PLL Enable (Disabled and Bypassed)
#pragma config FPLLODIV = DIV_2         // System PLL Output Clock Divider (PLL Divide by 2)

// DEVCFG1
#pragma config FNOSC = FRCPLL           // Oscillator Selection Bits (Fast RC Osc with PLL)
#pragma config FSOSCEN = OFF            // Secondary Oscillator Enable (Disabled)
#pragma config IESO = ON                // Internal/External Switch Over (Enabled)
#pragma config POSCMOD = OFF            // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF           // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1           // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSDCMD           // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576        // Watchdog Timer Postscaler (1:1048576)
#pragma config WINDIS = OFF             // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
#pragma config FWDTWINSZ = WINSZ_25     // Watchdog Timer Window Size (Window Size is 25%)

// DEVCFG0
#pragma config JTAGEN = OFF             // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx1        // ICE/ICD Comm Channel Select (Communicate on PGEC1/PGED1)
#pragma config PWP = OFF                // Program Flash Write Protect (Disable)
#pragma config BWP = OFF                // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF                 // Code Protect (Protection Disabled)

/*------------------------------------------------------------------------------
                                   INCLUDES
------------------------------------------------------------------------------*/
#define _SUPPRESS_PLIB_WARNING /* Suppress PLIB warnings */
#define _DISABLE_OPENADC10_CONFIGPORT_WARNING /* Suppress ADC warning */

#include <p32xxxx.h>
#include <plib.h>

/*------------------------------------------------------------------------------
                                    DEFINES
------------------------------------------------------------------------------*/
#define SYS_CLOCK               (40000000u) /* 40 MHz */
#define SYS_CLOCK_MHZ           (SYS_CLOCK / 1000000)
#define PB_CLOCK                (SYS_CLOCK) /* Use system clock for peripherals */
#define BAUD_RATE_COMMS         (19200u)
#define UART_MODULE             (1u)
#define BRGH_BIT                (FALSE)  

/* Missing interrupt defines in int_1xx_2xx_legacy.h */
#define mU1RXClearIntFlag() (IFS1CLR = _IFS1_U1RXIF_MASK)
#define mU1RXGetIntFlag() (IFS1bits.U1RXIF)
#define mU1RXGetIntEnable() (IEC1bits.U1RXIE)
#define mU1RXIntEnable(enable) (IEC1CLR = _IEC1_U1RXIE_MASK, IEC1SET = ((enable) << _IEC1_U1RXIE_POSITION))
#define mU1RXSetIntPriority(priority) (IPC8CLR = _IPC8_U1IP_MASK, IPC8SET = ((priority) << _IPC8_U1IP_POSITION))

/* Logic state definitions */
#define HIGH (1)
#define LOW  (0)

/* Software FIFO buffer size */
#define FIFO_BUFFER_SIZE        (2100u)

/* LED pin */
#define LED_PIN (LATBbits.LATB7)

/*------------------------------------------------------------------------------
                                LOCAL DATA TYPES
------------------------------------------------------------------------------*/
/* Software FIFO buffer type */
typedef struct
{
    char dataBuffer[FIFO_BUFFER_SIZE];
    int firstByteIndex;
    int lastByteIndex;
    int numBytes;
} SOFT_FIFO;

/*------------------------------------------------------------------------------
                            LOCAL FUNCTION PROTOTYPES
------------------------------------------------------------------------------*/
static unsigned int calcBRG(unsigned int baudRate, 
                            BOOL BRGH_bit, 
                            unsigned int clk);
static void initUART(unsigned int channel,
                     unsigned int baudRate, 
                     BOOL BRGH_bit, 
                     unsigned int clk);
static void initMain(void);
static void configureInterrupts(void);
static char getByte(void);
static void processGeneralMessage(unsigned char *c);

/*------------------------------------------------------------------------------
                                 GLOBAL VARIABLES
------------------------------------------------------------------------------*/


/*------------------------------------------------------------------------------
                                  LOCAL VARIABLES
------------------------------------------------------------------------------*/
static char rxData;
static BOOL byteReceived = FALSE;
static int rxCount = 0;
static SOFT_FIFO rxFifo = {{0}, 0, 0, 0};
static volatile BOOL fifoFlagBufEmpty = TRUE;
static volatile BOOL fifoFlagFull = FALSE;
static volatile BOOL fifoFlagOverflow = FALSE;

/*------------------------------------------------------------------------------
                           GLOBAL FUNCTION DEFINITIONS
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
  Function   : main
  Purpose    : Entry point of the system.
  Parameters : None.
  Returns    : None.
  Notes:     : None.
------------------------------------------------------------------------------*/
void main(void)
{    
    char c;

    /* Initialise the system */
    initMain();

    /* Wait for commands from the user interface */
    while (1)
    {
        /* While there is data in the software FIFO buffer */
        while (fifoFlagBufEmpty == FALSE)
        {
            /* Process data in the FIFO buffer */
            c = getByte();
            processGeneralMessage(&c);
        } /* while */
    } /* while */
} /* main() */

/*------------------------------------------------------------------------------
                            LOCAL FUNCTION DEFINITIONS
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
  Function   : initUART
  Purpose    : Initialises the UART peripheral.
  Parameters : channel - which UART channel to initialise.
               baudRate - baud rate used for UART comms
               BRGH_bit - bit to indicate high/low speed baud rate generator
               clk      - clock speed of the PIC
  Returns    : None.
  Notes      : None.
------------------------------------------------------------------------------*/
static void initUART(unsigned int channel,
                     unsigned int baudRate, 
                     BOOL BRGH_bit, 
                     unsigned int clk)
{
    /* Enable UART, BRGH = 0, simplex, RX idle LOW, 1 stop, no parity */
    unsigned int uxMode = 0x8800; 
    /* Enable RX & TX */
    unsigned int uxSta = 0x1400;
    unsigned int brg;

    brg = calcBRG(baudRate, BRGH_bit, clk);
    switch (channel)
    {
        case 1:
            U1BRG = brg;
            U1MODE = uxMode;
            U1STA = uxSta;
            break;
        case 2:
            U2BRG = brg;
            U2MODE = uxMode;
            U2STA = uxSta;
            break; 
#if (UART_COUNT_MAX >= 3)
         case 3:
            U3BRG = brg;
            U3MODE = uxMode;
            U3STA = uxSta;
            break; 
#endif
    } /* switch */
} /* initUART() */

/*------------------------------------------------------------------------------
  Function   : calcBRG
  Purpose    : Calculates the BRG value required for the UART baud rate 
               generator initialisation.
  Parameters : baudRate - baud rate used for UART comms
               BRGH_bit - bit to indicate high/low speed baud rate generator
               clk      - clock speed of the PIC
  Returns    : BRG value
  Notes      : The formula used to calculate the BRG value is obtained from the
               PIC32 Family Reference Manual, sect. 21 (UART) - in section 21.3.
------------------------------------------------------------------------------*/
static unsigned int calcBRG(unsigned int baudRate, 
                            BOOL BRGH_bit, 
                            unsigned int clk)
{
    unsigned int BRGval;    
    if (BRGH_bit == FALSE) /* low speed baud rate generator used */
    {
        BRGval = (clk / (16 * baudRate)) - 1;
    }
    else /* high speed baud rate generator used */
    {
        BRGval = (clk / (4 * baudRate)) - 1;
    }

    return BRGval;
} /* calcBRG() */

/*------------------------------------------------------------------------------
  Function   : initMain
  Purpose    : Main initialisation routine.
  Parameters : None.
  Returns    : None.
  Notes      : None.
------------------------------------------------------------------------------*/
void initMain(void)
{
    /* Initialise the system clock */
    SYSTEMConfigPerformance(SYS_CLOCK);

    /* Initialise the UART peripheral */
    initUART(1, BAUD_RATE_COMMS, FALSE, PB_CLOCK);

    /* Configure interrupts */   
    configureInterrupts();

    /* Disable JTAG */
    DDPCONbits.JTAGEN = 0;

    TRISBbits.TRISB7 = 0; /* LED pin - output */
    U1RXR = 0x00; /* U1RX on RA2 */
    RPB3R = 0x01; /* U1TX on RB3 */    
} /* initMain() */

/*------------------------------------------------------------------------------
  Function   : configureInterrupts
  Purpose    : Configure the interrupts used in this module.
  Parameters : None.
  Returns    : None.
  Notes      : None.
------------------------------------------------------------------------------*/
static void configureInterrupts(void)
{
    /* Configure UART interrupt */
    mU1RXSetIntPriority(1);    
    INTEnableSystemMultiVectoredInt();
    mU1RXIntEnable(HIGH);
    mU1RXClearIntFlag();
} /* configureInterrupts() */

/*------------------------------------------------------------------------------
  Function   : getByte
  Purpose    : Retrieve the next available data byte from the FIFO buffer.
  Parameters : None.  
  Returns    : Data byte.
  Notes      : None.
------------------------------------------------------------------------------*/
static char getByte(void)
{
    char byteValue = -1;

    /* If data exists in the buffer */
    if (rxFifo.numBytes > 0)
    {
        byteValue = rxFifo.dataBuffer[rxFifo.firstByteIndex];
        rxFifo.firstByteIndex++;
        rxFifo.numBytes--;
        //rxFifo.lastByteIndex--;
    }
    /* NOTE: this condition should actually never be reached */
    else /* If the software FIFO buffer is empty */
    {
        asm("nop"); /* TODO: Doen dalk iets hier? */
        //fifoFlagBufEmpty = TRUE; /* (Now it IS empty) */
        //return byteValue; /* with value = -1, indicating no data */
    }

    /* If the software FIFO buffer is empty, after the above read */
    /* This is the same as (numBytes == 0) */
    if (rxFifo.firstByteIndex == rxFifo.lastByteIndex)
    {
        fifoFlagBufEmpty = TRUE;
        /* Note that numBytes should now also be 0 */
    }

    /* If the index has reached the end of the buffer */
    if (rxFifo.lastByteIndex == FIFO_BUFFER_SIZE)
    {
        rxFifo.lastByteIndex = 0; /* Roll-over the index counter */       
    }

    /* If at the end of the buffer */
    if (rxFifo.firstByteIndex == FIFO_BUFFER_SIZE)
    {
        rxFifo.firstByteIndex = 0; /* Roll-over index counter */
    }

    return byteValue;
} /* getByte() */

/*------------------------------------------------------------------------------
  Function   : processGeneralMessage
  Purpose    : Process general incoming messages from console system.
  Parameters : c - pointer to one byte of the incoming message.
  Returns    : None.
  Notes      : None.
------------------------------------------------------------------------------*/
static void processGeneralMessage(unsigned char *c)
{
    LED_PIN ^= 1; /* Toggle the LED pin */
} /* processGeneralMessage() */

/*------------------------------------------------------------------------------
  Function   : uartRxInterruptHandler
  Purpose    : Interrupt handler for the UART receiver.
  Parameters : None.
  Returns    : None.
  Notes      : None.
------------------------------------------------------------------------------*/
//void __ISR(_UART1_RX_IRQ, ipl1auto)uartRxInterruptHandler(void)
void __ISR(_UART1_VECTOR, ipl1auto)uartRxInterruptHandler(void)
{

    /* If software FIFO buffer is full */
    if (rxFifo.numBytes == FIFO_BUFFER_SIZE)
    {
        fifoFlagOverflow = TRUE;
    } 
    /* If the software FIFO buffer is not full */
    else if (rxFifo.numBytes < FIFO_BUFFER_SIZE)
    {        
        /* Read a byte from the UART receive (hardware) FIFO */
        rxFifo.dataBuffer[rxFifo.lastByteIndex] = U1RXREG;
        rxFifo.lastByteIndex++;
        rxFifo.numBytes++;
    }

    /* If buffer has now been filled up after the byte read above */
    if (rxFifo.numBytes == FIFO_BUFFER_SIZE)
    {
        fifoFlagFull = TRUE;

        /* TODO: Besluit nog wat hier gedoen moet word */
    }
    /* TODO: skuif hierdie iewers anders heen om reg te hanteer */
    fifoFlagBufEmpty = FALSE;
    mU1RXClearIntFlag();

} /* ISR */
Das sieht nach einem Compiler-Bug aus. Benutzt du den neusten Compiler?

Antworten (2)

Schuld scheint die Tatsache zu sein, dass die Variable c in main() nicht initialisiert ist. Nachdem es bei seiner Deklaration initialisiert wurde, baut es wie gewohnt gut.

Es wäre immer noch aufschlussreich zu verstehen, was tatsächlich schief gelaufen ist.

Ich habe ein scheinbar verwandtes Problem mit einem PIC32MX270F256B, XC32 2.05/2.10 und MPLABX 4.15/4.20. Anstatt Probleme zu haben, bei denen der Code nicht kompiliert wird (ich verwende nicht BOOL), werden zur Laufzeit alle Variablen, die das Schlüsselwort nicht volatilein ihrer Deklaration enthalten, als 0x00000000 gelesen, was darauf hinweist, dass beide Werte nicht geschrieben werden Register, werden nicht wie erwartet aus Registern gelesen, oder die Adresse der Variablen ist durcheinander. Dies wird beim schrittweisen Durchlaufen des Codes in einer Debugsitzung deutlich.

Beim Steppen ist der Watch-Variablenwert für einige Variablen "Ungültige Adresse", die zu verschwinden scheint, wenn das volatileSchlüsselwort für jede Variablendeklaration verwendet wird, und der Code funktioniert wie beabsichtigt. Ohne volatile, wenn eine Funktion versucht, die Variable zu verwenden, scheint die Funktion sofort zurückzukehren und den Rest der Funktion zu überspringen.

Versuchen Sie, den Code mit dem Debugger mit den zugehörigen Variablen in der Beobachtungsliste schrittweise zu durchlaufen, und behalten Sie die Variablenwerte im Auge, suchen Sie nach sich nicht ändernden Werten (0x00000000, obwohl der Variablenwert geändert wurde) oder einem Wert von "Ungültige Adresse". . Wenn Sie eine der oben genannten Situationen sehen, versuchen Sie, volatiledie Deklaration der betreffenden Variablen zu ergänzen.

Achten Sie auch auf die void main(void)Funktion oder Unterfunktionen ( getByte(), processGeneralMessage()), die unerwartet zurückkehren oder fortgesetzt werden (die Haupt-While-Schleife).