164 lines
4.4 KiB
C
164 lines
4.4 KiB
C
|
/*
|
||
|
* i2c.c
|
||
|
*
|
||
|
* routines more or less copied from WCH example code, then fucked around with to work.
|
||
|
*
|
||
|
* these routines have serious issues.
|
||
|
* - any i2c issue may lock up the machine.
|
||
|
* - timeout handlers are hastily added and may have problems.
|
||
|
* - there's no error handling of any kind
|
||
|
* - the library code makes some serious assumptions re: flags
|
||
|
* - it's a shitpile of polling
|
||
|
*/
|
||
|
|
||
|
#include <ch32v20x.h>
|
||
|
|
||
|
|
||
|
|
||
|
#define I2C_TIMEOUT 0xefff
|
||
|
#define I2C_TIMEOUT_ACK_POLL 0x180
|
||
|
|
||
|
static uint16_t timeout;
|
||
|
|
||
|
|
||
|
void i2c_init()
|
||
|
{
|
||
|
I2C_InitTypeDef i2c = {0};
|
||
|
|
||
|
// ensure GPIO pins are configured before initializing
|
||
|
|
||
|
i2c.I2C_ClockSpeed = 666666;
|
||
|
i2c.I2C_Mode = I2C_Mode_I2C;
|
||
|
i2c.I2C_DutyCycle = I2C_DutyCycle_16_9;
|
||
|
i2c.I2C_OwnAddress1 = 0x7f;
|
||
|
i2c.I2C_Ack = I2C_Ack_Enable;
|
||
|
i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
|
||
|
I2C_Init(I2C1, &i2c);
|
||
|
|
||
|
I2C_Cmd(I2C1, ENABLE);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* reads data from devices which use a single-byte address register
|
||
|
*/
|
||
|
int8_t i2c_read_addr1b(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len)
|
||
|
{
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while((I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET) && timeout--);
|
||
|
if (!timeout) return -1;
|
||
|
|
||
|
I2C_GenerateSTART(I2C1, ENABLE);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) && timeout--);
|
||
|
if (!timeout) return -2;
|
||
|
|
||
|
I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) && timeout--);
|
||
|
if (!timeout) return -3;
|
||
|
|
||
|
I2C_SendData(I2C1, reg);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) && timeout--);
|
||
|
if (!timeout) return -4;
|
||
|
|
||
|
I2C_GenerateSTART(I2C1, ENABLE);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) && timeout--);
|
||
|
if (!timeout) return -5;
|
||
|
|
||
|
I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Receiver);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) && timeout--);
|
||
|
if (!timeout) return -6;
|
||
|
|
||
|
while (len) {
|
||
|
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET) {
|
||
|
I2C_AcknowledgeConfig(I2C1, len);
|
||
|
}
|
||
|
|
||
|
*data++ = I2C_ReceiveData(I2C1);
|
||
|
len--;
|
||
|
|
||
|
if (!len) {
|
||
|
I2C_GenerateSTOP(I2C1, ENABLE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
uint8_t i2c_read_reg_8b(uint8_t addr, uint8_t reg)
|
||
|
{
|
||
|
uint8_t dat;
|
||
|
|
||
|
i2c_read_addr1b(addr, reg, &dat, 1);
|
||
|
return dat;
|
||
|
}
|
||
|
|
||
|
int8_t i2c_write_addr1b(uint8_t addr, uint8_t reg, const uint8_t *data, uint8_t len)
|
||
|
{
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while((I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET) && timeout--);
|
||
|
if (!timeout) return -1;
|
||
|
|
||
|
I2C_GenerateSTART(I2C1, ENABLE);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) && timeout--);
|
||
|
if (!timeout) return -2;
|
||
|
|
||
|
I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) && timeout--);
|
||
|
if (!timeout) return -3;
|
||
|
|
||
|
I2C_SendData(I2C1, reg);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) && timeout--);
|
||
|
if (!timeout) return -4;
|
||
|
|
||
|
while (len) {
|
||
|
// fixme: can get stuck here if address isn't found.
|
||
|
// somehow all the above passes but this will fail
|
||
|
if (I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET) {
|
||
|
I2C_SendData(I2C1, *data++);
|
||
|
len--;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
I2C_GenerateSTOP(I2C1, ENABLE);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void i2c_write_reg_8b(uint8_t addr, uint8_t reg, uint8_t dat)
|
||
|
{
|
||
|
i2c_write_addr1b(addr, reg, &dat, 1);
|
||
|
}
|
||
|
|
||
|
int8_t i2c_ack_poll(uint8_t addr)
|
||
|
{
|
||
|
int8_t addr_match = 0;
|
||
|
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while((I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET) && timeout--);
|
||
|
if (!timeout) return -1;
|
||
|
|
||
|
I2C_GenerateSTART(I2C1, ENABLE);
|
||
|
timeout = I2C_TIMEOUT;
|
||
|
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) && timeout--);
|
||
|
if (!timeout) return -2;
|
||
|
|
||
|
I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Receiver);
|
||
|
timeout = I2C_TIMEOUT_ACK_POLL;
|
||
|
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) && timeout--);
|
||
|
if (!timeout) {
|
||
|
addr_match = -128;
|
||
|
}
|
||
|
|
||
|
I2C_GenerateSTOP(I2C1, ENABLE);
|
||
|
|
||
|
return addr_match;
|
||
|
}
|