mirror of
https://gitee.com/Lyon1998/pikapython.git
synced 2025-01-29 17:22:56 +08:00
277 lines
9.1 KiB
C
277 lines
9.1 KiB
C
#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;
|
||
}
|