pikapython/package/PikaStdDevice/pika_hal_SOFT_IIC.c
2023-03-30 11:33:13 +08:00

220 lines
6.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "../PikaStdDevice/pika_hal.h"
static int _GPIO_write(pika_dev* dev, uint32_t val) {
return pika_hal_write(dev, &val, sizeof(val));
}
static uint32_t _GPIO_read(pika_dev* dev) {
uint32_t val = 0;
pika_hal_read(dev, &val, sizeof(val));
return val;
}
static void _IIC_Delay(void) {
// Delay implementation, can be modified based on hardware platform.
// You may need to adjust the delay time to match your hardware.
}
static void _IIC_Start(pika_hal_SOFT_IIC_config* cfg) {
_GPIO_write(cfg->SDA, 1);
_GPIO_write(cfg->SCL, 1);
_IIC_Delay();
_GPIO_write(cfg->SDA, 0);
_IIC_Delay();
_GPIO_write(cfg->SCL, 0);
}
static void _IIC_Stop(pika_hal_SOFT_IIC_config* cfg) {
_GPIO_write(cfg->SDA, 0);
_GPIO_write(cfg->SCL, 1);
_IIC_Delay();
_GPIO_write(cfg->SDA, 1);
_IIC_Delay();
}
static void _IIC_SendByte(pika_hal_SOFT_IIC_config* cfg, uint8_t byte) {
for (int i = 0; i < 8; i++) {
_GPIO_write(cfg->SCL, 0);
_IIC_Delay();
if (byte & 0x80) {
_GPIO_write(cfg->SDA, 1);
} else {
_GPIO_write(cfg->SDA, 0);
}
_IIC_Delay();
_GPIO_write(cfg->SCL, 1);
_IIC_Delay();
byte <<= 1;
}
_GPIO_write(cfg->SCL, 0);
}
static uint8_t _IIC_ReadByte(pika_hal_SOFT_IIC_config* cfg, uint8_t ack) {
uint8_t byte = 0;
for (int i = 0; i < 8; i++) {
_GPIO_write(cfg->SCL, 1);
_IIC_Delay();
byte <<= 1;
if (_GPIO_read(cfg->SDA)) {
byte |= 0x01;
}
_GPIO_write(cfg->SCL, 0);
_IIC_Delay();
}
if (ack) {
_IIC_SendByte(cfg, 0xFF);
} else {
_IIC_SendByte(cfg, 0x00);
}
return byte;
}
static void set_SDA_input(pika_hal_SOFT_IIC_config* cfg) {
pika_hal_GPIO_config cfg_SDA = {0};
cfg_SDA.dir = PIKA_HAL_GPIO_DIR_IN;
pika_hal_ioctl(cfg->SDA, PIKA_HAL_IOCTL_CONFIG, &cfg_SDA);
}
static void set_SDA_output(pika_hal_SOFT_IIC_config* cfg) {
pika_hal_GPIO_config cfg_SDA = {0};
cfg_SDA.dir = PIKA_HAL_GPIO_DIR_OUT;
pika_hal_ioctl(cfg->SDA, PIKA_HAL_IOCTL_CONFIG, &cfg_SDA);
}
int pika_hal_platform_SOFT_IIC_write(pika_dev* dev, void* buf, size_t count) {
pika_hal_SOFT_IIC_config* cfg =
(pika_hal_SOFT_IIC_config*)dev->ioctl_config;
uint8_t* data = (uint8_t*)buf;
set_SDA_output(cfg);
_IIC_Start(cfg);
// 如果启用了mem_addr_ena将设备地址和内存地址发送到I2C总线
if (cfg->mem_addr_ena == PIKA_HAL_IIC_MEM_ADDR_ENA_ENABLE) {
_IIC_SendByte(cfg, cfg->slave_addr);
if (cfg->mem_addr_size == PIKA_HAL_IIC_MEM_ADDR_SIZE_8BIT) {
_IIC_SendByte(cfg, cfg->mem_addr & 0xFF);
} else if (cfg->mem_addr_size == PIKA_HAL_IIC_MEM_ADDR_SIZE_16BIT) {
_IIC_SendByte(cfg, (cfg->mem_addr >> 8) & 0xFF);
_IIC_SendByte(cfg, cfg->mem_addr & 0xFF);
}
}
for (int i = 0; i < count; i++) {
_IIC_SendByte(cfg, data[i]);
}
_IIC_Stop(cfg);
return count;
}
int pika_hal_platform_SOFT_IIC_read(pika_dev* dev, void* buf, size_t count) {
pika_hal_SOFT_IIC_config* cfg =
(pika_hal_SOFT_IIC_config*)dev->ioctl_config;
uint8_t* data = (uint8_t*)buf;
// 如果启用了mem_addr_ena先写设备地址和内存地址
if (cfg->mem_addr_ena == PIKA_HAL_IIC_MEM_ADDR_ENA_ENABLE) {
set_SDA_output(cfg);
_IIC_Start(cfg);
_IIC_SendByte(cfg, cfg->slave_addr);
if (cfg->mem_addr_size == PIKA_HAL_IIC_MEM_ADDR_SIZE_8BIT) {
_IIC_SendByte(cfg, cfg->mem_addr & 0xFF);
} else if (cfg->mem_addr_size == PIKA_HAL_IIC_MEM_ADDR_SIZE_16BIT) {
_IIC_SendByte(cfg, (cfg->mem_addr >> 8) & 0xFF);
_IIC_SendByte(cfg, cfg->mem_addr & 0xFF);
}
_IIC_Stop(cfg);
}
set_SDA_input(cfg);
_IIC_Start(cfg);
for (int i = 0; i < count - 1; i++) {
data[i] = _IIC_ReadByte(cfg, 1);
}
data[count - 1] = _IIC_ReadByte(cfg, 0);
_IIC_Stop(cfg);
return count;
}
int pika_hal_platform_SOFT_IIC_open(pika_dev* dev, char* name) {
return 0;
}
int pika_hal_platform_SOFT_IIC_close(pika_dev* dev) {
pika_hal_SOFT_IIC_config* cfg =
(pika_hal_SOFT_IIC_config*)dev->ioctl_config;
if (cfg->SDA != NULL) {
pika_hal_close(cfg->SDA);
}
if (cfg->SCL != NULL) {
pika_hal_close(cfg->SCL);
}
return 0;
}
int pika_hal_platform_SOFT_IIC_ioctl_config(pika_dev* dev,
pika_hal_SOFT_IIC_config* cfg) {
if (cfg->SDA == NULL || cfg->SCL == NULL) {
__platform_printf(
"Error: SOFT IIC config error, SDA and SCL must be set\r\n");
return -1;
}
// 检查软件IIC配置项是否正确
if (cfg->master_or_slave != PIKA_HAL_IIC_MASTER &&
cfg->master_or_slave != PIKA_HAL_IIC_SLAVE) {
__platform_printf(
"Error: SOFT IIC config error, master_or_slave must be set\r\n");
return -1;
}
if (cfg->address_width != PIKA_HAL_IIC_ADDRESS_WIDTH_7BIT &&
cfg->address_width != PIKA_HAL_IIC_ADDRESS_WIDTH_10BIT) {
__platform_printf(
"Error: SOFT IIC config error, address_width must be set\r\n");
return -1;
}
if (cfg->mem_addr_ena != PIKA_HAL_IIC_MEM_ADDR_ENA_ENABLE &&
cfg->mem_addr_ena != PIKA_HAL_IIC_MEM_ADDR_ENA_DISABLE) {
__platform_printf(
"Error: SOFT IIC config error, mem_addr_ena must be set\r\n");
return -1;
}
if (cfg->mem_addr_size != PIKA_HAL_IIC_MEM_ADDR_SIZE_8BIT &&
cfg->mem_addr_size != PIKA_HAL_IIC_MEM_ADDR_SIZE_16BIT) {
__platform_printf(
"Error: SOFT IIC config error, mem_addr_size must be set\r\n");
return -1;
}
// 在这里我们暂时不检查speed和timeout因为软件模拟的I2C可能无法精确控制速度和超时。
return 0;
}
int pika_hal_platform_SOFT_IIC_ioctl_enable(pika_dev* dev) {
pika_hal_SOFT_IIC_config* cfg =
(pika_hal_SOFT_IIC_config*)dev->ioctl_config;
if (cfg->SDA == NULL || cfg->SCL == NULL) {
__platform_printf(
"Error: SOFT IIC config error, SDA and SCL must be set\r\n");
return -1;
}
pika_hal_GPIO_config cfg_SDA = {0};
pika_hal_GPIO_config cfg_SCL = {0};
cfg_SDA.dir = PIKA_HAL_GPIO_DIR_OUT;
cfg_SCL.dir = PIKA_HAL_GPIO_DIR_OUT;
pika_hal_ioctl(cfg->SDA, PIKA_HAL_IOCTL_CONFIG, &cfg_SDA);
pika_hal_ioctl(cfg->SCL, PIKA_HAL_IOCTL_CONFIG, &cfg_SCL);
pika_hal_ioctl(cfg->SDA, PIKA_HAL_IOCTL_ENABLE);
pika_hal_ioctl(cfg->SCL, PIKA_HAL_IOCTL_ENABLE);
_GPIO_write(cfg->SDA, 1);
_GPIO_write(cfg->SCL, 1);
return 0;
}
int pika_hal_platform_SOFT_IIC_ioctl_disable(pika_dev* dev) {
pika_hal_SOFT_IIC_config* cfg =
(pika_hal_SOFT_IIC_config*)dev->ioctl_config;
pika_hal_ioctl(cfg->SDA, PIKA_HAL_IOCTL_DISABLE);
pika_hal_ioctl(cfg->SCL, PIKA_HAL_IOCTL_DISABLE);
return 0;
}