372 lines
8.6 KiB
C
372 lines
8.6 KiB
C
|
/*
|
||
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*
|
||
|
* Change Logs:
|
||
|
* Date Author Notes
|
||
|
* 2021-08-10 charlown first version
|
||
|
*/
|
||
|
|
||
|
#include <rtthread.h>
|
||
|
#include <rtdevice.h>
|
||
|
#include <rthw.h>
|
||
|
#include "board.h"
|
||
|
#include "drv_hwi2c.h"
|
||
|
|
||
|
#ifdef BSP_USING_HWI2C
|
||
|
|
||
|
#define LOG_TAG "drv.hwi2c"
|
||
|
#include "drv_log.h"
|
||
|
|
||
|
#define TIMEOUT 0x0FF
|
||
|
|
||
|
struct i2c_bus_device
|
||
|
{
|
||
|
struct rt_i2c_bus_device parent;
|
||
|
I2C_TypeDef *periph;
|
||
|
};
|
||
|
|
||
|
#ifdef BSP_USING_HWI2C1
|
||
|
|
||
|
struct i2c_bus_device i2c_bus1;
|
||
|
#endif
|
||
|
|
||
|
#ifdef BSP_USING_HWI2C2
|
||
|
|
||
|
struct i2c_bus_device i2c_bus2;
|
||
|
#endif
|
||
|
|
||
|
static int ch32f1_i2c_read(I2C_TypeDef *i2c_periph,
|
||
|
rt_uint8_t flags,
|
||
|
rt_uint16_t slave_address,
|
||
|
rt_uint8_t *p_buffer,
|
||
|
rt_uint16_t data_byte)
|
||
|
{
|
||
|
rt_uint32_t try;
|
||
|
|
||
|
if (flags & RT_I2C_ADDR_10BIT)
|
||
|
{
|
||
|
//fixme
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//7 bit address
|
||
|
try = 0;
|
||
|
while (I2C_GetFlagStatus(i2c_periph, I2C_FLAG_BUSY) != RESET)
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus read getflag timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
|
||
|
I2C_GenerateSTART(i2c_periph, ENABLE);
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_MODE_SELECT))
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus read checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
I2C_Send7bitAddress(i2c_periph, (slave_address << 1), I2C_Direction_Transmitter);
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus read checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
|
||
|
I2C_GenerateSTART(i2c_periph, ENABLE);
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_MODE_SELECT))
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus read checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
I2C_Send7bitAddress(i2c_periph, (slave_address << 1), I2C_Direction_Receiver);
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus read checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
|
||
|
if (data_byte == 1)
|
||
|
{
|
||
|
try = 0;
|
||
|
while (I2C_GetFlagStatus(i2c_periph, I2C_FLAG_RXNE) == RESET)
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus read checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
|
||
|
I2C_AcknowledgeConfig(i2c_periph, DISABLE);
|
||
|
|
||
|
*p_buffer = I2C_ReceiveData(i2c_periph);
|
||
|
|
||
|
I2C_GenerateSTOP(i2c_periph, ENABLE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
try = 0;
|
||
|
while (data_byte)
|
||
|
{
|
||
|
|
||
|
if (I2C_GetFlagStatus(i2c_periph, I2C_FLAG_RXNE) == RESET)
|
||
|
{
|
||
|
*p_buffer = I2C_ReceiveData(i2c_periph);
|
||
|
|
||
|
p_buffer++;
|
||
|
data_byte--;
|
||
|
try = 0;
|
||
|
|
||
|
if (data_byte == 1)
|
||
|
{
|
||
|
I2C_AcknowledgeConfig(i2c_periph, DISABLE);
|
||
|
I2C_GenerateSTOP(i2c_periph, ENABLE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus read checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
try++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int ch32f1_i2c_write(I2C_TypeDef *i2c_periph,
|
||
|
rt_uint8_t flags,
|
||
|
rt_uint16_t slave_address,
|
||
|
rt_uint8_t *p_buffer,
|
||
|
rt_uint16_t data_byte)
|
||
|
{
|
||
|
rt_uint32_t try;
|
||
|
|
||
|
if (flags & RT_I2C_ADDR_10BIT)
|
||
|
{
|
||
|
//fixme
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//7 bit address
|
||
|
try = 0;
|
||
|
while (I2C_GetFlagStatus(i2c_periph, I2C_FLAG_BUSY) != RESET)
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus write getflag timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
|
||
|
I2C_GenerateSTART(i2c_periph, ENABLE);
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_MODE_SELECT))
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus write checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
I2C_Send7bitAddress(i2c_periph, (slave_address << 1), I2C_Direction_Transmitter);
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus write checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
|
||
|
I2C_GenerateSTART(i2c_periph, ENABLE);
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_MODE_SELECT))
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus write checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
I2C_Send7bitAddress(i2c_periph, (slave_address << 1), I2C_Direction_Transmitter);
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus write checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
|
||
|
try = 0;
|
||
|
while (I2C_GetFlagStatus(i2c_periph, I2C_FLAG_TXE) == RESET)
|
||
|
{
|
||
|
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus write checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
|
||
|
while (data_byte)
|
||
|
{
|
||
|
I2C_SendData(i2c_periph, *p_buffer);
|
||
|
p_buffer++;
|
||
|
data_byte--;
|
||
|
|
||
|
try = 0;
|
||
|
while (!I2C_CheckEvent(i2c_periph, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
||
|
{
|
||
|
if (try == TIMEOUT)
|
||
|
{
|
||
|
LOG_E("i2c bus write checkevent timeout! \n");
|
||
|
return -1;
|
||
|
}
|
||
|
try++;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
I2C_GenerateSTOP(i2c_periph, ENABLE);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static rt_size_t ch32f1_master_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
|
||
|
{
|
||
|
struct rt_i2c_msg *msg;
|
||
|
struct i2c_bus_device *i2c_bus_dev;
|
||
|
rt_uint32_t index;
|
||
|
|
||
|
i2c_bus_dev = (struct i2c_bus_device *)bus;
|
||
|
|
||
|
for (index = 0; index < num; index++)
|
||
|
{
|
||
|
msg = &msgs[index];
|
||
|
if (msg->flags & RT_I2C_RD)
|
||
|
{
|
||
|
|
||
|
if (ch32f1_i2c_read(i2c_bus_dev->periph, msg->flags, msg->addr, msg->buf, msg->len) != 0)
|
||
|
{
|
||
|
LOG_E("i2c bus write failed,i2c bus stop!");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
if (ch32f1_i2c_write(i2c_bus_dev->periph, msg->flags, msg->addr, msg->buf, msg->len) != 0)
|
||
|
{
|
||
|
LOG_E("i2c bus write failed,i2c bus stop!");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
const struct rt_i2c_bus_device_ops ch32f1_i2c_ops = {
|
||
|
.master_xfer = ch32f1_master_xfer,
|
||
|
.slave_xfer = RT_NULL,
|
||
|
.i2c_bus_control = RT_NULL,
|
||
|
};
|
||
|
|
||
|
int rt_hw_i2c_init(void)
|
||
|
{
|
||
|
int result = RT_EOK;
|
||
|
|
||
|
#ifdef BSP_USING_HWI2C1
|
||
|
|
||
|
i2c_bus1.periph = I2C1;
|
||
|
ch32f1_i2c_clock_and_io_init(i2c_bus1.periph);
|
||
|
ch32f1_i2c_config(i2c_bus1.periph);
|
||
|
|
||
|
i2c_bus1.parent.ops = &ch32f1_i2c_ops;
|
||
|
result = rt_i2c_bus_device_register(&i2c_bus1.parent, "hwi2c1");
|
||
|
if (result != RT_EOK)
|
||
|
{
|
||
|
return result;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef BSP_USING_HWI2C2
|
||
|
|
||
|
i2c_bus2.periph = I2C2;
|
||
|
ch32f1_i2c_clock_and_io_init(i2c_bus2.periph);
|
||
|
ch32f1_i2c_config(i2c_bus2.periph);
|
||
|
|
||
|
i2c_bus2.parent.ops = &ch32f1_i2c_ops;
|
||
|
|
||
|
rt_i2c_bus_device_register(&i2c_bus2.parent, "hwi2c2");
|
||
|
if (result != RT_EOK)
|
||
|
{
|
||
|
return result;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
INIT_DEVICE_EXPORT(rt_hw_i2c_init);
|
||
|
|
||
|
#endif /* BSP_USING_HWI2C */
|