Update I2C code to newest version

This commit is contained in:
d0k3 2017-11-24 02:48:56 +01:00
parent 7466e0a4ea
commit 9217116a68
2 changed files with 167 additions and 91 deletions

View File

@ -17,28 +17,25 @@
*/ */
#include <stdbool.h> #include <stdbool.h>
#include "types.h"
#include "i2c.h" #include "i2c.h"
#define I2C1_REGS_BASE (0x10161000) #define I2C1_REGS_BASE (0x10161000)
#define REG_I2C1_DATA *((vu8* )(I2C1_REGS_BASE + 0x00))
#define REG_I2C1_CNT *((vu8* )(I2C1_REGS_BASE + 0x01))
#define REG_I2C1_CNTEX *((vu16*)(I2C1_REGS_BASE + 0x02))
#define REG_I2C1_SCL *((vu16*)(I2C1_REGS_BASE + 0x04))
#define I2C2_REGS_BASE (0x10144000) #define I2C2_REGS_BASE (0x10144000)
#define REG_I2C2_DATA *((vu8* )(I2C2_REGS_BASE + 0x00))
#define REG_I2C2_CNT *((vu8* )(I2C2_REGS_BASE + 0x01))
#define REG_I2C2_CNTEX *((vu16*)(I2C2_REGS_BASE + 0x02))
#define REG_I2C2_SCL *((vu16*)(I2C2_REGS_BASE + 0x04))
#define I2C3_REGS_BASE (0x10148000) #define I2C3_REGS_BASE (0x10148000)
#define REG_I2C3_DATA *((vu8* )(I2C3_REGS_BASE + 0x00))
#define REG_I2C3_CNT *((vu8* )(I2C3_REGS_BASE + 0x01))
#define REG_I2C3_CNTEX *((vu16*)(I2C3_REGS_BASE + 0x02))
#define REG_I2C3_SCL *((vu16*)(I2C3_REGS_BASE + 0x04))
typedef struct
{
vu8 REG_I2C_DATA;
vu8 REG_I2C_CNT;
vu16 REG_I2C_CNTEX;
vu16 REG_I2C_SCL;
} I2cRegs;
static const struct static const struct
{ {
u8 busId; u8 busId;
@ -67,62 +64,89 @@ static const struct
static void i2cWaitBusy(vu8 *cntReg) static void i2cWaitBusy(I2cRegs *const regs)
{ {
while(*cntReg & I2C_ENABLE); while(regs->REG_I2C_CNT & I2C_ENABLE);
} }
static vu8* i2cGetBusRegsBase(u8 busId) static I2cRegs* i2cGetBusRegsBase(u8 busId)
{ {
vu8 *base; I2cRegs *base;
if(!busId) base = (vu8*)I2C1_REGS_BASE; switch(busId)
else if(busId == 1) base = (vu8*)I2C2_REGS_BASE; {
else base = (vu8*)I2C3_REGS_BASE; case 0:
base = (I2cRegs*)I2C1_REGS_BASE;
break;
case 1:
base = (I2cRegs*)I2C2_REGS_BASE;
break;
case 2:
base = (I2cRegs*)I2C3_REGS_BASE;
break;
default:
base = NULL;
}
return base; return base;
} }
static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, vu8 *regsBase) void I2C_init(void)
{
I2cRegs *regs = i2cGetBusRegsBase(0); // Bus 1
i2cWaitBusy(regs);
regs->REG_I2C_CNTEX = 2; // ?
regs->REG_I2C_SCL = 1280; // ?
regs = i2cGetBusRegsBase(1); // Bus 2
i2cWaitBusy(regs);
regs->REG_I2C_CNTEX = 2; // ?
regs->REG_I2C_SCL = 1280; // ?
regs = i2cGetBusRegsBase(2); // Bus 3
i2cWaitBusy(regs);
regs->REG_I2C_CNTEX = 2; // ?
regs->REG_I2C_SCL = 1280; // ?
}
static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, I2cRegs *const regs)
{ {
const u8 devAddr = i2cDevTable[devId].devAddr; const u8 devAddr = i2cDevTable[devId].devAddr;
vu8 *const i2cData = regsBase;
vu8 *const i2cCnt = regsBase + 1;
u32 i = 0; u32 i = 0;
for(; i < 8; i++) for(; i < 8; i++)
{ {
i2cWaitBusy(i2cCnt); i2cWaitBusy(regs);
// Select device and start. // Select device and start.
*i2cData = devAddr; regs->REG_I2C_DATA = devAddr;
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
i2cWaitBusy(i2cCnt); i2cWaitBusy(regs);
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed.
{ {
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
continue; continue;
} }
// Select register and change direction to write. // Select register and change direction to write.
*i2cData = regAddr; regs->REG_I2C_DATA = regAddr;
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE;
i2cWaitBusy(i2cCnt); i2cWaitBusy(regs);
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed.
{ {
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
continue; continue;
} }
// Select device in read mode for read transfer. // Select device in read mode for read transfer.
if(read) if(read)
{ {
*i2cData = devAddr | 1u; // Set bit 0 for read. regs->REG_I2C_DATA = devAddr | 1u; // Set bit 0 for read.
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
i2cWaitBusy(i2cCnt); i2cWaitBusy(regs);
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed.
{ {
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
continue; continue;
} }
} }
@ -134,62 +158,68 @@ static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, vu8 *regsBa
else return false; else return false;
} }
void I2C_init(void)
{
i2cWaitBusy(i2cGetBusRegsBase(0) + 1);
REG_I2C1_CNTEX = 2; // ?
REG_I2C1_SCL = 1280; // ?
i2cWaitBusy(i2cGetBusRegsBase(1) + 1);
REG_I2C2_CNTEX = 2; // ?
REG_I2C2_SCL = 1280; // ?
i2cWaitBusy(i2cGetBusRegsBase(2) + 1);
REG_I2C3_CNTEX = 2; // ?
REG_I2C3_SCL = 1280; // ?
}
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size) bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
{ {
const u8 busId = i2cDevTable[devId].busId; const u8 busId = i2cDevTable[devId].busId;
vu8 *const i2cData = i2cGetBusRegsBase(busId); I2cRegs *const regs = i2cGetBusRegsBase(busId);
vu8 *const i2cCnt = i2cData + 1;
if(!i2cStartTransfer(devId, regAddr, true, i2cData)) return false; if(!i2cStartTransfer(devId, regAddr, true, regs)) return false;
while(--size) while(--size)
{ {
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK; regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK;
i2cWaitBusy(i2cCnt); i2cWaitBusy(regs);
*out++ = *i2cData; *out++ = regs->REG_I2C_DATA;
} }
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP; regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP;
i2cWaitBusy(i2cCnt); i2cWaitBusy(regs);
*out = *i2cData; // Last byte *out = regs->REG_I2C_DATA; // Last byte
return true; return true;
} }
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data) bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
{ {
const u8 busId = i2cDevTable[devId].busId; const u8 busId = i2cDevTable[devId].busId;
vu8 *const i2cData = i2cGetBusRegsBase(busId); I2cRegs *const regs = i2cGetBusRegsBase(busId);
vu8 *const i2cCnt = i2cData + 1;
if(!i2cStartTransfer(devId, regAddr, false, i2cData)) return false; if(!i2cStartTransfer(devId, regAddr, false, regs)) return false;
*i2cData = data; while(--size)
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP;
i2cWaitBusy(i2cCnt);
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
{ {
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; regs->REG_I2C_DATA = *in++;
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE;
i2cWaitBusy(regs);
if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed.
{
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
return false;
}
}
regs->REG_I2C_DATA = *in;
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP;
i2cWaitBusy(regs);
if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed.
{
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
return false; return false;
} }
return true; return true;
} }
u8 I2C_readReg(I2cDevice devId, u8 regAddr)
{
u8 data;
if(!I2C_readRegBuf(devId, regAddr, &data, 1)) return 0xFF;
return data;
}
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data)
{
return I2C_writeRegBuf(devId, regAddr, &data, 1);
}

View File

@ -19,7 +19,7 @@
*/ */
#include <stdbool.h> #include <stdbool.h>
#include "common.h" #include "types.h"
#define I2C_STOP (1u) #define I2C_STOP (1u)
@ -51,6 +51,52 @@ typedef enum
/**
* @brief Initializes the I2C buses. Call this only once.
*/
void I2C_init(void); void I2C_init(void);
/**
* @brief Reads data from a I2C register to a buffer.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param out The output buffer pointer.
* @param[in] size The read size.
*
* @return Returns true on success and false on failure.
*/
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size); bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size);
/**
* @brief Writes a buffer to a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param[in] in The input buffer pointer.
* @param[in] size The write size.
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size);
/**
* @brief Reads a byte from a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
*
* @return Returns the value read on success otherwise 0xFF.
*/
u8 I2C_readReg(I2cDevice devId, u8 regAddr);
/**
* @brief Writes a byte to a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param[in] data The data to write.
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data); bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data);