mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-24 14:13:45 +01:00
127 lines
3.4 KiB
C
127 lines
3.4 KiB
C
#include "i2c.h"
|
|
|
|
#include "printf.h"
|
|
#include "uart.h"
|
|
#include "zbs243.h"
|
|
|
|
static volatile struct I2cTransaction __xdata *__xdata mCurTrans;
|
|
static volatile uint8_t __xdata mNumTrans;
|
|
static volatile uint8_t __xdata mResult;
|
|
|
|
#pragma callee_saves i2cInit
|
|
void i2cInit(void) {
|
|
uint8_t bkp;
|
|
|
|
CLKEN |= 0x10;
|
|
|
|
bkp = CFGPAGE;
|
|
CFGPAGE = 0;
|
|
|
|
IEN1 |= 4; // int on
|
|
I2CUNKNOWN |= 4;
|
|
|
|
I2CCTL = 0x43; // master mode
|
|
I2CSPEED = 0x1a; // 100KHz
|
|
I2CCTL |= 0x80; // irq on
|
|
|
|
CFGPAGE = bkp;
|
|
}
|
|
|
|
// this code assumes HW stat emachine acts as it should. for this chip that seems to be true
|
|
// this is an 8051 so we value speed & code size over defensive programming. So sue me!
|
|
void I2C_IRQ(void) __interrupt(8) {
|
|
uint8_t bkp, sta;
|
|
|
|
bkp = CFGPAGE;
|
|
CFGPAGE = 0;
|
|
|
|
sta = I2CSTATE;
|
|
//pr("state=%02X\n", sta);
|
|
switch (sta >> 3) {
|
|
case 0x08 / 8: // start completed
|
|
case 0x10 / 8: // restart completed
|
|
I2CBUF = mCurTrans->deviceAddr;
|
|
break;
|
|
|
|
case 0x30 / 8: // byte write was NAKed
|
|
if (mCurTrans->numBytes) { // we still had more bytes to send?
|
|
I2CCTL |= 0x10; // stop
|
|
mResult = I2cNonLastDataByteNAKed;
|
|
break;
|
|
}
|
|
// fallthough since it is ok to NAK last written byte
|
|
|
|
case 0x28 / 8: // byte write was ACKed
|
|
case 0x18 / 8: // addr ACKED in write mode
|
|
if (mCurTrans->numBytes) {
|
|
mCurTrans->numBytes--;
|
|
I2CBUF = *mCurTrans->bytes++;
|
|
break;
|
|
}
|
|
transaction_over:
|
|
if (!--mNumTrans) { // byte(s)written and no more transactions? STOP
|
|
|
|
mResult = I2cOK;
|
|
I2CCTL |= 0x10; // stop
|
|
} else { // we have another transaction? RESTART
|
|
|
|
mCurTrans++;
|
|
I2CCTL |= 0x20; // do a restart
|
|
}
|
|
break;
|
|
|
|
case 0x20 / 8: // addr NAKEd in write mode
|
|
mResult = I2cWrAddrNAKed;
|
|
I2CCTL |= 0x10; // stop
|
|
mNumTrans = 0;
|
|
break;
|
|
|
|
case 0x48 / 8: // addr NACKed in read mode
|
|
mResult = I2cRdAddrNAKed;
|
|
I2CCTL |= 0x10; // stop
|
|
mNumTrans = 0;
|
|
break;
|
|
|
|
case 0x58 / 8: // NAK to RXed byte sent (we still have th ebyte we got in buffer)
|
|
case 0x50 / 8: // got byte in read mode
|
|
*mCurTrans->bytes++ = I2CBUF;
|
|
mCurTrans->numBytes--;
|
|
// fallthrough
|
|
|
|
case 0x40 / 8: // addr ACKED in read mode
|
|
if (!mCurTrans->numBytes)
|
|
goto transaction_over;
|
|
else if (mCurTrans->numBytes == 1)
|
|
I2CCTL &= ~0x04; // NAK
|
|
else
|
|
I2CCTL |= 0x04; // ACK
|
|
break;
|
|
|
|
default:
|
|
mResult = I2cInternalError;
|
|
I2CCTL |= 0x10; // stop
|
|
mNumTrans = 0;
|
|
break;
|
|
}
|
|
|
|
I2CCTL &= ~0x08;
|
|
CFGPAGE = bkp;
|
|
}
|
|
|
|
#pragma callee_saves i2cTransact
|
|
enum I2cResult i2cTransact(struct I2cTransaction __xdata *trans, uint8_t nTrans) {
|
|
mCurTrans = trans;
|
|
mNumTrans = nTrans;
|
|
|
|
mResult = I2cOK;
|
|
|
|
if (nTrans) {
|
|
I2CCTL &= ~0x10; // clear stop
|
|
I2CCTL |= 0x20; // issue start
|
|
|
|
while (mNumTrans)
|
|
; // wait
|
|
}
|
|
return mResult;
|
|
}
|