I'm implementing a read-only I2C slave on a PIC18F4620. I have made a -working- ISR handler for the MSSP module:
unsigned char dataFromMaster;
unsigned char SSPISR(void) {
unsigned char temp = SSPSTAT & 0x2d;
if ((temp ^ 0x09) == 0x00) {
// State 1: write operation, last byte was address
ReadI2C();
return 1;
} else if ((temp ^ 0x29) == 0x00) {
// State 2: write operation, last byte was data
dataFromMaster = ReadI2C();
return 2;
} else if (((temp & 0x2c) ^ 0x0c) == 0x00) {
// State 3: read operation, last byte was address
WriteI2C(0x00);
return 3;
} else if (!SSPCON1bits.CKP) {
// State 4: read operation, last byte was data
WriteI2C(0x00);
return 4;
} else {
// State 5: slave logic reset by NACK from master
return 5;
}
}
This is just a port to C from a part of the ASM code in appendix B of AN734.
In my main loop, I'm checking if there is new data, like this:
void main(void) {
if (dataFromMaster != 0x00) {
doSomething(dataFromMaster);
dataFromMaster = 0x00;
}
}
This gives a problem when the master sends bytes very fast, and new data comes in before the main loop gets to doSomething
. I therefore want to implement a buffer where data from the master is stored. I need a 16-char null-terminated array (the null
won't be used as a command for the slave). The ISR has to write new data to that array, and the main loop should read it from the array in the order it was received, and clear the array.
I have no idea how to implement this. Do you?
Answer
From the pseudocode of fm_andreas' answer, I made a working C18 code:
#define bufferSize 0x20
static volatile unsigned char buffer[bufferSize] = {0}; // This is the actual buffer
static volatile unsigned char readPointer = 0; // The pointer to read data
static volatile unsigned char writePointer = 0; // The pointer to write data
static volatile unsigned bufferOverflow = 0; // Indicates a buffer overflow
// In the ISR...
if (buffer[writePointer] == 0x00) { // If there is no data at the pointer
buffer[writePointer] = SSPBUF; // Put the data in the buffer
writePointer = (writePointer+1)%bufferSize; // Increase the pointer, reset if >32
} else { // If there is data...
bufferOverflow = 1; // Set the overflow flag
}
// In the main loop...
while (1) {
// Do some other stuff
if (readPointer != writePointer) { // If there is a new byte
putc(buffer[readPointer], stdout); // Do something with the data
buffer[readPointer] = 0x00; // Reset the data
readPointer = (readPointer+1)%bufferSize; // Increase the pointer, reset if >32
}
}
The beauty of this code is that it's a ring buffer:
It is therefore less likely to overflow when large data bulks are sent at once. This is discussed in the comments on Nick Alexeev's answer.
No comments:
Post a Comment