Wolf-LITE/Src/i2c.c

271 wiersze
4.6 KiB
C

#include "stm32f4xx_hal.h"
#include "main.h"
#include "functions.h"
#include "i2c.h"
/* low level conventions:
* - SDA/SCL idle high (expected high)
* - always start with i2c_delay rather than end
*/
I2C_DEVICE I2C_WM8731 = {
.SDA_PORT = WM8731_SDA_GPIO_Port,
.SDA_PIN = WM8731_SDA_Pin,
.SCK_PORT = WM8731_SCK_GPIO_Port,
.SCK_PIN = WM8731_SCK_Pin,
.i2c_tx_addr = 0,
.i2c_tx_buf = {0},
.i2c_tx_buf_idx = 0,
.i2c_tx_buf_overflow = false,
};
#ifdef HAS_TOUCHPAD
I2C_DEVICE I2C_TOUCHPAD = {
.SDA_PORT = ENC2_CLK_GPIO_Port,
.SDA_PIN = ENC2_CLK_Pin,
.SCK_PORT = ENC2_DT_GPIO_Port,
.SCK_PIN = ENC2_DT_Pin,
.i2c_tx_addr = 0,
.i2c_tx_buf = {0},
.i2c_tx_buf_idx = 0,
.i2c_tx_buf_overflow = false,
};
#endif
static uint8_t i2c_writeOneByte(I2C_DEVICE *dev, uint8_t);
static void SDA_OUT(I2C_DEVICE *dev)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = dev->SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(dev->SDA_PORT, &GPIO_InitStruct);
}
static void SDA_IN(I2C_DEVICE *dev)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = dev->SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(dev->SDA_PORT, &GPIO_InitStruct);
}
static void SCK_OUT(I2C_DEVICE *dev)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = dev->SCK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(dev->SCK_PORT, &GPIO_InitStruct);
}
void i2c_start(I2C_DEVICE *dev)
{
SDA_SET;
SCK_SET;
I2C_DELAY
SDA_CLR;
I2C_DELAY
SCK_CLR;
}
void i2c_stop(I2C_DEVICE *dev)
{
SDA_OUT(dev);
SDA_CLR;
SCK_SET;
I2C_DELAY
I2C_DELAY
I2C_DELAY
I2C_DELAY
SDA_SET;
I2C_DELAY
}
bool i2c_get_ack(I2C_DEVICE *dev)
{
uint32_t time = 0;
SDA_IN(dev);
I2C_DELAY
I2C_DELAY
SCK_SET;
I2C_DELAY
I2C_DELAY
while (HAL_GPIO_ReadPin(dev->SDA_PORT, dev->SDA_PIN))
{
time++;
if (time > 50)
{
i2c_stop(dev);
return false;
}
I2C_DELAY
I2C_DELAY
}
SCK_CLR;
return true;
}
void i2c_shift_out(I2C_DEVICE *dev, uint8_t val)
{
SDA_OUT(dev);
int i;
for (i = 0; i < 8; i++)
{
I2C_DELAY
HAL_GPIO_WritePin(dev->SDA_PORT, dev->SDA_PIN, (GPIO_PinState) !!(val & (1 << (7 - i))));
SDA_OUT(dev);
I2C_DELAY
SCK_SET;
I2C_DELAY
I2C_DELAY
SCK_CLR;
}
}
/*
* Joins I2C bus as master on given SDA and SCL pins.
*/
void i2c_begin(I2C_DEVICE *dev)
{
SCK_SET;
SDA_SET;
SCK_OUT(dev);
SDA_OUT(dev);
}
void i2c_beginTransmission_u8(I2C_DEVICE *dev, uint8_t slave_address)
{
i2c_begin(dev);
dev->i2c_tx_addr = slave_address;
dev->i2c_tx_buf_idx = 0;
dev->i2c_tx_buf_overflow = false;
}
bool i2c_beginReceive_u8(I2C_DEVICE *dev, uint8_t slave_address)
{
i2c_begin(dev);
dev->i2c_tx_addr = slave_address;
dev->i2c_tx_buf_idx = 0;
dev->i2c_tx_buf_overflow = false;
i2c_start(dev);
i2c_shift_out(dev, (uint8_t)((dev->i2c_tx_addr << 1) | I2C_READ));
if (!i2c_get_ack(dev))
{
//sendToDebug_strln("no ack");
return false;
}
return true;
}
uint8_t i2c_endTransmission(I2C_DEVICE *dev)
{
if (dev->i2c_tx_buf_overflow)
return EDATA;
i2c_start(dev);
//I2C_DELAY;
i2c_shift_out(dev, (uint8_t)((dev->i2c_tx_addr << 1) | I2C_WRITE));
if (!i2c_get_ack(dev))
return ENACKADDR;
// shift out the address we're transmitting to
for (uint8_t i = 0; i < dev->i2c_tx_buf_idx; i++)
{
uint8_t ret = i2c_writeOneByte(dev, dev->i2c_tx_buf[i]);
if (ret)
return ret; // SUCCESS is 0
}
I2C_DELAY
I2C_DELAY
i2c_stop(dev);
dev->i2c_tx_buf_idx = 0;
dev->i2c_tx_buf_overflow = false;
return SUCCESS;
}
void i2c_write_u8(I2C_DEVICE *dev, uint8_t value)
{
if (dev->i2c_tx_buf_idx == WIRE_BUFSIZ)
{
dev->i2c_tx_buf_overflow = true;
return;
}
dev->i2c_tx_buf[dev->i2c_tx_buf_idx++] = value;
}
// private methods
static uint8_t i2c_writeOneByte(I2C_DEVICE *dev, uint8_t byte)
{
i2c_shift_out(dev, byte);
if (!i2c_get_ack(dev))
return ENACKTRNS;
return SUCCESS;
}
uint8_t i2c_Read_Byte(I2C_DEVICE *dev, uint8_t ack)
{
unsigned char i,receive=0;
SDA_IN(dev);
I2C_DELAY
I2C_DELAY
for(i=0;i<8;i++ )
{
SCK_CLR;
I2C_DELAY
I2C_DELAY
SCK_SET;
receive<<=1;
I2C_DELAY
I2C_DELAY
if(HAL_GPIO_ReadPin(dev->SDA_PORT,dev->SDA_PIN))
receive++;
}
if (!ack)
{
//NAck
SCK_CLR;
SDA_OUT(dev);
SDA_SET;
I2C_DELAY
I2C_DELAY
SCK_SET;
I2C_DELAY
I2C_DELAY
SCK_CLR;
SDA_IN(dev);
}
else
{
//Ack
SCK_CLR;
SDA_OUT(dev);
SDA_CLR;
I2C_DELAY
I2C_DELAY
SCK_SET;
I2C_DELAY
I2C_DELAY
SCK_CLR;
SDA_IN(dev);
}
return receive;
}