#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