From a4e58354cd2f4fe4cdaf15aeec7a6263f10d19fc Mon Sep 17 00:00:00 2001 From: stark1898y <1658608470@qq.com> Date: Sun, 15 Dec 2024 15:45:11 +0800 Subject: [PATCH] =?UTF-8?q?bsp=5Fi2c=20=E5=87=BA=E7=8E=B0=E6=89=93?= =?UTF-8?q?=E5=8D=B0float=E5=BC=82=E5=B8=B8=EF=BC=8C=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E4=B8=8A=E5=87=BA=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APP/peripheral_main.c | 5 + BSP/inc/bsp_i2c.h | 143 ++++++++ BSP/src/bsp_i2c.c | 759 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 907 insertions(+) create mode 100644 BSP/inc/bsp_i2c.h create mode 100644 BSP/src/bsp_i2c.c diff --git a/APP/peripheral_main.c b/APP/peripheral_main.c index 5986dd1..734ec73 100644 --- a/APP/peripheral_main.c +++ b/APP/peripheral_main.c @@ -24,6 +24,8 @@ #include "bsp_beep_led_emv.h" +#include "bsp_i2c.h" + #include "log.h" #include "bsp_uart.h" @@ -175,6 +177,9 @@ int main(void) GAPRole_PeripheralInit(); Peripheral_Init(); + DelayMs(100); + GXHTC3C_Init(); + BSP_FLASH_Init(); Main_Circulation(); diff --git a/BSP/inc/bsp_i2c.h b/BSP/inc/bsp_i2c.h new file mode 100644 index 0000000..ada6b44 --- /dev/null +++ b/BSP/inc/bsp_i2c.h @@ -0,0 +1,143 @@ +/* + * @Author : stark1898y 1658608470@qq.com + * @Date : 2024-12-15 15:42:00 + * @LastEditors : stark1898y 1658608470@qq.com + * @LastEditTime : 2024-12-15 15:42:00 + * @FilePath : \BLE_TYQ_CH592F - 副本\BSP\inc\bsp_i2c.h + * @Description : + * + * Copyright (c) 2024 by yzy, All Rights Reserved. + */ +#ifndef __BSP_I2C_H__ +#define __BSP_I2C_H__ + +#include +#include +#include + +#include "CONFIG.h" + +#define GXHTC3C_ADDR 0x70 +// #define GXHTC3C_7BIT_ADDR 0x38 // (GXHTC3C_ADDR >> 1) + +// 供电电压VDD从0上升上电电压VPOR,芯片会进入空闲状态。然后应该通过发送命令让芯片进入休眠状态以降低芯片功耗 +#define GXHTC3C_CMD_SLEEP 0xB098 +// 当芯片处于休眠状态时,如果要进行其它的命令操作,需要发送唤醒命令 +#define GXHTC3C_CMD_WAKEUP 0x3517 + +#define GXHTC3C_CMD_NORMAL_CLK_STRE_ON_TEMP_FRONT 0x7CA2 +#define GXHTC3C_CMD_NORMAL_CLK_STRE_ON_HUMI_FRONT 0x5C24 + +#define GXHTC3C_CMD_NORMAL_CLK_STRE_OFF_TEMP_FRONT 0x7866 +#define GXHTC3C_CMD_NORMAL_CLK_STRE_OFF_HUMI_FRONT 0x58E0 + +#define GXHTC3C_CMD_LOW_CLK_STRE_ON_TEMP_FRONT 0x6458 +#define GXHTC3C_CMD_LOW_CLK_STRE_ON_HUMI_FRONT 0x44DE + +#define GXHTC3C_CMD_LOW_CLK_STRE_OFF_TEMP_FRONT 0x609C +#define GXHTC3C_CMD_LOW_CLK_STRE_OFF_HUMI_FRONT 0x401A + +#define GXHTC3C_CMD_SOFT_REST 0x805D + +// 读传感器序列号 +#define GXHTC3C_CMD_READ_ID 0xEFC8 + +#define I2C_BUFFER_LENGTH 32 +#define I2C_READ 1 +#define I2C_WRITE 0 + +typedef enum { + I2C_READY, + I2C_MRX, + I2C_MTX, + I2C_SRX, + I2C_STX, +}i2c_state_t; + +typedef enum { + I2C_NO_MEM = 1, + I2C_STATE, + I2C_MT_NACK, + I2C_ARB_LOST, + I2C_BUS_ERROR, + I2C_OVR, + I2C_PECERR, + I2C_TIMEOUT, + I2C_SMBALERT, +}i2c_error_t; + +/** + * @brief User callback function on I2C slave transmitting. + * + * @param data Pointer to user data to transmit. + * + * @param len Pointer to user data length. + */ +typedef void (*i2c_on_slave_transmit)(uint8_t *data, uint8_t *len); + +/** + * @brief User callback function on I2C slave received. + * + * @param data Pointer to current received data. + * + * @param len Received data length. + */ +typedef void (*i2c_on_slave_receive)(uint8_t *data, uint8_t len); + +struct i2c_slave_cb { + i2c_on_slave_transmit on_transmit; + i2c_on_slave_receive on_receive; +}; + +// /** +// * @brief I2C interrupt routine initialization. +// * +// * @param address I2C address. +// */ +// void i2c_app_init(uint8_t address); + +/** + * @brief I2C slave user callback function regiester. + * + * @param cb Pointer to user callback function. + */ +void i2c_slave_cb_register(struct i2c_slave_cb *cb); + +/** + * @brief I2C master write data to slave. + * + * @param addr_7bit I2C slave 7bit address. + * @param data Pointer to the write data. + * @param length Write data length. + * @param wait Choose to wait for the write process to end or not. + * @param send_stop Choose to send stop or not. + * @return 0 If successful. + */ +int i2c_write_to(uint8_t addr_7bit, const uint8_t *data, uint8_t length, + uint8_t wait, uint8_t send_stop); + +/** + * @brief I2C master read data to slave + * + * @param addr_7bit I2C slave 7bit address. + * @param data Pointer to the read data to put in. + * @param length Read data length. + * @param send_stop Choose to send stop or not + * @param timeout Read process timeout. + * @return Negative on error code otherwise indicates the actual read length. + */ +int i2c_read_from(uint8_t addr_7bit, uint8_t *data, uint8_t length, + uint8_t send_stop, int timeout); + +void GXHTC3C_Sleep(void); +void GXHTC3C_Wakeup(void); +void GXHTC3C_GetStart(void); +uint8_t GXHTC3C_GetTempHumi(float *humi, float *temp); + +void BSP_I2C_DeInit(void); + +void GXHTC3C_Init(void); + + +#endif // !__BSP_I2C_H__ + diff --git a/BSP/src/bsp_i2c.c b/BSP/src/bsp_i2c.c new file mode 100644 index 0000000..926dfce --- /dev/null +++ b/BSP/src/bsp_i2c.c @@ -0,0 +1,759 @@ +#include "bsp_i2c.h" + +#include "bsp_uart.h" +#include "log.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]; +uint8_t i2c_rx_data[6]; + +void BSP_I2C_Init(uint8_t address) +{ + i2c_state = I2C_READY; + i2c_send_stop = true; + i2c_in_repstart = false; + + GPIOB_ModeCfg(GPIO_Pin_14 | GPIO_Pin_15, 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; + + 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 + 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; + } + return 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("humi %.2f %, temp %.2f C", humi, temp); + } + + GXHTC3C_Sleep(); +} + +void GXHTC3C_Init(void) +{ +#if 1 + BSP_I2C_Init(MASTER_ADDR); + int ret; + + GXHTC3C_Sleep(); + DelayMs(100); + + GXHTC3C_Wakeup(); + DelayMs(20); + + GXHTC3C_GetStart(); + DelayMs(20); + float humi, temp; + ret = GXHTC3C_GetTempHumi(&humi, &temp); + if (ret == 0) + { + logDebug("humi %.2f %, temp %.2f C", humi, temp); + } + + GXHTC3C_Sleep(); + + for (uint8_t i = 0; i < 3; i++) + { + GXHTC3C_Read(); + } + +#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