allenhuffman
Joined: 17 Jun 2019 Posts: 643 Location: Des Moines, Iowa, USA
|
CCS PCD "bare metal" C wrappers for polled I2C sla |
Posted: Mon Oct 06, 2025 7:56 am |
|
|
A few years ago, we found that some of the CCS generated I2C code could lock forever (no deadlock) -- after we were having this happen with some bad I2C stuff.
I started working on converting the polled I2C Slave code over to C routines by looking at the .lst file and recreating what the compiler was generating. The plan was to extend it with deadlock counters or whatever, which I never got around to. (Our coding standard wants only one return in a function, but this first pass was recreating how the assembly worked so it has multiple.)
Code: |
unsigned int i2cSlaveRead (unsigned int ack)
{
uint16_t data;
data = 0;
while (1)
{
// Wait for start.
while (S == 0);
// GCSTAT:
// Check for broadcast.
if (GCSTAT == 1)
{
// CHECK10BIT:
// Check for 10-bit addressing.
if (A10M == 1)
{
// CHECK10MATCH:
// Check for 10-bit address match.
if (ADD10 == 0)
{
// 10-bit address was not ours. Go back to start.
continue;
}
}
}
// If here, it was either a broadcast, a matching 10-bit address,
// or our 7-bit address.
break;
}
// READ:
// Wait for receive buffer full.
while (RBF == 0);
// READBYTE:
// Read byte.
data = I2C3RCV;
// Check receive overflow flag.
if (I2COV == 1)
{
// CLEAROV:
// Clear receive overflow flag.
I2COV = 0;
}
// CLOCKRELEASE:
// Release SCLx clock.
SCLREL = 1;
return data;
}
void i2cSlaveWrite (unsigned int data)
{
// START:
// If no start bit, return.
if (S == 0) return;
// GCSTAT:
// Check for broadcast.
if (GCSTAT == 0) return;
// CHECK10BIT:
// Check for 10-bit addressing.
if (A10M == 1)
{
// CHECK10MATCH:
// Check for 10-bit address match.
if (ADD10 == 0) return;
}
// If here, it was either a broadcast, a matching 10-bit address,
// or our 7-bit address.
// SEND:
// Send byte.
I2C3TRN = data;
// CLOCKRELEASE:
// Release SCLx clock.
SCLREL = 1;
} |
These require the defines of various bits using stuff like this:
Code: | // IC2C2STAT - sto(P) bit for status.
#word I2C2STAT = getenv("SFR:I2C2STAT")
#bit TBF = I2C2STAT.0 // bit 0 - transmit buffer full status
#bit RBF = I2C2STAT.1 // bit 1 - receive buffer full status
#bit RW = I2C2STAT.2 // bit 2 - read/write information
#bit S = I2C2STAT.3 // bit 3 - start
#bit P = I2C2STAT.4 // bit 4 - stop
#word IFS3 = getenv("SFR:IFS3")
#bit I2C_SYSTEM_BUS_IRQ_PENDING_BIT = IFS3.1 // bit 1 - slave I2Cx IRQ status
|
...though I do not find the definitions I made for this test slave code, proably because we never got around to completing and using it.
I wanted to ask if someone here has already done this, and might have it somewhere. Eventually I wanted to recreate the master I2C routines as well. This would obviously not be as flexible as what PCD creates, but is a very useful learning tool when bringing up a new engineer on how I2C is actually working.
Anyone? _________________ Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?
Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002. |
|