BLE_DCF_TYQ_CH592F/BSP/src/bsp_i2c.c

774 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "bsp_i2c.h"
#include "bsp_uart.h"
#include "log.h"
#include "bsp_valve.h"
#undef LOG_ENABLE
#define LOG_ENABLE 1
#undef LOG_TAG
#define LOG_TAG "I2C"
// #define CONFIG_I2C_DEBUG
#ifdef CONFIG_I2C_DEBUG
#define I2C_DBG(...) logDebug(__VA_ARGS__)
#else
#define I2C_DBG(...)
#endif
static volatile uint8_t i2c_state;
static volatile uint8_t i2c_slave_addr_rw;
static volatile uint8_t i2c_send_stop; // should the transaction end with a stop
static volatile uint8_t i2c_in_repstart; // in the middle of a repeated start
static uint8_t i2c_master_buffer[I2C_BUFFER_LENGTH];
static volatile uint8_t i2c_master_buffer_index;
static uint8_t i2c_master_buffer_length;
static uint8_t i2c_slave_txbuffer[I2C_BUFFER_LENGTH];
static volatile uint8_t i2c_slave_txbuffer_index;
static uint8_t i2c_slave_txbuffer_length;
static uint8_t i2c_slave_rxbuffer[I2C_BUFFER_LENGTH];
static volatile uint8_t i2c_slave_rxbuffer_index;
static uint8_t is_nack_sent = false;
static volatile uint8_t i2c_error;
static struct i2c_slave_cb *slave_cb = NULL;
#define MASTER_ADDR 0x42
uint8_t i2c_tx_data[2];
// __attribute__((aligned(4)))
uint8_t i2c_rx_data[8];
void BSP_I2C_Init(uint8_t address)
{
i2c_state = I2C_READY;
i2c_send_stop = true;
i2c_in_repstart = false;
GPIOB_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13, GPIO_ModeIN_PU);
I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_7bit, address);
I2C_ITConfig(I2C_IT_BUF, ENABLE);
I2C_ITConfig(I2C_IT_EVT, ENABLE);
I2C_ITConfig(I2C_IT_ERR, ENABLE);
PFIC_EnableIRQ(I2C_IRQn);
logDebug("BSP_I2C_Init(%02x)", address);
}
void i2c_slave_cb_register(struct i2c_slave_cb *cb)
{
slave_cb = cb;
}
int I2C_Write(uint8_t addr_7bit, const uint8_t *data, uint8_t length,
uint8_t wait, uint8_t send_stop)
{
if (length > I2C_BUFFER_LENGTH)
{
return -I2C_NO_MEM;
}
if (i2c_state != I2C_READY)
{
return -I2C_STATE;
}
if (!length)
{
return 0;
}
i2c_state = I2C_MTX;
i2c_send_stop = send_stop;
i2c_error = 0;
// initialize buffer iteration vars
i2c_master_buffer_index = 0;
i2c_master_buffer_length = length;
tmos_memcpy(i2c_master_buffer, data, length);
i2c_slave_addr_rw = I2C_WRITE;
i2c_slave_addr_rw |= addr_7bit << 1;
I2C_GenerateSTOP(DISABLE);
if (i2c_in_repstart == true)
{
i2c_in_repstart = false;
do {
I2C_SendData(i2c_slave_addr_rw);
} while (R16_I2C_CTRL1 & RB_I2C_BTF);
/* Disabled in IRS */
I2C_ITConfig(I2C_IT_BUF, ENABLE);
I2C_ITConfig(I2C_IT_EVT, ENABLE);
I2C_ITConfig(I2C_IT_ERR, ENABLE);
}
else
{
I2C_GenerateSTART(ENABLE);
}
while (wait && (i2c_state == I2C_MTX))
{
continue;
}
if (i2c_error)
{
return -i2c_error;
}
return 0;
}
int I2C_Read(uint8_t addr_7bit, uint8_t *data, uint8_t length,
uint8_t send_stop, int timeout)
{
int to = 0;
uint8_t forever = (timeout == -1);
if (length > I2C_BUFFER_LENGTH)
{
return -I2C_NO_MEM;
}
if (i2c_state != I2C_READY)
{
return -I2C_STATE;
}
if (!length)
{
return 0;
}
i2c_state = I2C_MRX;
i2c_send_stop = send_stop;
i2c_error = 0;
// initialize buffer iteration vars
i2c_master_buffer_index = 0;
i2c_master_buffer_length = length - 1;
i2c_slave_addr_rw = I2C_READ;
i2c_slave_addr_rw |= addr_7bit << 1;
I2C_GenerateSTOP(DISABLE);
if (i2c_in_repstart == true)
{
i2c_in_repstart = false;
do {
I2C_SendData(i2c_slave_addr_rw);
} while (R16_I2C_CTRL1 & RB_I2C_BTF);
/* Disabled in IRS */
I2C_ITConfig(I2C_IT_BUF, ENABLE);
I2C_ITConfig(I2C_IT_EVT, ENABLE);
I2C_ITConfig(I2C_IT_ERR, ENABLE);
}
else
{
I2C_GenerateSTART(ENABLE);
}
// wait for read operation to complete
while (i2c_state == I2C_MRX)
{
mDelaymS(1);
to++;
if (!forever && (to >= timeout))
{
break;
}
}
if (i2c_master_buffer_index < length)
length = i2c_master_buffer_index;
// copy i2c buffer to data
tmos_memcpy(data, i2c_master_buffer, length);
return length;
}
#ifdef CONFIG_I2C_DEBUG
static void print_i2c_irq_sta(uint32_t state)
{
I2C_DBG("i2c irq: ( ");
if (state & RB_I2C_SB)
I2C_DBG("SB ");
if (state & RB_I2C_ADDR)
I2C_DBG("ADDR ");
if (state & RB_I2C_BTF)
I2C_DBG("BTF ");
if (state & RB_I2C_ADD10)
I2C_DBG("ADD10 ");
if (state & RB_I2C_STOPF)
I2C_DBG("STOP ");
if (state & RB_I2C_RxNE)
I2C_DBG("RxNE ");
if (state & RB_I2C_TxE)
I2C_DBG("TxE ");
if (state & RB_I2C_BERR)
I2C_DBG("BERR ");
if (state & RB_I2C_ARLO)
I2C_DBG("ARLO ");
if (state & RB_I2C_AF)
I2C_DBG("AF ");
if (state & RB_I2C_OVR)
I2C_DBG("OVR ");
if (state & RB_I2C_PECERR)
I2C_DBG("PECERR ");
if (state & RB_I2C_TIMEOUT)
I2C_DBG("TIMEOUT ");
if (state & RB_I2C_SMBALERT)
I2C_DBG("SMBALERT ");
if (state & (RB_I2C_MSL << 16))
I2C_DBG("MSL ");
if (state & (RB_I2C_BUSY << 16))
I2C_DBG("BUSY ");
if (state & (RB_I2C_TRA << 16))
I2C_DBG("TRA ");
if (state & (RB_I2C_GENCALL << 16))
I2C_DBG("GENCALL ");
if (state & (RB_I2C_SMBDEFAULT << 16))
I2C_DBG("SMBDEFAULT ");
if (state & (RB_I2C_SMBHOST << 16))
I2C_DBG("SMBHOST ");
if (state & (RB_I2C_DUALF << 16))
I2C_DBG("DUALF ");
I2C_DBG(")");
}
#else
static inline void print_i2c_irq_sta(uint32_t state)
{
(void)state;
}
#endif
void BSP_I2C_DeInit(void)
{
GPIOB_SetBits(GPIO_Pin_14);
GPIOB_ModeCfg(GPIO_Pin_14, GPIO_ModeIN_PU);
GPIOB_SetBits(GPIO_Pin_15);
GPIOB_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_PU);
}
// GXHTC3C_CMD_LOW_CLK_STRE_OFF_HUMI_FRONT
void GXHTC3C_SendCmd(uint16_t cmd)
{
int ret;
i2c_tx_data[0] = HI_UINT16(cmd);
i2c_tx_data[1] = LO_UINT16(cmd);
ret = I2C_Write(GXHTC3C_ADDR, (const uint8_t *)&i2c_tx_data, 2, true, true);
// logDebug("GXHTC3C_SendCmd %s", ret ? "failed" : "success");
}
void GXHTC3C_Sleep(void)
{
GXHTC3C_SendCmd(GXHTC3C_CMD_SLEEP);
}
void GXHTC3C_Wakeup(void)
{
GXHTC3C_SendCmd(GXHTC3C_CMD_WAKEUP);
}
void GXHTC3C_GetStart(void)
{
// 低功耗、Clock stretching关闭、湿度在前
GXHTC3C_SendCmd(GXHTC3C_CMD_LOW_CLK_STRE_OFF_HUMI_FRONT);
}
// 定义CRC-8参数
#define POLYNOMIAL 0x31 // 生成多项式x8+x5+x4+1 (省略最高位1)
#define INIT_VALUE 0xFF // 初始化值
#define REFLECT_IN false // 不反射输入
#define REFLECT_OUT false // 不反射输出
uint8_t GXHTC3C_CRC_8(uint8_t *p_crc, uint8_t len)
{
uint8_t crc = INIT_VALUE;
for (size_t i = 0; i < len; ++i)
{
crc ^= p_crc[i]; // 异或当前字节
for (uint8_t j = 0; j < 8; ++j)
{
if (crc & 0x80)
{ // 如果最高位是1
crc = (crc << 1) ^ POLYNOMIAL; // 左移一位并异或多相式
}
else
{
crc <<= 1; // 否则只左移一位
}
// 确保crc保持在8位内
crc &= 0xFF;
}
}
// 最终返回CRC值
return crc;
}
// GXHTC3C_CMD_LOW_CLK_STRE_OFF_HUMI_FRONT
uint8_t GXHTC3C_GetTempHumi(float *humi, float *temp)
{
int ret;
ret = I2C_Read(GXHTC3C_ADDR, (uint8_t *)&i2c_rx_data, 6, true, 1000);
logDebug("read %d byte(s) from %#x", ret, GXHTC3C_ADDR);
if (ret != 6)
{
logError("read failed");
logHexDumpAll(i2c_rx_data, ret);
return 1;
}
// 低功耗、Clock stretching关闭、湿度在前
uint8_t humi_raw_data[2];
uint8_t temp_raw_data[2];
humi_raw_data[0] = i2c_rx_data[0];
humi_raw_data[1] = i2c_rx_data[1];
uint16_t raw_humi = (humi_raw_data[0] << 8) | humi_raw_data[1];
uint8_t crc_humi = GXHTC3C_CRC_8(humi_raw_data, 2);
temp_raw_data[0] = i2c_rx_data[3];
temp_raw_data[1] = i2c_rx_data[4];
uint16_t raw_temp = (temp_raw_data[0] << 8) | temp_raw_data[1];
uint8_t crc_temp = GXHTC3C_CRC_8(temp_raw_data, 2);
if ((crc_humi == i2c_rx_data[2]) && (crc_temp == i2c_rx_data[5]))
{
// logDebug("crc ok");
// logHexDumpAll(i2c_rx_data, 6);
*humi = (100.0 * raw_humi) / 65536.0; // 湿度真实值
*temp = (175.0 * raw_temp) / 65536.0 - 45.0; // 温度真实值
// logDebug("humi %f, temp %f", *humi, *temp);
}
else
{
logHexDumpAll(i2c_rx_data, 6);
logError("crc_temp 0x%02x, crc_humi 0x%02x", crc_temp, crc_humi);
logError("crc error");
return 2;
}
// logDebug("0 success");
return 0;
}
#if 0
void GXHTC3C_Read(void)
{
int ret;
GXHTC3C_Wakeup();
DelayMs(20);
GXHTC3C_GetStart();
DelayMs(20);
float humi, temp;
ret = GXHTC3C_GetTempHumi(&humi, &temp);
if (ret == 0)
{
// logDebug("ret=0");
logDebug("humi %.2f %, temp %.2f C", humi, temp);
}
GXHTC3C_Sleep();
}
#endif
int BSP_ReadTempHumi(float *humi, float *temp)
{
int ret;
GXHTC3C_Wakeup();
DelayMs(1);
GXHTC3C_GetStart();
DelayMs(3);
float _humi, _temp;
ret = GXHTC3C_GetTempHumi(&_humi, &_temp);
if (ret == 0)
{
*humi = _humi;
*temp = _temp;
// gValveData.temp = (int8_t)temp;
// gValveData.humi = (uint8_t)humi;
logDebug("humi %.2f %, temp %.2f C", *humi, *temp);
}
GXHTC3C_Sleep();
return ret;
}
void GXHTC3C_Init(void)
{
#if 1
BSP_I2C_Init(MASTER_ADDR);
int ret;
GXHTC3C_Sleep();
float _humi, _temp;
BSP_ReadTempHumi(&_humi, &_temp);
#endif
}
#if 1
__INTERRUPT
__HIGH_CODE
void I2C_IRQHandler(void)
{
uint32_t event = I2C_GetLastEvent();
print_i2c_irq_sta(event);
/* I2C Master */
if (event & (RB_I2C_MSL << 16))
{
if (event & RB_I2C_SB)
{
/* Start condition sent, send address */
I2C_SendData(i2c_slave_addr_rw);
I2C_DBG("Master selected, send address");
}
/* I2C Master transmitter */
if (event & (RB_I2C_TRA << 16))
{
I2C_DBG("Master transmitter:");
/* Slave receiver acked address or sent bit */
if (event & (RB_I2C_ADDR | RB_I2C_BTF | RB_I2C_TxE | (RB_I2C_TRA << 16)))
{
/* if there is data to send, send it, otherwise stop */
if (i2c_master_buffer_index < i2c_master_buffer_length)
{
I2C_SendData(i2c_master_buffer[i2c_master_buffer_index++]);
I2C_DBG(" send (%#x)\n",
i2c_master_buffer[i2c_master_buffer_index - 1]);
}
else
{
if (i2c_send_stop)
{
i2c_state = I2C_READY;
I2C_GenerateSTOP(ENABLE);
I2C_DBG(" send STOP");
}
else
{
i2c_in_repstart = true;
/* we're gonna send the START, don't enable the interrupt. */
I2C_ITConfig(I2C_IT_BUF, DISABLE);
I2C_ITConfig(I2C_IT_EVT, DISABLE);
I2C_ITConfig(I2C_IT_ERR, DISABLE);
I2C_GenerateSTART(ENABLE);
i2c_state = I2C_READY;
I2C_DBG(" restart");
}
}
}
/* Address or data sent, nack received */
if (event & RB_I2C_AF)
{
I2C_ClearFlag(I2C_FLAG_AF);
i2c_error = I2C_MT_NACK;
i2c_state = I2C_READY;
I2C_GenerateSTOP(ENABLE);
I2C_DBG(" NACK received, sent stop");
}
}
else
{
/* I2C Master reveiver */
I2C_DBG("Master receiver:");
/* address sent, ack received */
if (event & RB_I2C_ADDR)
{
/* ack if more bytes are expected, otherwise nack */
if (i2c_master_buffer_length)
{
I2C_AcknowledgeConfig(ENABLE);
I2C_DBG(" address sent");
I2C_DBG(" ACK next");
}
else
{
// XXX: Should not delay too match before NACK
I2C_AcknowledgeConfig(DISABLE);
is_nack_sent = true;
I2C_DBG(" address sent");
I2C_DBG(" NACK next");
}
}
/* data reveived */
if (event & (RB_I2C_RxNE))
{
/* put byte into buffer */
i2c_master_buffer[i2c_master_buffer_index++] = I2C_ReceiveData();
if (i2c_master_buffer_index < i2c_master_buffer_length)
{
I2C_AcknowledgeConfig(ENABLE);
I2C_DBG(" ACK next");
}
else
{
// XXX: Should not delay too match before NACK
I2C_AcknowledgeConfig(DISABLE);
I2C_DBG(" NACK next");
if (is_nack_sent)
{
is_nack_sent = false;
if (i2c_send_stop)
{
I2C_GenerateSTOP(ENABLE);
i2c_state = I2C_READY;
I2C_DBG(" send STOP");
}
else
{
i2c_in_repstart = true;
/* we're gonna send the START, don't enable the interrupt. */
I2C_ITConfig(I2C_IT_BUF, DISABLE);
I2C_ITConfig(I2C_IT_EVT, DISABLE);
I2C_ITConfig(I2C_IT_ERR, DISABLE);
I2C_GenerateSTART(ENABLE);
i2c_state = I2C_READY;
I2C_DBG(" restart");
}
}
else
{
is_nack_sent = true;
}
}
I2C_DBG(" received data (%#x)\n",
i2c_master_buffer[i2c_master_buffer_index - 1]);
}
/* nack received */
if (event & RB_I2C_AF)
{
I2C_ClearFlag(I2C_FLAG_AF);
/* put final byte into buffer */
i2c_master_buffer[i2c_master_buffer_index++] = I2C_ReceiveData();
if (i2c_send_stop)
{
i2c_state = I2C_READY;
I2C_GenerateSTOP(ENABLE);
I2C_DBG(" NACK received, send STOP");
}
else
{
i2c_in_repstart = true;
/* we're gonna send the START, don't enable the interrupt. */
I2C_ITConfig(I2C_IT_BUF, DISABLE);
I2C_ITConfig(I2C_IT_EVT, DISABLE);
I2C_ITConfig(I2C_IT_ERR, DISABLE);
I2C_GenerateSTART(ENABLE);
i2c_state = I2C_READY;
I2C_DBG(" restart");
}
}
}
}
else
{
/* I2C slave */
/* addressed, returned ack */
if (event & RB_I2C_ADDR)
{
if (event & ((RB_I2C_TRA << 16) | RB_I2C_TxE))
{
I2C_DBG("Slave transmitter address matched");
i2c_state = I2C_STX;
i2c_slave_txbuffer_index = 0;
i2c_slave_txbuffer_length = 0;
if (slave_cb && slave_cb->on_transmit)
{
slave_cb->on_transmit(i2c_slave_txbuffer, &i2c_slave_txbuffer_length);
}
}
else
{
I2C_DBG("Slave reveiver address matched");
i2c_state = I2C_SRX;
i2c_slave_rxbuffer_index = 0;
}
}
if (event & (RB_I2C_TRA << 16))
{ // TODO: STOP?
/* Slave transmintter */
I2C_AcknowledgeConfig(ENABLE);
I2C_DBG("Slave transmitter:");
if (event & RB_I2C_AF)
{
/* Nack received */
I2C_ClearFlag(I2C_FLAG_AF);
I2C_AcknowledgeConfig(ENABLE);
I2C_DBG(" Nack received");
/* leave slave receiver state */
i2c_state = I2C_READY;
/* clear status */
event = 0;
}
if (event & (RB_I2C_BTF | RB_I2C_TxE))
{
/* if there is more to send, ack, otherwise send 0xff */
if (i2c_slave_txbuffer_index < i2c_slave_txbuffer_length)
{
/* copy data to output register */
I2C_SendData(i2c_slave_txbuffer[i2c_slave_txbuffer_index++]);
I2C_DBG(" send (%#x)\n",
i2c_slave_txbuffer[i2c_slave_txbuffer_index - 1]);
}
else
{
I2C_SendData(0xff);
I2C_DBG(" no more data, send 0xff");
}
}
}
else
{
/* Slave receiver */
I2C_DBG("Slave receiver:");
if (event & RB_I2C_RxNE)
{
/* if there is still room in the rx buffer */
if (i2c_slave_rxbuffer_index < I2C_BUFFER_LENGTH)
{
/* put byte in buffer and ack */
i2c_slave_rxbuffer[i2c_slave_rxbuffer_index++] = I2C_ReceiveData();
I2C_AcknowledgeConfig(ENABLE);
I2C_DBG(" received (%#x)\n",
i2c_slave_rxbuffer[i2c_slave_rxbuffer_index - 1]);
}
else
{
// otherwise nack
I2C_AcknowledgeConfig(DISABLE);
}
}
if (event & RB_I2C_STOPF)
{
/* ack future responses and leave slave receiver state */
R16_I2C_CTRL1 |= RB_I2C_PE; // clear flag
I2C_DBG(" reveive stop");
/* callback to user defined callback */
if (slave_cb && slave_cb->on_receive)
{
slave_cb->on_receive(i2c_slave_rxbuffer, i2c_slave_rxbuffer_index);
}
/* since we submit rx buffer , we can reset it */
i2c_slave_rxbuffer_index = 0;
}
if (event & RB_I2C_AF)
{
I2C_ClearFlag(I2C_FLAG_AF);
/* ack future responses */
I2C_AcknowledgeConfig(ENABLE);
}
}
}
if (event & RB_I2C_BERR)
{
I2C_ClearFlag(RB_I2C_BERR);
I2C_GenerateSTOP(ENABLE);
i2c_error = I2C_BUS_ERROR;
I2C_DBG("RB_I2C_BERR");
}
if (event & RB_I2C_ARLO)
{
I2C_ClearFlag(RB_I2C_ARLO);
i2c_error = I2C_ARB_LOST;
I2C_DBG("RB_I2C_ARLO");
}
if (event & RB_I2C_OVR)
{
I2C_ClearFlag(RB_I2C_OVR);
i2c_error = I2C_OVR;
I2C_DBG("RB_I2C_OVR");
}
if (event & RB_I2C_PECERR)
{
I2C_ClearFlag(RB_I2C_PECERR);
i2c_error = I2C_PECERR;
I2C_DBG("RB_I2C_PECERR");
}
if (event & RB_I2C_TIMEOUT)
{
I2C_ClearFlag(RB_I2C_TIMEOUT);
i2c_error = I2C_TIMEOUT;
I2C_DBG("RB_I2C_TIMEOUT");
}
if (event & RB_I2C_SMBALERT)
{
I2C_ClearFlag(RB_I2C_SMBALERT);
i2c_error = I2C_SMBALERT;
I2C_DBG("RB_I2C_SMBALERT");
}
}
#endif