/**
* @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 *********************************/