/**
* @file HW_I2C_ATY.c
*
* @param Project DEVICE_GENERAL_ATY_LIB
*
* @author ATY
*
* @copyright
* - Copyright 2017 - 2026 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 functions of I2C for C platform
*
* @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,
// };
/* 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 *********************************/