/** * @file HW_I2C_ATY.c * * @param Project DEVICE_GENERAL_ATY_LIB * * @author ATY * * @copyright * - Copyright 2017 - 2025 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 * - 1_02_240108 > ATY * -# add multy addr and channel * - 1_01_240111 > ATY * -# add lock ******************************************************************************** */ #ifndef __HW_I2C_ATY_C #define __HW_I2C_ATY_C #include "HW_I2C_ATY.h" /******************************* For user *************************************/ /******************************************************************************/ /** * @brief Star I2C bus * * @param dev * @return uint8_t * @note START:when CLK is high,DATA change form high to low */ uint8_t I2C_Start(struct HW_I2C_ATY_Dev* dev) { __ATY_LOCK(dev); dev->sdaSet('I', _ATY_IO_O); dev->delay(SHORT_DELAY); dev->sdaSet('L', _ATY_HL_H); dev->sclSet(_ATY_HL_H); dev->delay(SHORT_DELAY); dev->sdaSet('L', _ATY_HL_L); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_L); __ATY_UNLOCK(dev); return 0; } /** * @brief Stop I2C bus * * @param dev * @return uint8_t * @note STOP:when CLK is high DATA change form low to high */ uint8_t I2C_Stop(struct HW_I2C_ATY_Dev* dev) { __ATY_LOCK(dev); dev->sdaSet('I', _ATY_IO_O); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_L); dev->sdaSet('L', _ATY_HL_L); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_H); dev->delay(SHORT_DELAY); dev->sdaSet('L', _ATY_HL_H); __ATY_UNLOCK(dev); return 0; } /** * @brief I2C ack * * @param dev * @return uint8_t */ uint8_t I2C_Ack(struct HW_I2C_ATY_Dev* dev) { __ATY_LOCK(dev); dev->sdaSet('I', _ATY_IO_O); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_L); dev->sdaSet('L', _ATY_HL_L); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_H); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_L); __ATY_UNLOCK(dev); return 0; } /** * @brief I2C no ack * * @param dev * @return uint8_t */ uint8_t I2C_NoAck(struct HW_I2C_ATY_Dev* dev) { __ATY_LOCK(dev); dev->sdaSet('I', _ATY_IO_O); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_L); dev->sdaSet('L', _ATY_HL_H); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_H); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_L); __ATY_UNLOCK(dev); return 0; } /** * @brief Wait ack coming * * @param maxErrTime max time to wait until fail * @param dev * @return 0 success, !0: fail */ uint8_t I2C_WaitAck(uint16_t maxErrTime, struct HW_I2C_ATY_Dev* dev) { uint16_t errTime = 0; __ATY_LOCK(dev); dev->sdaSet('I', _ATY_IO_I); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_H); dev->delay(SHORT_DELAY); while(dev->sdaGet() == 1) { errTime++; dev->delay(2); if(errTime > maxErrTime) { __ATY_UNLOCK(dev); I2C_Stop(dev); return 1; } } dev->sclSet(_ATY_HL_L); __ATY_UNLOCK(dev); return 0; } /** * @brief I2C send one byte * * @param byte data to send * @param dev * @return uint8_t */ uint8_t I2C_WriteByte(uint8_t byte, struct HW_I2C_ATY_Dev* dev) { uint8_t isb_i; __ATY_LOCK(dev); dev->sdaSet('I', _ATY_IO_O); dev->delay(LONG_DELAY); dev->sclSet(_ATY_HL_L); for(isb_i = 0; isb_i < 8; isb_i++) { dev->delay(SHORT_DELAY); if((byte & 0x80) >> 7) dev->sdaSet('L', _ATY_HL_H); else dev->sdaSet('L', _ATY_HL_L); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_H); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_L); byte <<= 1; } dev->delay(SHORT_DELAY); dev->sdaSet('L', _ATY_HL_H); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_H); // dev->delay(SHORT_DELAY); // dev->sclSet(_ATY_HL_L); __ATY_UNLOCK(dev); return 0; } /** * @brief I2C read one byte * * @param ack if send ACK or not * @param dev * @return data to read */ uint8_t I2C_ReadByte(uint8_t ack, struct HW_I2C_ATY_Dev* dev) { uint8_t irb_i, byte = 0; __ATY_LOCK(dev); dev->sdaSet('I', _ATY_IO_I); dev->delay(LONG_DELAY); for(irb_i = 0; irb_i < 8; irb_i++) { dev->sclSet(_ATY_HL_L); dev->delay(SHORT_DELAY); dev->sclSet(_ATY_HL_H); dev->delay(SHORT_DELAY); byte <<= 1; if(dev->sdaGet() == 1) byte++; } dev->sclSet(_ATY_HL_L); __ATY_UNLOCK(dev); if(ack) I2C_Ack(dev); else I2C_NoAck(dev); 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) * @param dev * @return 0: success, !0: error */ uint8_t I2C_Write(uint8_t addr, uint8_t* data_t, uint8_t len, struct HW_I2C_ATY_Dev* dev) { if(dev->hardwareEnable == 1){ uint8_t errCode = 0; __ATY_LOCK(dev); errCode = dev->i2cProcess((addr << 1 | 0), data_t, len, _ATY_RW_W); __ATY_UNLOCK(dev); return errCode; } else{ uint8_t i = 0; I2C_Start(dev); I2C_WriteByte((addr << 1 | 0), dev); if(I2C_WaitAck(I2C_WAIT_ACK_TIME, dev)) return 1; for(i = 0; i < len; i++) { I2C_WriteByte(data_t[i], dev); if(I2C_WaitAck(I2C_WAIT_ACK_TIME, dev)) return 1; } I2C_Stop(dev); 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) * @param dev * @return 0: success, !0: error */ uint8_t I2C_Write_NoStop(uint8_t addr, uint8_t* data_t, uint8_t len, struct HW_I2C_ATY_Dev* dev) { uint8_t i = 0; I2C_Start(dev); I2C_WriteByte((addr << 1 | 0), dev); if(I2C_WaitAck(I2C_WAIT_ACK_TIME, dev)) return 1; for(i = 0; i < len; i++) { I2C_WriteByte(data_t[i], dev); if(I2C_WaitAck(I2C_WAIT_ACK_TIME, dev)) 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) * @param dev * @return 0: success, !0: error */ uint8_t I2C_Read(uint8_t addr, uint8_t* data_t, uint8_t len, struct HW_I2C_ATY_Dev* dev) { if(dev->hardwareEnable == 1){ uint8_t errCode = 0; __ATY_LOCK(dev); errCode = dev->i2cProcess((addr << 1 | 1), data_t, len, _ATY_RW_R); __ATY_UNLOCK(dev); return errCode; } else{ I2C_Start(dev); I2C_WriteByte((addr << 1 | 1), dev); if(I2C_WaitAck(I2C_WAIT_ACK_TIME, dev)) return 1; while(len--) { if(len > 0) *data_t++ = I2C_ReadByte(1, dev); else *data_t++ = I2C_ReadByte(0, dev); } I2C_Stop(dev); 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) * @param dev * @return 0: success, !0: error */ uint8_t I2C_WriteReg(uint8_t addr, uint8_t reg, uint8_t* data_t, uint8_t len, struct HW_I2C_ATY_Dev* dev) { uint8_t i = 0; I2C_Start(dev); I2C_WriteByte((addr << 1 | 0), dev); if(I2C_WaitAck(I2C_WAIT_ACK_TIME, dev)) { I2C_Stop(dev); return 1; } if(reg != 0) { I2C_WriteByte(reg, dev); I2C_WaitAck(I2C_WAIT_ACK_TIME, dev); } for(i = 0; i < len; i++) { I2C_WriteByte(data_t[i], dev); if(I2C_WaitAck(I2C_WAIT_ACK_TIME, dev)) { I2C_Stop(dev); return 1; } } I2C_Stop(dev); 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) * @param dev * @return 0: success, !0: error */ uint8_t I2C_ReadReg(uint8_t addr, uint8_t reg, uint8_t* data_t, uint8_t len, struct HW_I2C_ATY_Dev* dev) { I2C_Start(dev); I2C_WriteByte((addr << 1 | 0), dev); if(I2C_WaitAck(I2C_WAIT_ACK_TIME, dev)) { I2C_Stop(dev); return 1; } I2C_WriteByte(reg, dev); I2C_WaitAck(I2C_WAIT_ACK_TIME, dev); I2C_Stop(dev); I2C_Start(dev); I2C_WriteByte((addr << 1 | 1), dev); I2C_WaitAck(I2C_WAIT_ACK_TIME, dev); while(len) { if(len == 1) *data_t = I2C_ReadByte(0, dev); else *data_t = I2C_ReadByte(1, dev); len--; data_t++; } I2C_Stop(dev); return 0; } #endif /* __HW_I2C_ATY_C */ /************************************ etc *************************************/ /* init */ /* software */ // void I2C_1_SCL_SET(uint8_t level){ } // void I2C_1_SDA_SET(uint8_t cmd, uint8_t param){ } // uint8_t I2C_1_SDA_GET(void){ return 0; } // // STM32 HAL // uint8_t I2C_1(uint8_t addr, uint8_t* data_t, uint8_t len, uint8_t rw){ // if(rw == _ATY_RW_W) // return (uint8_t)HAL_I2C_Master_Transmit(&hi2c1, (addr << 1 | 0), data_t, len, 1000); // else if(rw == _ATY_RW_R) // return (uint8_t)HAL_I2C_Master_Receive(&hi2c1, (addr << 1 | 1), data_t, len, 1000); // else if(rw == _ATY_RW_RW) // todo: no stop // return 0; // return 0; // } // // 51 // todo: not tested // uint8_t I2C_1(uint8_t addr, uint8_t* data_t, uint8_t len, uint8_t rw) // { // if(rw == _ATY_RW_W){ // uint8_t i = 0; // uint16_t errCount = 1000; // // Start(); // I2CMSCR = 0x01; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // // SendData((addr << 1 | 0)); // I2CTXD = (addr << 1 | 0); // I2CMSCR = 0x02; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // // RecvACK(); // I2CMSCR = 0x03; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // for(i = 0; i < len; i++){ // // SendData(data_t[i]); // I2CTXD = data_t[i]; // I2CMSCR = 0x02; // // RecvACK(); // I2CMSCR = 0x03; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // } // // Stop(); // I2CMSCR = 0x06; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // if(errCount == 0) return 1; // return 0; // } // else if(rw == _ATY_RW_R){ // uint8_t i = 0; // // Start(); // I2CMSCR = 0x01; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // // SendData((addr << 1 | 0)); // I2CTXD = (addr << 1 | 0); // I2CMSCR = 0x02; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // // RecvACK(); // I2CMSCR = 0x03; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // for(i = 0; i < len; i++){ // // data_t[i] = RecvData(); // I2CMSCR = 0x04; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // data_t[i] = I2CRXD; // if(i == len - 1){ // // SendNAK(); // I2CMSST = 0x01; // I2CMSCR = 0x05; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // } // else{ // // SendACK(); // I2CMSST = 0x00; // I2CMSCR = 0x05; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // } // } // // Stop(); // I2CMSCR = 0x06; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // if(errCount == 0) return 1; // return 0; // } // else if(rw == _ATY_RW_RW){ // uint8_t i = 0; // // Start(); // I2CMSCR = 0x01; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // // SendData((addr << 1 | 0)); // I2CTXD = (addr << 1 | 0); // I2CMSCR = 0x02; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // // RecvACK(); // I2CMSCR = 0x03; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // for(i = 0; i < len; i++){ // // SendData(data_t[i]); // I2CTXD = data_t[i]; // I2CMSCR = 0x02; // // RecvACK(); // I2CMSCR = 0x03; // while((!(I2CMSST & 0x40)) && errCount) errCount--; // if(errCount == 0) return 1; else errCount = 1000; // I2CMSST &= ~0x40; // } // if(errCount == 0) return 1; // return 0; // } // } // // ESP8266_RTOS // todo: not tested // #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; // } /* software */ // void I2C_1_SCL_SET(uint8_t level){ // if(level == _ATY_HL_L){ // GPIO_SET_L(I2C_SCL_PORT, I2C_SCL_PIN); // } // else if(level == _ATY_HL_H){ // GPIO_SET_H(I2C_SCL_PORT, I2C_SCL_PIN); // } // } // void I2C_1_SDA_SET(uint8_t cmd, uint8_t param){ // if(cmd == 'I'){ // if(param == _ATY_IO_I){ // GPIO_SET_IN(I2C_SDA_PORT, I2C_SDA_PIN); // } // else if(param == _ATY_IO_O){ // GPIO_SET_OUT(I2C_SDA_PORT, I2C_SDA_PIN); // } // } // else if(cmd == 'L'){ // if(param == _ATY_HL_L){ // GPIO_SET_L(I2C_SDA_PORT, I2C_SDA_PIN); // } // else if(param == _ATY_HL_H){ // GPIO_SET_H(I2C_SDA_PORT, I2C_SDA_PIN); // } // } // } // uint8_t I2C_1_SDA_GET(void){ return GPIO_GET(I2C_SDA_PORT, I2C_SDA_PIN); } // uint8_t I2C_1(uint8_t addr, uint8_t* data_t, uint8_t len, uint8_t rw){ return 0; } /* public */ // void I2C_Delay(uint8_t t){ while(t--); } // struct HW_I2C_ATY_Dev HW_I2C_ATY_Dev_1 = { // .hardwareEnable = 1, // .sclSet = I2C_1_SCL_SET, // .sdaSet = I2C_1_SDA_SET, // .sdaGet = I2C_1_SDA_GET, // .i2cProcess = I2C_1, // .delay = I2C_Delay, // .lock = _ATY_UNLOCKED, // .debugEnable = 0, // .LOG = printf // }; /* use */ // I2C_Write(addr, data_t, len, &HW_I2C_ATY_Dev_1); // I2C_Read(addr, data_t, len, &HW_I2C_ATY_Dev_1); /******************************************************************************/ /******************************** End Of File *********************************/