774 lines
20 KiB
C
774 lines
20 KiB
C
#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
|