225 lines
5.7 KiB
C
225 lines
5.7 KiB
C
/*
|
|
* Copyright (c) 2006-2024, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2024-04-08 QT-one first version
|
|
*/
|
|
|
|
#include "drv_i2c.h"
|
|
|
|
#ifdef RT_USING_I2C
|
|
#if !defined(BSP_USING_I2C0_HW) && !defined(BSP_USING_I2C1_HW)
|
|
#error "Please define at least one BSP_USING_I2Cx_HW"
|
|
/* this driver can be disabled at menuconfig RT-Thread Components Device Drivers */
|
|
#endif
|
|
|
|
struct ht32_i2c_config
|
|
{
|
|
HT_I2C_TypeDef *i2c_x;
|
|
const char *i2c_name;
|
|
IRQn_Type irq;
|
|
};
|
|
|
|
struct ht32_i2c
|
|
{
|
|
struct ht32_i2c_config *config;
|
|
struct rt_i2c_bus_device i2c_bus;
|
|
};
|
|
|
|
enum
|
|
{
|
|
#ifdef BSP_USING_I2C0_HW
|
|
I2C0_INDEX,
|
|
#endif
|
|
#ifdef BSP_USING_I2C1_HW
|
|
I2C1_INDEX,
|
|
#endif
|
|
};
|
|
|
|
static struct ht32_i2c_config i2c_config[] =
|
|
{
|
|
#ifdef BSP_USING_I2C0_HW
|
|
{
|
|
.i2c_x = HT_I2C0,
|
|
.i2c_name = BSP_USING_I2C0_HW_NAME,
|
|
.irq = I2C0_IRQn
|
|
},
|
|
#endif
|
|
#ifdef BSP_USING_I2C1_HW
|
|
{
|
|
.i2c_x = HT_I2C1,
|
|
.i2c_name = BSP_USING_I2C1_HW_NAME,
|
|
.irq = I2C1_IRQn
|
|
},
|
|
#endif
|
|
};
|
|
|
|
static struct ht32_i2c i2cs[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0};
|
|
|
|
static rt_size_t ht32_i2c_init(struct ht32_i2c *i2c_drv)
|
|
{
|
|
struct ht32_i2c_config *i2c_config = i2c_drv->config;
|
|
|
|
CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
|
|
#ifdef BSP_USING_I2C0_HW
|
|
if (HT_I2C0 == i2c_config->i2c_x)
|
|
{
|
|
CKCUClock.Bit.I2C0 = 1;
|
|
}
|
|
#endif
|
|
#ifdef BSP_USING_I2C1_HW
|
|
if (HT_I2C1 == i2c_config->i2c_x)
|
|
{
|
|
CKCUClock.Bit.I2C1 = 1;
|
|
}
|
|
#endif
|
|
CKCUClock.Bit.AFIO = 1;
|
|
CKCU_PeripClockConfig(CKCUClock, ENABLE);
|
|
|
|
ht32_hardware_i2c_gpio_init(i2c_config->i2c_x);
|
|
|
|
I2C_InitTypeDef I2C_InitStructure;
|
|
I2C_InitStructure.I2C_GeneralCall = DISABLE;
|
|
I2C_InitStructure.I2C_AddressingMode = I2C_ADDRESSING_7BIT;
|
|
I2C_InitStructure.I2C_Acknowledge = DISABLE;
|
|
I2C_InitStructure.I2C_OwnAddress = 0x00;
|
|
I2C_InitStructure.I2C_Speed = 400000;
|
|
I2C_InitStructure.I2C_SpeedOffset = 0;
|
|
|
|
I2C_Init(i2c_config->i2c_x, &I2C_InitStructure);
|
|
I2C_Cmd(i2c_config->i2c_x, ENABLE);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static int ht32_i2c_read(struct ht32_i2c_config *hi2c,
|
|
rt_uint16_t slave_address,
|
|
rt_uint8_t *p_buffer,
|
|
rt_uint16_t data_byte)
|
|
{
|
|
uint16_t date_num = 0;
|
|
uint8_t data = 0xFF;
|
|
|
|
/* Determine if the bus is idle */
|
|
while (I2C_GetFlagStatus(hi2c->i2c_x, I2C_FLAG_BUSBUSY));
|
|
/* Send start bit, slave address and read/write bit */
|
|
I2C_TargetAddressConfig(hi2c->i2c_x, slave_address, I2C_MASTER_READ);
|
|
|
|
while (!I2C_CheckStatus(hi2c->i2c_x, I2C_MASTER_SEND_START));
|
|
while (!I2C_CheckStatus(hi2c->i2c_x, I2C_MASTER_RECEIVER_MODE));
|
|
I2C_AckCmd(hi2c->i2c_x, ENABLE);
|
|
while (date_num < data_byte)
|
|
{
|
|
date_num++;
|
|
|
|
while (!I2C_CheckStatus(hi2c->i2c_x, I2C_MASTER_RX_NOT_EMPTY));
|
|
data = I2C_ReceiveData(hi2c->i2c_x);
|
|
|
|
if (date_num == (data_byte - 1))
|
|
{
|
|
I2C_AckCmd(hi2c->i2c_x, DISABLE);
|
|
}
|
|
if (p_buffer != RT_NULL)
|
|
{
|
|
*p_buffer++ = data;
|
|
}
|
|
}
|
|
I2C_GenerateSTOP(hi2c->i2c_x);
|
|
while (I2C_ReadRegister(hi2c->i2c_x, I2C_REGISTER_SR) & 0x80000);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ht32_i2c_write(struct ht32_i2c_config *hi2c,
|
|
uint16_t slave_address,
|
|
uint8_t *p_buffer,
|
|
uint16_t data_byte)
|
|
{
|
|
uint16_t date_num = data_byte;
|
|
|
|
/* Determine if the bus is idle */
|
|
while (I2C_GetFlagStatus(hi2c->i2c_x, I2C_FLAG_BUSBUSY));
|
|
/* Send start bit, slave address and read/write bit */
|
|
I2C_TargetAddressConfig(hi2c->i2c_x, slave_address, I2C_MASTER_WRITE);
|
|
|
|
while (!I2C_CheckStatus(hi2c->i2c_x, I2C_MASTER_SEND_START));
|
|
|
|
while (!I2C_CheckStatus(hi2c->i2c_x, I2C_MASTER_TRANSMITTER_MODE));
|
|
while (date_num--)
|
|
{
|
|
while (!I2C_CheckStatus(hi2c->i2c_x, I2C_MASTER_TX_EMPTY));
|
|
I2C_SendData(hi2c->i2c_x, *p_buffer);
|
|
p_buffer++;
|
|
}
|
|
|
|
while (!I2C_CheckStatus(hi2c->i2c_x, I2C_MASTER_TX_EMPTY));
|
|
I2C_GenerateSTOP(hi2c->i2c_x);
|
|
while (I2C_ReadRegister(hi2c->i2c_x, I2C_REGISTER_SR) & 0x80000);
|
|
return 0;
|
|
}
|
|
|
|
static rt_ssize_t ht32_master_xfer(struct rt_i2c_bus_device *bus,
|
|
struct rt_i2c_msg msgs[],
|
|
rt_uint32_t num)
|
|
{
|
|
struct ht32_i2c *i2c_instance;
|
|
struct rt_i2c_msg *msg;
|
|
rt_uint32_t i;
|
|
|
|
i2c_instance = rt_container_of(bus, struct ht32_i2c, i2c_bus);
|
|
RT_ASSERT(bus != RT_NULL);
|
|
RT_ASSERT(msgs != RT_NULL);
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
msg = &msgs[i];
|
|
|
|
if (msg->flags & RT_I2C_RD)
|
|
{
|
|
if (ht32_i2c_read(i2c_instance->config, msg->addr, msg->buf, msg->len) != 0)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ht32_i2c_write(i2c_instance->config, msg->addr, msg->buf, msg->len) != 0)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static struct rt_i2c_bus_device_ops ht32_i2c_ops =
|
|
{
|
|
.master_xfer = ht32_master_xfer,
|
|
.slave_xfer = RT_NULL,
|
|
.i2c_bus_control = RT_NULL
|
|
};
|
|
|
|
int rt_hw_i2c_init(void)
|
|
{
|
|
int i;
|
|
rt_err_t result;
|
|
rt_size_t obj_num = sizeof(i2cs) / sizeof(struct ht32_i2c);
|
|
|
|
for (i = 0; i < obj_num; i++)
|
|
{
|
|
i2cs[i].config = &i2c_config[i];
|
|
i2cs[i].i2c_bus.parent.user_data = (void *)&i2cs[i];
|
|
i2cs[i].i2c_bus.ops = &ht32_i2c_ops;
|
|
|
|
ht32_i2c_init(&i2cs[i]);
|
|
result = rt_i2c_bus_device_register(&i2cs[i].i2c_bus, i2cs[i].config->i2c_name);
|
|
}
|
|
return result;
|
|
}
|
|
INIT_BOARD_EXPORT(rt_hw_i2c_init);
|
|
|
|
#endif /* RT_USING_I2C */
|