简体   繁体   中英

Odd PIC behavior with variables set by ISR

I am observing some odd behavior in my PIC code where I copy data from a global variable that is written by an ISR into two different buffers consecutively, but the value only seems to successfully get written into one of the two buffers. When I try this with a different variable that is not written by an ISR, it correctly gets copied into both buffers.

My setup is a PIC16LF15355 using the XC8 compiler version 1.45. I am configuring one of the PIC MSSP modules as a SPI interface to write measurement data and switch states to an RF transceiver. I have a another remote RF transceiver that receives and processes the data with a PIC16LF15355 via a SPI interface. For both PICs, I am configuring the second MSSP module as an I2C interface connected to a Raspberry Pi for debugging purposes. Any data that is written to the SPI buffer on the transmitting end is also copied to the I2C buffer so that it can be periodically read to see what is being sent. Likewise, the data read into the SPI buffer on the receiving end is copied to an I2C buffer so that it can be read periodically to see what is being received.

There is a switch input on the transmitting end that is debounced with a timer ISR (timer0_handler in the code below). The state gets written into sw1State by this ISR. When it comes time to transmit data, the switch state and other measurement data gets copied into the I2C buffer and then the I2C buffer gets copied into the SPI buffer for transmission. When I sample the I2C buffer contents periodically from the Pi, I can see switch state changing in response to presses of the switch. But when I sample the I2C buffer contents periodically on the receiving end, I only ever see the switch state default value (1).

What is strange is that if I change the code to copy the value from a variable that is not written by an ISR, the value shows up correctly on the receiving end. But copy from the I2C buffer to the SPI buffer is just a generic copy of one array to another, and all other measurement data shows up correctly on the receiving end. The two buffers should be identical. And there is nothing in my code that modifies the SPI buffer between the time when it gets copied from the I2C buffer and when the SPI buffer gets written out to the transceiver.

A stripped down copy of the code is included below. I've been looking at this for several days and I just don't see what is causing this.

volatile uint8_t sw1State;            // current switch 1 state
volatile uint8_t sw1TimeExpired;      // true if switch 1 debounce time expired
uint8_t spiOutBuf[13]; // SPI output buffer
uint8_t spiInBuf[13];  // SPI input buffer
uint8_t i2cBuff[13];   // I2C input/output buffer

void interrupt main_ISR( void ) {
    I2C_slave_handler();
    timer0_handler();
    switch_input_handler();
}

int main( void ) {
    ... device initialization code omitted for brevity

    sw1State = 1;
    sw1TimeExpired = 1;

    for ( ; ; )
    {        
        // Read the ADC values and add to the I2C buffer (for debugging).
        for ( uint8_t chan = 0; chan < 9; chan++ )
        {
            i2cBuff[chan + 1] = ADC_read( chan );
        }

        // Read the switch status and add to the I2C buffer.
        i2cBuff[10] = sw1State;

        // Load the write transmit payload command into the SPI buffer.
        spiOutBuf[0] = CMD_W_TX_PAYLOAD;

        // Copy the payload data from the I2C buffer to the SPI buffer.
        for ( uint8_t i = 1; i < 13; i++ )
        {
            spiOutBuf[i] = i2cBuff[i];
        }

        // Write the SPI buffer to the transceiver module payload register.
        writeReadSPI( 13 );

        // Clear the RB4 interrupt-on-change interrupt flag (IRQ change) and 
        // set CE high to initiate the transmit.  Hold CE high until an ack
        // is received or there is an ack timeout.
        IOCBFbits.IOCBF4 = 0;
        CE = 1;
        __delay_us( 130 );    // ensure minimum state change transition time

        ... code here omitted which checks the transceiver status

        __delay_ms( 80 );
    }
}

void switch_input_handler( void ) {
    // Check for switch 1 trigger.
    if ( IOCCFbits.IOCCF6 == 1 )
    {
        IOCCFbits.IOCCF6 = 0;   // clear IOC interrupt

        // Process switch 1 trigger if debounce time has expired.
        if ( sw1TimeExpired == 1 )
        {
            // Toggle between OFF state and ON state.
            if ( sw1State == 1 )
            {
                sw1State = 2;
            }
            else
            {
                sw1State = 1;
            }
            // Load and restart Timer0 with 2-second counter value.
            T0CON0bits.T0EN = 0;
            TMR0H = 0xc2;
            TMR0L = 0xf7;
            T0CON0bits.T0EN = 1;
            sw1TimeExpired = 0;
        }
    }
}

void timer0_handler( void ) {
    if ( PIR0bits.TMR0IF == 1 )
    {
        PIR0bits.TMR0IF = 0;    // clear the interrupt
        T0CON0bits.T0EN = 0;    // disable Timer0

        if ( sw1TimeExpired == 0 )
        {
            sw1TimeExpired = 1; // Note the switch 1 timeout for switch handler.
                                // No state transition here.  This just enables
                                // the next switch interrupt to change state.
        }
    }
}

void I2C_slave_handler( void ) {
   ... code omitted for brevity
}

From the code snippet it appears that the SPI channel is transmitting as a background task, while the I2C channel is transmitting in the foreground (interrupt handler). This could potentially result in a race condition and explain the behavior you are experiencing.

Recommend you try using a single transmit buffer for both channels, and set a variable to indicate when both channels have successfully sent the the data. Once both channels indicate data transmitted, then generate a fresh data packet/buffer for the next cycle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM