I have found over the years that except in speed-critical or multi-master applications, it's actually easier to bit-bang an I2C master than to try to use the I2C facilities built into many chips.
Note that if a device uses clock stretching, any time you release SCK, you must wait for it to actually go high. For simplicity, such delays are omitted from the following descriptions, but should be included if appropriate in your "release_SCK()" routine.
To start an I2C transaction, release SCK (if it isn't already) and, if the data line is low, assert SCK (drive it low), release SDA (if it isn't already), and release the SCK. Repeat this process up to nine times until SDA is high. If SDA is still low after nine repetitions, the bus is unusable.
To output each byte (including the address byte), assert SDA, and then for each bit repeat the sequence (assert SCK; set SDA high or low to match next bit of data; release SCK) eight times. After the last bit, assert SCK, release SDA, and release SCK. If SDA is low, a slave is acknowledging; if SDA is high, no slave is acknowledging and the transaction should be aborted.
When all output is complete, assert SCK, then SDA, and then release SCK, then SDA.
To input each byte, assert SDA, then release SCK if it isn't already (it will be for the first byte, but not others). Then reassert SCK, release SDA, and repeat the sequence (release SCK, read data bit, assert SCK) eight times. Note that at the end of this sequence, unlike when outputting a byte, SCK will be left asserted.
When all input is complete, release SDA (it should already already be released) and SCK.
Note that because the clock is left asserted after inputting each byte, it's not necessary to specify whether the byte should be ack'ed or nak'ed. If you read another byte, the last byte read will be nak'ed. If you terminate the read, it will be nak'ed.
Start; send address; write one byte, finish
SCK - -__-__-__-__-__-__-__-__-__-- -__-__-__-__-__-__-__-__-__--- -__--
SDA(M) - __777666555444333222111___--- --777666555444333222111000---- --__-
SDA(S) - -------------------------??AA A------------------------??AAA A----
Start; send address; read two bytes; finish
SCK - -__-__-__-__-__-__-__-__-__--- -__--_--_--_--_--_--_--_--__ -__--_--_--_--_--_--_--_--__ _-
SDA(M) - __777666555444333222111------- __-------------------------- __-------------------------- --
SDA(S) - -------------------------??AAA A??77?66?55?44?33?22?11?00?? -??77?66?55?44?33?22?11?00?? ?-
I have no experience with PIC, but the problem seems generic enough. I would create a simple array with two independent pointers into the array: one read pointer and one write pointer. Whenever you receive a byte, you increment the write pointer and write at the new position; in your main loop you could then check if the read pointer and the write pointer are the same. If not, you simply read and process from the buffer and increase the read pointer for every byte until they are.
You could then either reset the pointers to the beginning of the array, or let them "flow over" to the beginning making essentially a circular buffer. This is easiest if the size of the array is a factor of 2 as you can then simply bitmask both pointers after their increments.
Some example (pseudo)code:
volatile unsigned int readPointer= 0;
volatile unsigned int writePointer=0;
volatile char theBuffer[32];
...
//in your ISR
writePointer = (writePointer+1) & 0x1F;
theBuffer[writePointer] = ReadI2C(); // assuming this is the easiest way to do it
// I would probably just read the register directly
...
//in main
while (readPointer != writePointer) {
readPointer = (readPointer+1) & 0x1F;
nextByte = theBuffer[readPointer];
// do whatever necessary with nextByte
}
Best Answer
Slew rate is how fast the signal changes from low to high, or vice versa. By limiting this abrupt transition, you can reduce ringing from signal reflections, and limit crosstalk between signal lines.
The way it works out, though, is that at 100kHz, the signal rates are so slow that the slew rate doesn't really matter; at 400kHz you may be able to fix an otherwise problematic circuit by limiting it; but then when you get to 1MHz you really need all the transition speed you can get, and so you just have to do good signal matching and route your lines more carefully.
The bit in question does nothing more than enable or disable the feature. The rest is simply advice. The speeds are in parentheses, as it is just a suggestion.