/** * @file HW_I2C_ATY.c * * @param Project DEVICE_GENERAL_ATY_LIB * * @author ATY * * @copyright * - Copyright 2017 - 2023 MZ-ATY * - This code follows: * - MZ-ATY Various Contents Joint Statement - * * https://mengze.top/MZ-ATY_VCJS * - CC 4.0 BY-NC-SA - * * https://creativecommons.org/licenses/by-nc-sa/4.0/ * - Your use will be deemed to have accepted the terms of this statement. * * @brief Familiar functions of I2C for all embedded device * * @version * - 1_01_220602 > ATY * -# Preliminary version, first Release * - 1_02_220804 > ATY * -# Change delay flow * -# Change SDA set function * -# Add Read/Write function * -Undone: hardware not test ******************************************************************************** */ #ifndef __HW_I2C_ATY_C #define __HW_I2C_ATY_C #include "HW_I2C_ATY.h" /******************************* For user *************************************/ void OLED_Delay(uint8_t t) { while(t--); } /******************************************************************************/ #ifndef __I2C_HARDWARE_ATY // 1: Out, 0: In, config default out uint8_t i2c_SdaDir = 1; /** * @brief Set SDA output */ void I2C_SDA_SetOut(void) { if(i2c_SdaDir == 0) { i2c_SdaDir = 1; GPIO_SET_OUT(I2C_SDA_PORT, I2C_SDA_PIN); } } /** * @brief Set SDA input */ void I2C_SDA_SetIn(void) { if(i2c_SdaDir == 1) { i2c_SdaDir = 0; GPIO_SET_IN(I2C_SDA_PORT, I2C_SDA_PIN); } } /** * @brief Star I2C bus * @note START:when CLK is high,DATA change form high to low */ void I2C_Start(void) { I2C_SDA_SET_OUT; OLED_Delay(SHORT_DELAY); I2C_SDA_SET_H; I2C_SCL_SET_H; OLED_Delay(SHORT_DELAY); I2C_SDA_SET_L; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_L; } /** * @brief Stop I2C bus * @note STOP:when CLK is high DATA change form low to high */ void I2C_Stop(void) { I2C_SDA_SET_OUT; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_L; I2C_SDA_SET_L; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_H; OLED_Delay(SHORT_DELAY); I2C_SDA_SET_H; } /** * @brief I2C ack */ void I2C_Ack(void) { I2C_SDA_SET_OUT; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_L; I2C_SDA_SET_L; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_H; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_L; } /** * @brief I2C no ack */ void I2C_NoAck(void) { I2C_SDA_SET_OUT; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_L; I2C_SDA_SET_H; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_H; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_L; } /** * @brief Wait ack coming * @param maxErrTime max time to wait until fail * @return 0 success, !0: fail */ uint8_t I2C_WaitAck(uint16_t maxErrTime) { uint16_t errTime = 0; I2C_SDA_SET_IN; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_H; OLED_Delay(SHORT_DELAY); while(I2C_SDA_GET_H) { errTime++; OLED_Delay(2); if(errTime > maxErrTime) { I2C_Stop(); return 1; } } I2C_SCL_SET_L; return 0; } /** * @brief I2C send one byte * @param byte data to send */ void I2C_WriteByte(uint8_t byte) { uint8_t isb_i; I2C_SDA_SET_OUT; OLED_Delay(LONG_DELAY); I2C_SCL_SET_L; for(isb_i = 0; isb_i < 8; isb_i++) { OLED_Delay(SHORT_DELAY); if((byte & 0x80) >> 7) I2C_SDA_SET_H; else I2C_SDA_SET_L; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_H; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_L; byte <<= 1; } OLED_Delay(SHORT_DELAY); I2C_SDA_SET_H; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_H; // OLED_Delay(SHORT_DELAY); // I2C_SCL_SET_L; } /** * @brief I2C read one byte * @param ack if send ACK or not * @return data to read */ uint8_t I2C_ReadByte(uint8_t ack) { uint8_t irb_i, byte = 0; I2C_SDA_SET_IN; OLED_Delay(LONG_DELAY); for(irb_i = 0; irb_i < 8; irb_i++) { I2C_SCL_SET_L; OLED_Delay(SHORT_DELAY); I2C_SCL_SET_H; OLED_Delay(SHORT_DELAY); byte <<= 1; if(I2C_SDA_GET_H) byte++; } I2C_SCL_SET_L; if(ack) I2C_Ack(); else I2C_NoAck(); return byte; } /** * @brief Write serial data to reg * @param addr slave machine address * @param data_t data to write(uint8) * @param len length of write data(uint8) * @return 0: success, !0: error */ uint8_t I2C_Write(uint8_t addr, uint8_t* data_t, uint8_t len) { uint8_t i = 0; I2C_Start(); I2C_WriteByte(addr << 1 | 0); if(I2C_WaitAck(I2C_WAIT_ACK_TIME)) return 1; for(i = 0; i < len; i++) { I2C_WriteByte(data_t[i]); if(I2C_WaitAck(I2C_WAIT_ACK_TIME)) return 1; } I2C_Stop(); return 0; } /** * @brief Write serial data to reg * @param addr slave machine address * @param data_t data to write(uint8) * @param len length of write data(uint8) * @return 0: success, !0: error */ uint8_t I2C_Write_NoStop(uint8_t addr, uint8_t* data_t, uint8_t len) { uint8_t i = 0; I2C_Start(); I2C_WriteByte(addr << 1 | 0); if(I2C_WaitAck(I2C_WAIT_ACK_TIME)) return 1; for(i = 0; i < len; i++) { I2C_WriteByte(data_t[i]); if(I2C_WaitAck(I2C_WAIT_ACK_TIME)) return 1; } return 0; } /** * @brief Read serial data to reg * @param addr slave machine address * @param data_t data to read(uint8) * @param len length of read data(uint8) * @return 0: success, !0: error */ uint8_t I2C_Read(uint8_t addr, uint8_t* data_t, uint8_t len) { I2C_Start(); I2C_WriteByte(addr << 1 | 1); if(I2C_WaitAck(I2C_WAIT_ACK_TIME)) return 1; while(len--) { if(len > 0) *data_t++ = I2C_ReadByte(1); else *data_t++ = I2C_ReadByte(0); } I2C_Stop(); return 0; } /** * @brief Write serial data to reg * @param addr slave machine address * @param reg reg addr to write * @param data_t data to write(uint8) * @param len length of write data(uint8) * @return 0: success, !0: error */ uint8_t I2C_WriteReg(uint8_t addr, uint8_t reg, uint8_t* data_t, uint8_t len) { uint8_t i = 0; I2C_Start(); I2C_WriteByte(addr << 1 | 0); if(I2C_WaitAck(I2C_WAIT_ACK_TIME)) { I2C_Stop(); return 1; } if(reg != 0) { I2C_WriteByte(reg); I2C_WaitAck(I2C_WAIT_ACK_TIME); } for(i = 0; i < len; i++) { I2C_WriteByte(data_t[i]); if(I2C_WaitAck(I2C_WAIT_ACK_TIME)) { I2C_Stop(); return 1; } } I2C_Stop(); return 0; } /** * @brief Read serial data to reg * @param addr slave machine address * @param reg reg addr to read * @param data_t data to read(uint8) * @param len length of read data(uint8) * @return 0: success, !0: error */ uint8_t I2C_ReadReg(uint8_t addr, uint8_t reg, uint8_t* data_t, uint8_t len) { I2C_Start(); I2C_WriteByte(addr << 1 | 0); if(I2C_WaitAck(I2C_WAIT_ACK_TIME)) { I2C_Stop(); return 1; } I2C_WriteByte(reg); I2C_WaitAck(I2C_WAIT_ACK_TIME); I2C_Stop(); I2C_Start(); I2C_WriteByte(addr << 1 | 1); I2C_WaitAck(I2C_WAIT_ACK_TIME); while(len) { if(len == 1) *data_t = I2C_ReadByte(0); else *data_t = I2C_ReadByte(1); len--; data_t++; } I2C_Stop(); return 0; } #else #if defined(__STM32_HAL_ATY) #include "i2c.h" /** * @brief Eliminate HAL_I2C bug * @warning Put "__HAL_RCC_I2C1_CLK_ENABLE();" before GPIO init */ //void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) //{ // GPIO_InitTypeDef GPIO_InitStruct = {0}; // if(hi2c->Instance==I2C1) // { // /* USER CODE BEGIN I2C1_MspInit 0 */ // __HAL_RCC_I2C1_CLK_ENABLE(); // /* USER CODE END I2C1_MspInit 0 */ // // __HAL_RCC_GPIOB_CLK_ENABLE(); // /**I2C1 GPIO Configuration // PB6 ------> I2C1_SCL // PB7 ------> I2C1_SDA // */ // GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; // GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // // /* Peripheral clock enable */ // //__HAL_RCC_I2C1_CLK_ENABLE(); // /* USER CODE BEGIN I2C1_MspInit 1 */ // // /* USER CODE END I2C1_MspInit 1 */ // } // //} /** * @brief Write serial data to reg * @param addr slave machine address * @param data_t data to write(uint8) * @param len length of write data(uint8) * @return 0: success, !0: error */ uint8_t I2C_Write(uint8_t addr, uint8_t* data_t, uint8_t len) { uint8_t i = 3; while(i--) { if(HAL_I2C_Master_Transmit(&I2CH_N, addr << 1 | 0, data_t, len, 1000) == HAL_OK) return 0; } return 1; } /** * @brief Read serial data to reg * @param addr slave machine address * @param data_t data to read(uint8) * @param len length of read data(uint8) * @return 0: success, !0: error */ uint8_t I2C_Read(uint8_t addr, uint8_t* data_t, uint8_t len) { uint8_t i = 3; while(i--) { if(HAL_I2C_Master_Receive(&I2CH_N, addr << 1 | 1, data_t, len, 1000) == HAL_OK) return 0; } return 1; } #elif defined(__ESP8266_RTOS_ATY) #include "driver/i2c.h" #define I2C_EXAMPLE_MASTER_SCL_IO 2 /*!< gpio number for I2C master clock */ #define I2C_EXAMPLE_MASTER_SDA_IO 14 /*!< gpio number for I2C master data */ #define I2C_EXAMPLE_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */ #define I2C_EXAMPLE_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ #define I2C_EXAMPLE_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ /** * @brief i2c master initialization */ static esp_err_t i2c_example_master_init() { int i2c_master_port = I2CH_N; i2c_config_t conf; conf.mode = I2C_MODE_MASTER; conf.sda_io_num = I2C_EXAMPLE_MASTER_SDA_IO; conf.sda_pullup_en = 1; conf.scl_io_num = I2C_EXAMPLE_MASTER_SCL_IO; conf.scl_pullup_en = 1; conf.clk_stretch_tick = 300; // 300 ticks, Clock stretch is about 210us, you can make changes according to the actual situation. ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, conf.mode)); ESP_ERROR_CHECK(i2c_param_config(i2c_master_port, &conf)); return ESP_OK; } /** * @brief Write serial data to reg * @param addr slave machine address * @param data_t data to write(uint8) * @param len length of write data(uint8) * @return 0: success, !0: error */ uint8_t I2C_Write(uint8_t addr, uint8_t* data_t, uint8_t len) { int ret; i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, addr << 1 | 0, ACK_CHECK_EN); i2c_master_write(cmd, data_t, len, ACK_CHECK_EN); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(I2CH_N, cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); return ret; } /** * @brief Read serial data to reg * @param addr slave machine address * @param data_t data to read(uint8) * @param len length of read data(uint8) * @return 0: success, !0: error */ uint8_t I2C_Read(uint8_t addr, uint8_t* data_t, uint8_t len) { int ret; i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, addr << 1 | 0, ACK_CHECK_EN); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(I2CH_N, cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); if(ret != ESP_OK) { return ret; } cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, addr << 1 | 1, ACK_CHECK_EN); i2c_master_read(cmd, data_t, len, LAST_NACK_VAL); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); return ret; } // void Wait() // { // while(!(I2CMSST & 0x40)); // I2CMSST &= ~0x40; // } // void Start() // { // I2CMSCR = 0x01; //发送START命令 // Wait(); // } // void SendData(char dat) // { // I2CTXD = dat; //写数据到数据缓冲区 // I2CMSCR = 0x02; //发送SEND命令 // Wait(); // } // void RecvACK() // { // I2CMSCR = 0x03; //发送读ACK命令 // Wait(); // } // char RecvData() // { // I2CMSCR = 0x04; //发送RECV命令 // Wait(); // return I2CRXD; // } // void SendACK() // { // I2CMSST = 0x00; //设置ACK信号 // I2CMSCR = 0x05; //发送ACK命令 // Wait(); // } // void SendNAK() // { // I2CMSST = 0x01; //设置NAK信号 // I2CMSCR = 0x05; //发送ACK命令 // Wait(); // } // void Stop() // { // I2CMSCR = 0x06; //发送STOP命令 // Wait(); // } // void Delay() // { // int i; // for(i = 0; i < 3000; i++) // { // _nop_(); // _nop_(); // _nop_(); // _nop_(); // } // } #endif /* PLATFORM */ #endif /* __I2C_HARDWARE_ATY */ #endif /* __HW_I2C_ATY_C */ /******************************** End Of File *********************************/