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,112 +17,136 @@
*/
#include <stdbool.h>
#include "types.h"
#include "i2c.h"
#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 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 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
{
u8 busId;
u8 devAddr;
} i2cDevTable[] =
{
{0, 0x4A},
{0, 0x7A},
{0, 0x78},
{1, 0x4A},
{1, 0x78},
{1, 0x2C},
{1, 0x2E},
{1, 0x40},
{1, 0x44},
{2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct
{2, 0xD0},
{2, 0xD2},
{2, 0xA4},
{2, 0x9A},
{2, 0xA0},
{1, 0xEE},
{0, 0x40},
{2, 0x54}
{0, 0x4A},
{0, 0x7A},
{0, 0x78},
{1, 0x4A},
{1, 0x78},
{1, 0x2C},
{1, 0x2E},
{1, 0x40},
{1, 0x44},
{2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct
{2, 0xD0},
{2, 0xD2},
{2, 0xA4},
{2, 0x9A},
{2, 0xA0},
{1, 0xEE},
{0, 0x40},
{2, 0x54}
};
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;
if(!busId) base = (vu8*)I2C1_REGS_BASE;
else if(busId == 1) base = (vu8*)I2C2_REGS_BASE;
else base = (vu8*)I2C3_REGS_BASE;
I2cRegs *base;
switch(busId)
{
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;
}
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;
vu8 *const i2cData = regsBase;
vu8 *const i2cCnt = regsBase + 1;
u32 i = 0;
for(; i < 8; i++)
{
i2cWaitBusy(i2cCnt);
i2cWaitBusy(regs);
// Select device and start.
*i2cData = devAddr;
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
i2cWaitBusy(i2cCnt);
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
regs->REG_I2C_DATA = devAddr;
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
i2cWaitBusy(regs);
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;
}
// Select register and change direction to write.
*i2cData = regAddr;
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE;
i2cWaitBusy(i2cCnt);
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
regs->REG_I2C_DATA = regAddr;
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.
{
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
continue;
}
// Select device in read mode for read transfer.
if(read)
{
*i2cData = devAddr | 1u; // Set bit 0 for read.
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
i2cWaitBusy(i2cCnt);
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
regs->REG_I2C_DATA = devAddr | 1u; // Set bit 0 for read.
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
i2cWaitBusy(regs);
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;
}
}
@ -134,62 +158,68 @@ static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, vu8 *regsBa
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)
{
const u8 busId = i2cDevTable[devId].busId;
vu8 *const i2cData = i2cGetBusRegsBase(busId);
vu8 *const i2cCnt = i2cData + 1;
I2cRegs *const regs = i2cGetBusRegsBase(busId);
if(!i2cStartTransfer(devId, regAddr, true, i2cData)) return false;
if(!i2cStartTransfer(devId, regAddr, true, regs)) return false;
while(--size)
{
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK;
i2cWaitBusy(i2cCnt);
*out++ = *i2cData;
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK;
i2cWaitBusy(regs);
*out++ = regs->REG_I2C_DATA;
}
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP;
i2cWaitBusy(i2cCnt);
*out = *i2cData; // Last byte
regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP;
i2cWaitBusy(regs);
*out = regs->REG_I2C_DATA; // Last byte
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;
vu8 *const i2cData = i2cGetBusRegsBase(busId);
vu8 *const i2cCnt = i2cData + 1;
I2cRegs *const regs = i2cGetBusRegsBase(busId);
if(!i2cStartTransfer(devId, regAddr, false, i2cData)) return false;
if(!i2cStartTransfer(devId, regAddr, false, regs)) return false;
*i2cData = data;
*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.
while(--size)
{
*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 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 "common.h"
#include "types.h"
#define I2C_STOP (1u)
@ -51,6 +51,52 @@ typedef enum
/**
* @brief Initializes the I2C buses. Call this only once.
*/
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);
/**
* @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);