pikapython/package/PikaStdDevice/pika_hal_SOFT_IIC.c
2023-07-15 14:59:56 +08:00

277 lines
9.1 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 "pika_hal.h"
#include <stdint.h>
static void _IIC_SDA_input(pika_hal_SOFT_IIC_config* iic_cfg) {
pika_hal_GPIO_config cfg_SDA = {0};
cfg_SDA.dir = PIKA_HAL_GPIO_DIR_IN;
pika_hal_ioctl(iic_cfg->SDA, PIKA_HAL_IOCTL_CONFIG, &cfg_SDA);
}
static void _IIC_SDA_output(pika_hal_SOFT_IIC_config* iic_cfg) {
pika_hal_GPIO_config cfg_SDA = {0};
cfg_SDA.dir = PIKA_HAL_GPIO_DIR_OUT;
pika_hal_ioctl(iic_cfg->SDA, PIKA_HAL_IOCTL_CONFIG, &cfg_SDA);
}
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) {
pika_sleep_ms(3);
}
static void _IIC_Start(pika_hal_SOFT_IIC_config* cfg) {
pika_debug("iic start");
_IIC_SDA_output(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) {
pika_debug("iic stop");
_IIC_SDA_output(cfg);
_GPIO_write(cfg->SDA, 0);
_GPIO_write(cfg->SCL, 1);
_IIC_Delay();
_GPIO_write(cfg->SDA, 1);
_IIC_Delay();
}
static pika_bool _IIC_SendByte(pika_hal_SOFT_IIC_config* cfg, uint8_t byte) {
pika_debug(" - iic write: 0x%02X", byte);
_IIC_SDA_output(cfg);
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;
}
// 在发送完字节后检查ACK信号
_GPIO_write(cfg->SCL, 0);
_IIC_Delay();
_IIC_SDA_input(cfg); // 设置SDA为输入
_GPIO_write(cfg->SCL, 1); // 将SCL线设置为高让从设备发送ACK信号
int timeout = 1000;
uint32_t ack = 0;
do {
_IIC_Delay();
ack = !_GPIO_read(cfg->SDA); // 如果从设备发送了ACK信号SDA线会被拉低
} while (ack == 0 && timeout-- > 0);
// pika_debug("ack timeout:%d", timeout);
if (timeout <= 0) {
pika_platform_printf("Error: IIC write byte timeout\r\n");
}
_GPIO_write(cfg->SCL, 0); // 将SCL线设置为低完成一个I2C周期
return ack;
}
static void _IIC_Ack(pika_hal_SOFT_IIC_config* cfg) {
_GPIO_write(cfg->SCL, 0); // 拉低时钟线
_IIC_SDA_output(cfg); // 设置SDA为输出
_GPIO_write(cfg->SDA, 0); // 拉低数据线
_IIC_Delay();
_GPIO_write(cfg->SCL, 1); // 产生时钟
_IIC_Delay();
_GPIO_write(cfg->SCL, 0); // 拉低时钟线
}
static void _IIC_NAck(pika_hal_SOFT_IIC_config* cfg) {
_GPIO_write(cfg->SCL, 0); // 拉低时钟线
_IIC_SDA_output(cfg); // 设置SDA为输出
_GPIO_write(cfg->SDA, 1); // 数据线拉高
_IIC_Delay();
_GPIO_write(cfg->SCL, 1); // 产生时钟
_IIC_Delay();
_GPIO_write(cfg->SCL, 0); // 拉低时钟线
}
static uint8_t _IIC_ReadByte(pika_hal_SOFT_IIC_config* cfg, uint8_t ack) {
uint8_t byte = 0;
_IIC_SDA_input(cfg);
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();
}
// 在读取完一个字节后发送ACK信号
if (ack) {
_IIC_Ack(cfg); // 如果ack为真发送ACK信号
} else {
_IIC_NAck(cfg); // 如果ack为假发送NACK信号
}
pika_debug(" - iic read: 0x%02X", byte);
return byte;
}
int pika_hal_platform_SOFT_IIC_write(pika_dev* dev, void* buf, size_t count) {
pika_hal_SOFT_IIC_config* iic_cfg =
(pika_hal_SOFT_IIC_config*)dev->ioctl_config;
uint8_t* data = (uint8_t*)buf;
_IIC_Start(iic_cfg);
uint8_t addr_write = (iic_cfg->slave_addr << 1) | 0x00; // 方向位为0代表写
// pika_debug("iic addr_write: 0x%02X", addr_write);
_IIC_SendByte(iic_cfg, addr_write); // 方向位为0代表写
// 如果启用了mem_addr_ena将设备地址和内存地址发送到I2C总线
if (iic_cfg->mem_addr_ena == PIKA_HAL_IIC_MEM_ADDR_ENA_ENABLE) {
if (iic_cfg->mem_addr_size == PIKA_HAL_IIC_MEM_ADDR_SIZE_8BIT) {
_IIC_SendByte(iic_cfg, iic_cfg->mem_addr & 0xFF);
} else if (iic_cfg->mem_addr_size == PIKA_HAL_IIC_MEM_ADDR_SIZE_16BIT) {
_IIC_SendByte(iic_cfg, (iic_cfg->mem_addr >> 8) & 0xFF);
_IIC_SendByte(iic_cfg, iic_cfg->mem_addr & 0xFF);
}
}
for (int i = 0; i < count; i++) {
_IIC_SendByte(iic_cfg, data[i]);
}
_IIC_Stop(iic_cfg);
return count;
}
int pika_hal_platform_SOFT_IIC_read(pika_dev* dev, void* buf, size_t count) {
pika_hal_SOFT_IIC_config* iic_cfg =
(pika_hal_SOFT_IIC_config*)dev->ioctl_config;
uint8_t* data = (uint8_t*)buf;
_IIC_Start(iic_cfg);
// 如果启用了mem_addr_ena先写设备地址和内存地址
if (iic_cfg->mem_addr_ena == PIKA_HAL_IIC_MEM_ADDR_ENA_ENABLE) {
uint8_t addr_write =
(iic_cfg->slave_addr << 1) | 0x00; // 方向位为0代表写
// pika_debug("iic addr_write: 0x%02X", addr_write);
_IIC_SendByte(iic_cfg, addr_write); // 方向位为0代表写
if (iic_cfg->mem_addr_size == PIKA_HAL_IIC_MEM_ADDR_SIZE_8BIT) {
_IIC_SendByte(iic_cfg, iic_cfg->mem_addr & 0xFF);
} else if (iic_cfg->mem_addr_size == PIKA_HAL_IIC_MEM_ADDR_SIZE_16BIT) {
_IIC_SendByte(iic_cfg, (iic_cfg->mem_addr >> 8) & 0xFF);
_IIC_SendByte(iic_cfg, iic_cfg->mem_addr & 0xFF);
}
_IIC_Start(iic_cfg);
}
uint8_t addr_read = (iic_cfg->slave_addr << 1) | 0x01; // 方向位为1代表读
// pika_debug("iic addr_read: 0x%02X", addr_read);
_IIC_SendByte(iic_cfg, addr_read); // 方向位为1代表读
for (int i = 0; i < count - 1; i++) {
// data[i] = _IIC_ReadByte(iic_cfg, 1);
data[i] = _IIC_ReadByte(iic_cfg, 1);
}
data[count - 1] = _IIC_ReadByte(iic_cfg, 0);
_IIC_Stop(iic_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;
}