chore: migrate project into clean repository

This commit is contained in:
yuuux
2026-08-13 16:50:52 +08:00
commit d1d25a09e7
27405 changed files with 9422808 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
# LISA I2C Driver
#
# Copyright (c) 2025, LISTENAI
# SPDX-License-Identifier: Apache-2.0
if(CONFIG_LISA_I2C)
listenai_library_named(lisa_i2c)
listenai_library_sources(
lisa_i2c_arcs.c # ARCS 平台适配层
)
listenai_include_directories(.)
endif() # CONFIG_LISA_I2C

View File

@@ -0,0 +1,34 @@
# LISA I2C Driver Configuration
#
# Copyright (c) 2025, LISTENAI
# SPDX-License-Identifier: Apache-2.0
menuconfig LISA_I2C
bool "Enable LISA I2C Driver"
default n
depends on LISA_DEVICE
help
Enable LISA I2C device driver based on lisa_device framework.
Provides master and slave mode I2C communication interfaces.
This driver wraps the HAL I2C functions and provides a unified
device interface for I2C operations including read, write, and
combined write-read transactions.
if LISA_I2C
config LISA_I2C0
bool "Enable LISA I2C0"
default n
help
Enable LISA I2C0 controller.
I2C0 is the first I2C controller available on the ARCS platform.
config LISA_I2C1
bool "Enable LISA I2C1"
default n
help
Enable LISA I2C1 controller.
I2C1 is the second I2C controller available on the ARCS platform.
endif # LISA_I2C

View File

@@ -0,0 +1,223 @@
# I2C 驱动
基于 lisa_device 框架的 I2C 设备驱动,为 ARCS 平台提供统一的 I2C 通信接口。
## 功能特性
- **设备支持**: I2C0、I2C1 两个独立的 I2C 控制器,可独立配置和使用
- **灵活配置**: 可选择性启用 I2C0 或 I2C1节省资源
- **主机模式**: 支持标准模式100kHz、快速模式400kHz、快速增强模式1MHz
- **传输接口**: 支持单次读写和组合传输(写后读)
- **设备探测**: 支持 0 字节传输进行设备探测
- **线程安全**: 内部使用互斥锁保护并发访问
## 配置选项
`prj.conf` 中启用驱动:
```kconfig
CONFIG_LISA_I2C=y # 使能 I2C 驱动框架
CONFIG_LISA_I2C0=y # 使能 I2C0 控制器(可选)
CONFIG_LISA_I2C1=y # 使能 I2C1 控制器(可选)
```
**注意**: 根据应用需求选择启用对应的 I2C 控制器,未启用的控制器不会编译进代码。
## API 接口
### 配置接口
```c
int lisa_i2c_configure(lisa_device_t *dev, const lisa_i2c_config_t *config);
int lisa_i2c_get_config(lisa_device_t *dev, lisa_i2c_config_t *config);
```
### 传输接口
```c
int lisa_i2c_transfer(lisa_device_t *dev, lisa_i2c_msg_t *msgs, uint32_t num_msgs);
int lisa_i2c_write(lisa_device_t *dev, uint16_t addr, const uint8_t *buf, uint32_t len);
int lisa_i2c_read(lisa_device_t *dev, uint16_t addr, uint8_t *buf, uint32_t len);
```
## 速度模式
驱动支持以下速度模式:
- `LISA_I2C_SPEED_STANDARD` (100000 Hz): 标准模式
- `LISA_I2C_SPEED_FAST` (400000 Hz): 快速模式
- `LISA_I2C_SPEED_FAST_PLUS` (1000000 Hz): 快速增强模式
## 传输标志
- `LISA_I2C_FLAG_NONE`: 无特殊标志(默认为写操作)
- `LISA_I2C_FLAG_READ`: 读操作标志(不设置则为写操作)
- `LISA_I2C_FLAG_NO_START`: 不发送 START 条件(当前实现中忽略)
- `LISA_I2C_FLAG_NO_STOP`: 不发送 STOP 条件(用于组合传输)
- `LISA_I2C_FLAG_10BIT_ADDR`: 使用 10 位地址模式
## 使用示例
### 基本配置和读写
```c
#include "lisa_i2c.h"
#include "lisa_device.h"
// 1. 获取 I2C 设备
lisa_device_t *i2c_dev = lisa_device_get("i2c0");
if (!lisa_device_ready(i2c_dev)) {
printf("Error: i2c0 device not ready\n");
return -1;
}
// 2. 配置 I2C 总线(可选,默认为标准模式)
lisa_i2c_config_t config = {
.speed = LISA_I2C_SPEED_FAST, // 400kHz
.master_mode = true,
.slave_addr = 0
};
lisa_i2c_configure(i2c_dev, &config);
// 3. 写入数据
uint8_t write_data[] = {0x01, 0x02, 0x03};
int ret = lisa_i2c_write(i2c_dev, 0x50, write_data, sizeof(write_data));
if (ret != 0) {
printf("Write failed: %d\n", ret);
}
// 4. 读取数据
uint8_t read_data[4];
ret = lisa_i2c_read(i2c_dev, 0x50, read_data, sizeof(read_data));
if (ret != 0) {
printf("Read failed: %d\n", ret);
}
```
### 组合传输(写后读)
```c
// 使用 transfer 接口实现写后读操作
lisa_i2c_msg_t msgs[2];
// 第一个消息:写入寄存器地址
uint8_t reg_addr = 0x01;
msgs[0].addr = 0x50;
msgs[0].flags = LISA_I2C_FLAG_NO_STOP; // 写操作,不发送 STOP继续传输
msgs[0].len = 1;
msgs[0].buf = &reg_addr;
// 第二个消息:读取数据
uint8_t read_buf[4];
msgs[1].addr = 0x50;
msgs[1].flags = LISA_I2C_FLAG_READ; // 读操作标志
msgs[1].len = sizeof(read_buf);
msgs[1].buf = read_buf;
int ret = lisa_i2c_transfer(i2c_dev, msgs, 2);
if (ret != 0) {
printf("Transfer failed: %d\n", ret);
}
```
### 设备探测
```c
// 使用 0 字节传输探测设备是否存在
lisa_i2c_msg_t msg = {
.addr = 0x50,
.flags = LISA_I2C_FLAG_NONE,
.len = 0, // 0 字节传输
.buf = NULL
};
int ret = lisa_i2c_transfer(i2c_dev, &msg, 1);
if (ret == LISA_DEVICE_OK) {
printf("Device found at address 0x50\n");
} else if (ret == LISA_DEVICE_ERR_NACK) {
printf("No device at address 0x50\n");
}
```
## 硬件配置
### 引脚复用配置
I2C 驱动在初始化时会自动调用板型目录中定义的 `lisa_i2c0_pinmux()``lisa_i2c1_pinmux()` 函数,用于配置 I2C 引脚的复用功能。
**配置位置**:
- **定义**: `boards/<板型名>/pinmux.c` 中实现 `lisa_i2c0_pinmux()``lisa_i2c1_pinmux()` 函数
- **声明**: `boards/<板型名>/pinmux.h` 中声明函数
- **调用时机**: I2C0/I2C1 设备初始化时自动调用
**示例** (参考 `boards/arcs_evb/pinmux.c`):
```c
void lisa_i2c0_pinmux()
{
/* I2C0: PA22=SDA, PA23=SCL, 功能码 8 */
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 22, 8);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 23, 8);
}
void lisa_i2c1_pinmux()
{
/* I2C1: PB0=SCL, PB1=SDA, 功能码 9 */
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_B, 0, 9);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_B, 1, 9);
}
```
**注意**:
- 该函数由板型相关代码实现,不同板型的引脚配置可能不同
- 只需配置实际使用的 I2C 控制器引脚
- I2C 功能码通常为 8 或 9具体请参考芯片手册
- 如需自定义引脚配置,可在 sample 中重写 pinmux 函数(参考 `samples/drivers/devices/lisa_uart/poll_in/src/main.c`
## 注意事项
1. **引脚配置**: 使用 I2C 前需要先配置对应的 GPIO 引脚为 I2C 功能,驱动初始化时会自动调用 pinmux 函数
2. **设备选择**: 使用前需在 `prj.conf` 中启用对应的 I2C 控制器
3. **设备初始化**: 系统启动时会自动初始化已启用的 I2C 设备
4. **线程安全**: 驱动内部已实现线程保护,可在多线程环境中使用
5. **超时处理**: 所有传输操作都有 1 秒的超时限制
6. **错误处理**:
- `LISA_DEVICE_ERR_NACK`: 从机无应答(设备不存在或地址错误)
- `LISA_DEVICE_ERR_TIMEOUT`: 传输超时
- `LISA_DEVICE_ERR_IO`: 硬件 IO 错误
7. **transfer 函数使用**:
- 支持读写操作,通过 `LISA_I2C_FLAG_READ` 标志区分
- 支持组合传输(使用 `LISA_I2C_FLAG_NO_STOP` 实现写后读)
- 支持 0 字节传输进行设备探测
- 简单读写建议使用 `lisa_i2c_read()``lisa_i2c_write()` 函数
8. **引脚上拉**: I2C 总线需要外接上拉电阻(通常 4.7kΩ),或确认开发板已提供默认上拉
9. **设备探测**: 使用 0 字节传输(`len=0`)进行设备探测时,驱动会严格检查 ACK 响应,确保探测结果准确
## 文件说明
- `lisa_i2c.h` - 驱动头文件,包含所有 API 和类型定义
- `lisa_i2c_arcs.c` - ARCS 平台适配实现
- `CMakeLists.txt` - 构建配置
- `Kconfig` - 配置选项
- `README.md` - 驱动使用说明
## 示例程序
完整的示例程序位于:
- `samples/drivers/devices/lisa_i2c/basic_write_read/` - I2C 基础读写示例
- 演示 `lisa_i2c_write()` API 用法
- 演示 `lisa_i2c_read()` API 用法
- 演示 `lisa_i2c_transfer()` 组合传输用法
- `samples/drivers/devices/lisa_i2c/slave_scan/` - I2C 从机扫描示例
- 扫描 I2C 总线上的所有从机地址
- 检测已连接的 I2C 设备

View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) 2025, LISTENAI
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file lisa_i2c.h
* @brief LISA I2C 设备驱动接口
*/
#pragma once
#include "lisa_device.h"
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ========================================================================
* I2C 类型定义
* ======================================================================== */
/**
* @brief I2C 传输标志位
*/
typedef enum {
LISA_I2C_FLAG_NONE = 0x00, /* 无特殊标志 */
LISA_I2C_FLAG_NO_START = 0x01, /* 不发送START条件 */
LISA_I2C_FLAG_NO_STOP = 0x02, /* 不发送STOP条件 */
LISA_I2C_FLAG_10BIT_ADDR = 0x04, /* 使用10位地址模式 */
LISA_I2C_FLAG_READ = 0x08, /* 读操作(默认为写操作) */
} lisa_i2c_flags_t;
/**
* @brief I2C 速度模式
*/
typedef enum {
LISA_I2C_SPEED_STANDARD = 100000, /* 标准模式: 100 kHz */
LISA_I2C_SPEED_FAST = 400000, /* 快速模式: 400 kHz */
LISA_I2C_SPEED_FAST_PLUS = 1000000,/* 快速增强模式: 1 MHz */
} lisa_i2c_speed_t;
/**
* @brief I2C 消息结构体
*
* 用于描述一次 I2C 传输操作
*/
typedef struct {
uint16_t addr; /* 从机地址7位或10位 */
uint8_t flags; /* 传输标志位lisa_i2c_flags_t */
uint16_t len; /* 数据长度 */
uint8_t *buf; /* 数据缓冲区指针 */
} lisa_i2c_msg_t;
/**
* @brief I2C 配置结构体
*/
typedef struct {
uint32_t speed; /* 总线速度Hz */
bool master_mode; /* true: 主机模式, false: 从机模式 */
uint16_t slave_addr; /* 从机模式下的本机地址 */
} lisa_i2c_config_t;
/* ========================================================================
* I2C 设备 API 结构体
* ======================================================================== */
typedef struct {
int (*configure)(lisa_device_t *dev, const lisa_i2c_config_t *config);
int (*get_config)(lisa_device_t *dev, lisa_i2c_config_t *config);
int (*transfer)(lisa_device_t *dev, lisa_i2c_msg_t *msgs, uint32_t num_msgs);
int (*write)(lisa_device_t *dev, uint16_t addr, const uint8_t *buf, uint32_t len);
int (*read)(lisa_device_t *dev, uint16_t addr, uint8_t *buf, uint32_t len);
} lisa_i2c_api_t;
/* ========================================================================
* I2C 对外接口函数
* ======================================================================== */
/* ===== 配置接口 ===== */
/**
* @brief 配置I2C总线
*
* 配置I2C总线的工作模式和参数。
*
* @param dev I2C设备指针
* @param config 配置参数结构体指针,包含:
* - speed: 总线速度Hz
* - master_mode: 主机/从机模式
* - slave_addr: 从机模式下的本机地址
*
* @return 0 成功
* @return LISA_DEVICE_ERR_INVALID 参数无效
* @return LISA_DEVICE_ERR_NOT_SUPPORT 不支持该操作
* @return <0 其他错误
*
* @note 配置前请确保设备已初始化
*/
static inline int lisa_i2c_configure(lisa_device_t *dev, const lisa_i2c_config_t *config)
{
if (!dev || !dev->api || !config) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_api_t *api = (lisa_i2c_api_t *)dev->api;
return api->configure ? api->configure(dev, config) : LISA_DEVICE_ERR_NOT_SUPPORT;
}
/**
* @brief 获取I2C总线当前配置
*
* 读取I2C总线的当前配置信息。
*
* @param dev I2C设备指针
* @param config 输出参数,用于接收配置信息
*
* @return 0 成功
* @return LISA_DEVICE_ERR_INVALID 参数无效
* @return LISA_DEVICE_ERR_NOT_SUPPORT 不支持该操作
* @return <0 其他错误
*/
static inline int lisa_i2c_get_config(lisa_device_t *dev, lisa_i2c_config_t *config)
{
if (!dev || !dev->api || !config) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_api_t *api = (lisa_i2c_api_t *)dev->api;
return api->get_config ? api->get_config(dev, config) : LISA_DEVICE_ERR_NOT_SUPPORT;
}
/* ===== 传输接口 ===== */
/**
* @brief I2C通用传输接口
*
* 执行一组I2C消息传输支持组合传输如写后读
*
* @param dev I2C设备指针
* @param msgs 消息数组指针
* @param num_msgs 消息数量
*
* @return 0 成功
* @return LISA_DEVICE_ERR_INVALID 参数无效
* @return LISA_DEVICE_ERR_NOT_SUPPORT 不支持该操作
* @return LISA_DEVICE_ERR_TIMEOUT 传输超时
* @return LISA_DEVICE_ERR_NACK 从机无应答
* @return <0 其他错误
*
* @note 消息数组中的传输会按顺序执行
* @note 使用flags可以控制START/STOP条件的发送
*/
static inline int lisa_i2c_transfer(lisa_device_t *dev, lisa_i2c_msg_t *msgs, uint32_t num_msgs)
{
if (!dev || !dev->api || !msgs || num_msgs == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_api_t *api = (lisa_i2c_api_t *)dev->api;
return api->transfer ? api->transfer(dev, msgs, num_msgs) : LISA_DEVICE_ERR_NOT_SUPPORT;
}
/**
* @brief I2C写数据
*
* 向指定从机地址写入数据。
*
* @param dev I2C设备指针
* @param addr 从机地址7位
* @param buf 数据缓冲区指针
* @param len 数据长度
*
* @return 0 成功
* @return LISA_DEVICE_ERR_INVALID 参数无效
* @return LISA_DEVICE_ERR_NOT_SUPPORT 不支持该操作
* @return LISA_DEVICE_ERR_TIMEOUT 传输超时
* @return LISA_DEVICE_ERR_NACK 从机无应答
* @return <0 其他错误
*/
static inline int lisa_i2c_write(lisa_device_t *dev, uint16_t addr, const uint8_t *buf, uint32_t len)
{
if (!dev || !dev->api || !buf || len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_api_t *api = (lisa_i2c_api_t *)dev->api;
return api->write ? api->write(dev, addr, buf, len) : LISA_DEVICE_ERR_NOT_SUPPORT;
}
/**
* @brief I2C读数据
*
* 从指定从机地址读取数据。
*
* @param dev I2C设备指针
* @param addr 从机地址7位
* @param buf 数据缓冲区指针
* @param len 要读取的数据长度
*
* @return 0 成功
* @return LISA_DEVICE_ERR_INVALID 参数无效
* @return LISA_DEVICE_ERR_NOT_SUPPORT 不支持该操作
* @return LISA_DEVICE_ERR_TIMEOUT 传输超时
* @return LISA_DEVICE_ERR_NACK 从机无应答
* @return <0 其他错误
*/
static inline int lisa_i2c_read(lisa_device_t *dev, uint16_t addr, uint8_t *buf, uint32_t len)
{
if (!dev || !dev->api || !buf || len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_api_t *api = (lisa_i2c_api_t *)dev->api;
return api->read ? api->read(dev, addr, buf, len) : LISA_DEVICE_ERR_NOT_SUPPORT;
}
/* ========================================================================
* 便捷宏定义
* ======================================================================== */
/**
* @brief 默认I2C配置标准速度主机模式
*/
#define LISA_I2C_CONFIG_DEFAULT() \
{ \
.speed = LISA_I2C_SPEED_STANDARD, \
.master_mode = true, \
.slave_addr = 0, \
}
/**
* @brief 快速模式I2C配置
*/
#define LISA_I2C_CONFIG_FAST() \
{ \
.speed = LISA_I2C_SPEED_FAST, \
.master_mode = true, \
.slave_addr = 0, \
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,590 @@
/*
* Copyright (c) 2025, LISTENAI
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file lisa_i2c_arcs.c
* @brief LISA I2C ARCS 平台适配层
*
* 此文件实现 ARCS 芯片平台的 I2C 硬件适配
*/
#include "lisa_i2c.h"
#include "Driver_I2C.h"
#include <stddef.h>
#include <string.h>
#include <lisa_mutex.h>
#include <lisa_time.h>
#include "pinmux.h"
#define LOG_TAG "lisa_i2c_arcs"
#include <lisa_log.h>
#include "FreeRTOS.h"
#include "task.h"
#define DEVICE_LOCK(priv) \
do { \
if (priv->mutex) { \
lisa_mutex_lock(priv->mutex, LISA_OS_WAIT_FOREVER); \
} \
} while (0)
#define DEVICE_UNLOCK(priv) \
do { \
if (priv->mutex) { \
lisa_mutex_unlock(priv->mutex); \
} \
} while (0)
/* ===== I2C 设备私有数据 ===== */
typedef struct {
void *hal_handler; /* HAL I2C 句柄 */
lisa_mutex_t *mutex; /* 互斥锁 */
lisa_i2c_config_t config; /* 当前配置 */
volatile uint32_t event_flags; /* 事件标志(用于同步) */
} lisa_i2c_priv_t;
/* ===== I2C 设备静态实例 ===== */
#if CONFIG_LISA_I2C0
static lisa_i2c_priv_t i2c0_priv;
#endif
#if CONFIG_LISA_I2C1
static lisa_i2c_priv_t i2c1_priv;
#endif
/* ===== HAL 事件回调函数 ===== */
#if CONFIG_LISA_I2C0
static void i2c0_event_callback(uint32_t event, void *workspace)
{
lisa_i2c_priv_t *priv = (lisa_i2c_priv_t *)workspace;
if (priv) {
priv->event_flags |= event;
}
}
#endif
#if CONFIG_LISA_I2C1
static void i2c1_event_callback(uint32_t event, void *workspace)
{
lisa_i2c_priv_t *priv = (lisa_i2c_priv_t *)workspace;
if (priv) {
priv->event_flags |= event;
}
}
#endif
/* ===== 内部辅助函数 ===== */
/**
* @brief 验证I2C速度是否在支持范围内
* @param speed 速度值Hz
* @return true 速度有效, false 速度无效
*/
static bool is_valid_speed(uint32_t speed)
{
/* 支持的速度范围100kHz 到 1MHz */
return (speed >= LISA_I2C_SPEED_STANDARD && speed <= LISA_I2C_SPEED_FAST_PLUS);
}
/**
* @brief 将 LISA I2C 速度转换为 HAL 速度常量
* @param speed 速度值Hz
* @return HAL速度常量如果速度无效返回0
*/
static uint32_t speed_to_hal_speed(uint32_t speed)
{
if (speed <= 100000) {
return CSK_I2C_BUS_SPEED_STANDARD;
} else if (speed <= 400000) {
return CSK_I2C_BUS_SPEED_FAST;
} else if (speed <= 1000000) {
return CSK_I2C_BUS_SPEED_FAST_PLUS;
} else {
/* 超出支持范围 */
return 0;
}
}
/**
* @brief 等待传输完成或错误
* @param priv I2C设备私有数据指针
* @param timeout_ms 超时时间(毫秒)
* @param is_probe 是否为设备探测0字节传输
* @return LISA_DEVICE_OK 传输成功, LISA_DEVICE_ERR_NACK 地址无应答, LISA_DEVICE_ERR_IO I/O错误, LISA_DEVICE_ERR_TIMEOUT 超时
*/
static int wait_for_transfer(lisa_i2c_priv_t *priv, uint32_t timeout_ms, bool is_probe)
{
uint32_t start_time = lisa_os_get_tick_ms();
uint32_t end_time = start_time + timeout_ms;
while (lisa_os_get_tick_ms() < end_time) {
uint32_t events = priv->event_flags;
/* 检查传输完成
* 对于设备探测0字节传输必须严格检查 NACK
* 对于正常数据传输,与原始实现保持一致
*/
if (events & CSK_I2C_EVENT_TRANSFER_DONE) {
/* 对于设备探测0字节传输严格检查地址应答 */
if (is_probe) {
/* 检查是否有地址应答 */
if (events & CSK_I2C_EVENT_ADDRESS_ACK) {
priv->event_flags = 0;
return LISA_DEVICE_OK; /* 设备存在 */
} else {
priv->event_flags = 0;
return LISA_DEVICE_ERR_NACK; /* 设备不存在 */
}
}
/* 对于正常传输,传输完成即认为成功(保持与修复前一致,以免影响 camera */
priv->event_flags = 0;
return LISA_DEVICE_OK;
}
/* 检查错误事件(仅在传输未完成时) */
if (events & (CSK_I2C_EVENT_ADDRESS_NACK | CSK_I2C_EVENT_ARBITRATION_LOST | CSK_I2C_EVENT_BUS_ERROR)) {
priv->event_flags = 0; /* 清除所有事件 */
if (events & CSK_I2C_EVENT_ADDRESS_NACK) {
return LISA_DEVICE_ERR_NACK;
}
if (events & CSK_I2C_EVENT_BUS_ERROR) {
return LISA_DEVICE_ERR_IO;
}
return LISA_DEVICE_ERR_IO;
}
/* 短暂延时,避免 CPU 占用过高 */
vTaskDelay(pdMS_TO_TICKS(1));
}
/* 超时 */
priv->event_flags = 0;
return LISA_DEVICE_ERR_TIMEOUT;
}
/* ===== ARCS平台I2C实现函数 ===== */
/**
* @brief 配置I2C总线
*/
static int arcs_i2c_configure(lisa_device_t *dev, const lisa_i2c_config_t *config)
{
if (!lisa_device_is_initialized(dev) || !config) {
return LISA_DEVICE_ERR_INVALID;
}
/* 验证速度范围 */
if (!is_valid_speed(config->speed)) {
LISA_LOGE(LOG_TAG, "Invalid I2C speed: %lu Hz (supported range: %u-%u Hz)",
config->speed, LISA_I2C_SPEED_STANDARD, LISA_I2C_SPEED_FAST_PLUS);
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_priv_t *priv = (lisa_i2c_priv_t *)dev->priv_data;
DEVICE_LOCK(priv);
/* 设置总线速度 */
uint32_t hal_speed = speed_to_hal_speed(config->speed);
if (hal_speed == 0) {
DEVICE_UNLOCK(priv);
LISA_LOGE(LOG_TAG, "Invalid I2C speed: %lu Hz (supported range: %u-%u Hz)",
config->speed, LISA_I2C_SPEED_STANDARD, LISA_I2C_SPEED_FAST_PLUS);
return LISA_DEVICE_ERR_INVALID;
}
if (I2C_Control(priv->hal_handler, CSK_I2C_BUS_SPEED, hal_speed) != 0) {
DEVICE_UNLOCK(priv);
LISA_LOGE(LOG_TAG, "Failed to set bus speed");
return LISA_DEVICE_ERR_IO;
}
/* 保存配置(仅在成功设置后) */
memcpy(&priv->config, config, sizeof(lisa_i2c_config_t));
/* 如果是从机模式,设置从机地址 */
if (!config->master_mode) {
if (I2C_Control(priv->hal_handler, CSK_I2C_OWN_ADDRESS, config->slave_addr) != 0) {
DEVICE_UNLOCK(priv);
LISA_LOGE(LOG_TAG, "Failed to set slave address");
return LISA_DEVICE_ERR_IO;
}
}
DEVICE_UNLOCK(priv);
LISA_LOGI(LOG_TAG, "I2C configured: speed=%lu Hz, mode=%s", config->speed,
config->master_mode ? "master" : "slave");
return LISA_DEVICE_OK;
}
/**
* @brief 获取I2C总线当前配置
*/
static int arcs_i2c_get_config(lisa_device_t *dev, lisa_i2c_config_t *config)
{
if (!lisa_device_is_initialized(dev) || !config) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_priv_t *priv = (lisa_i2c_priv_t *)dev->priv_data;
DEVICE_LOCK(priv);
memcpy(config, &priv->config, sizeof(lisa_i2c_config_t));
DEVICE_UNLOCK(priv);
/* 验证配置的有效性
* 如果发现配置无效(可能是之前保存的无效值),返回错误
* 调用者应该重新调用 configure 来设置有效配置
*/
if (!is_valid_speed(config->speed)) {
LISA_LOGE(LOG_TAG, "Current I2C speed is invalid: %lu Hz (supported range: %u-%u Hz). Please reconfigure with a valid speed.",
config->speed, LISA_I2C_SPEED_STANDARD, LISA_I2C_SPEED_FAST_PLUS);
return LISA_DEVICE_ERR_INVALID;
}
return LISA_DEVICE_OK;
}
/**
* @brief I2C通用传输接口
*/
static int arcs_i2c_transfer(lisa_device_t *dev, lisa_i2c_msg_t *msgs, uint32_t num_msgs)
{
if (!lisa_device_is_initialized(dev) || !msgs || num_msgs == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_priv_t *priv = (lisa_i2c_priv_t *)dev->priv_data;
DEVICE_LOCK(priv);
/* 检查是否为主机模式 */
if (!priv->config.master_mode) {
DEVICE_UNLOCK(priv);
LISA_LOGE(LOG_TAG, "Transfer only supported in master mode");
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
for (uint32_t i = 0; i < num_msgs; i++) {
lisa_i2c_msg_t *msg = &msgs[i];
/* 检查消息有效性
* 允许 len == 0 的情况(用于地址探测)
* 当 len > 0 时buf 必须有效
*/
if (msg->len > 0 && !msg->buf) {
DEVICE_UNLOCK(priv);
return LISA_DEVICE_ERR_INVALID;
}
/* 准备地址支持10位地址 */
uint32_t addr = msg->addr;
if (msg->flags & LISA_I2C_FLAG_10BIT_ADDR) {
addr |= CSK_I2C_ADDRESS_10BIT;
}
/* 判断是否为读操作(通过 LISA_I2C_FLAG_READ 标志) */
bool is_write = !(msg->flags & LISA_I2C_FLAG_READ);
/* 清除事件标志 */
priv->event_flags = 0;
/* 判断是否发送 STOP 条件 */
bool xfer_pending = (msg->flags & LISA_I2C_FLAG_NO_STOP) ? true : false;
/* 如果是第一个消息且设置了 NO_START需要特殊处理 */
/* 但 HAL 接口不支持 NO_START所以忽略该标志 */
if (i == 0 && (msg->flags & LISA_I2C_FLAG_NO_START)) {
LISA_LOGW(LOG_TAG, "NO_START flag not supported, ignored");
}
/* 执行传输
* HAL 层支持 0 字节传输(用于地址探测/ACK polling
* 当 len == 0 时buf 可以为 NULL
*/
int32_t hal_ret;
if (is_write) {
hal_ret = I2C_MasterTransmit(priv->hal_handler, addr,
msg->len > 0 ? msg->buf : NULL,
msg->len, xfer_pending);
} else {
hal_ret = I2C_MasterReceive(priv->hal_handler, addr,
msg->len > 0 ? msg->buf : NULL,
msg->len, xfer_pending);
}
if (hal_ret != 0) {
/* HAL 启动失败,尝试等待短时间检查是否有事件标志(如 NACK */
bool is_probe = (msg->len == 0); /* 0字节传输为设备探测 */
int ret = wait_for_transfer(priv, 100, is_probe); /* 100ms 短超时 */
DEVICE_UNLOCK(priv);
if (ret == LISA_DEVICE_ERR_NACK) {
return LISA_DEVICE_ERR_NACK; /* 明确返回 NACK */
}
LISA_LOGE(LOG_TAG, "HAL transfer failed: %d", hal_ret);
return LISA_DEVICE_ERR_IO;
}
/* 等待传输完成
* 对于组合传输(写后读),即使设置了 NO_STOP也需要等待第一个传输完成
* 才能启动第二个传输,否则 HAL 会返回 BUSY 错误
* 只有在最后一个消息时才发送 STOP 条件
*/
bool is_probe = (msg->len == 0); /* 0字节传输为设备探测 */
uint32_t timeout_ms = is_probe ? 50 : 1000;
int ret = wait_for_transfer(priv, timeout_ms, is_probe);
if (ret != LISA_DEVICE_OK) {
DEVICE_UNLOCK(priv);
return ret;
}
}
DEVICE_UNLOCK(priv);
return LISA_DEVICE_OK;
}
/**
* @brief I2C写数据
*/
static int arcs_i2c_write(lisa_device_t *dev, uint16_t addr, const uint8_t *buf, uint32_t len)
{
if (!lisa_device_is_initialized(dev) || !buf || len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_priv_t *priv = (lisa_i2c_priv_t *)dev->priv_data;
DEVICE_LOCK(priv);
/* 检查是否为主机模式 */
if (!priv->config.master_mode) {
DEVICE_UNLOCK(priv);
LISA_LOGE(LOG_TAG, "Write only supported in master mode");
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
/* 清除事件标志 */
priv->event_flags = 0;
/* 执行写操作 */
int32_t hal_ret = I2C_MasterTransmit(priv->hal_handler, addr, (uint8_t *)buf, len, false);
if (hal_ret != 0) {
/* HAL 启动失败,尝试等待短时间检查是否有事件标志(如 NACK */
int ret = wait_for_transfer(priv, 100, false); /* 100ms 短超时 */
DEVICE_UNLOCK(priv);
if (ret == LISA_DEVICE_ERR_NACK) {
return LISA_DEVICE_ERR_NACK; /* 明确返回 NACK */
}
LISA_LOGE(LOG_TAG, "HAL write failed: %d", hal_ret);
return LISA_DEVICE_ERR_IO;
}
/* 等待传输完成write 不是设备探测) */
int ret = wait_for_transfer(priv, 1000, false); /* 1秒超时 */
DEVICE_UNLOCK(priv);
return ret;
}
/**
* @brief I2C读数据
*/
static int arcs_i2c_read(lisa_device_t *dev, uint16_t addr, uint8_t *buf, uint32_t len)
{
if (!lisa_device_is_initialized(dev) || !buf || len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_i2c_priv_t *priv = (lisa_i2c_priv_t *)dev->priv_data;
DEVICE_LOCK(priv);
/* 检查是否为主机模式 */
if (!priv->config.master_mode) {
DEVICE_UNLOCK(priv);
LISA_LOGE(LOG_TAG, "Read only supported in master mode");
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
/* 清除事件标志 */
priv->event_flags = 0;
/* 执行读操作 */
int32_t hal_ret = I2C_MasterReceive(priv->hal_handler, addr, buf, len, false);
if (hal_ret != 0) {
/* HAL 启动失败,尝试等待短时间检查是否有事件标志(如 NACK */
int ret = wait_for_transfer(priv, 100, false); /* 100ms 短超时 */
DEVICE_UNLOCK(priv);
if (ret == LISA_DEVICE_ERR_NACK) {
return LISA_DEVICE_ERR_NACK; /* 明确返回 NACK */
}
LISA_LOGE(LOG_TAG, "HAL read failed: %d", hal_ret);
return LISA_DEVICE_ERR_IO;
}
/* 等待传输完成read 不是设备探测) */
int ret = wait_for_transfer(priv, 1000, false); /* 1秒超时 */
DEVICE_UNLOCK(priv);
return ret;
}
/* ===== ARCS I2C API 实例 ===== */
static const lisa_i2c_api_t arcs_i2c_api = {
.configure = arcs_i2c_configure,
.get_config = arcs_i2c_get_config,
.transfer = arcs_i2c_transfer,
.write = arcs_i2c_write,
.read = arcs_i2c_read,
};
/* ===== 设备初始化函数 ===== */
#if CONFIG_LISA_I2C0
static int arcs_i2c0_init(void)
{
/* 清空私有数据 */
memset(&i2c0_priv, 0, sizeof(lisa_i2c_priv_t));
/* 获取 HAL I2C0 句柄 */
i2c0_priv.hal_handler = I2C0();
if (!i2c0_priv.hal_handler) {
LISA_LOGE(LOG_TAG, "Failed to get I2C0 handler");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 创建互斥锁 */
i2c0_priv.mutex = lisa_mutex_create();
if (!i2c0_priv.mutex) {
LISA_LOGE(LOG_TAG, "Failed to create mutex");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 初始化 HAL I2C */
if (I2C_Initialize(i2c0_priv.hal_handler, i2c0_event_callback, &i2c0_priv) != 0) {
LISA_LOGE(LOG_TAG, "Failed to initialize I2C0");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 使能电源 */
if (I2C_PowerControl(i2c0_priv.hal_handler, CSK_POWER_FULL) != 0) {
LISA_LOGE(LOG_TAG, "Failed to power on I2C0");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 设置传输模式为中断模式 */
if (I2C_Control(i2c0_priv.hal_handler, CSK_I2C_TRANSMIT_MODE, 0) != 0) {
LISA_LOGE(LOG_TAG, "Failed to set I2C0 transmit mode");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 设置默认总线速度为标准模式 */
if (I2C_Control(i2c0_priv.hal_handler, CSK_I2C_BUS_SPEED, CSK_I2C_BUS_SPEED_STANDARD) != 0) {
LISA_LOGE(LOG_TAG, "Failed to set I2C0 bus speed");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 清除总线 */
I2C_Control(i2c0_priv.hal_handler, CSK_I2C_BUS_CLEAR, 0);
/* 配置 I2C0 引脚复用 */
lisa_i2c0_pinmux();
/* 设置默认配置 */
i2c0_priv.config.speed = LISA_I2C_SPEED_STANDARD;
i2c0_priv.config.master_mode = true;
i2c0_priv.config.slave_addr = 0;
LISA_LOGI(LOG_TAG, "I2C0 initialized successfully");
return LISA_DEVICE_OK;
}
#endif
#if CONFIG_LISA_I2C1
static int arcs_i2c1_init(void)
{
/* 清空私有数据 */
memset(&i2c1_priv, 0, sizeof(lisa_i2c_priv_t));
/* 获取 HAL I2C1 句柄 */
i2c1_priv.hal_handler = I2C1();
if (!i2c1_priv.hal_handler) {
LISA_LOGE(LOG_TAG, "Failed to get I2C1 handler");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 创建互斥锁 */
i2c1_priv.mutex = lisa_mutex_create();
if (!i2c1_priv.mutex) {
LISA_LOGE(LOG_TAG, "Failed to create mutex");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 初始化 HAL I2C */
if (I2C_Initialize(i2c1_priv.hal_handler, i2c1_event_callback, &i2c1_priv) != 0) {
LISA_LOGE(LOG_TAG, "Failed to initialize I2C1");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 使能电源 */
if (I2C_PowerControl(i2c1_priv.hal_handler, CSK_POWER_FULL) != 0) {
LISA_LOGE(LOG_TAG, "Failed to power on I2C1");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 设置传输模式为中断模式 */
if (I2C_Control(i2c1_priv.hal_handler, CSK_I2C_TRANSMIT_MODE, 0) != 0) {
LISA_LOGE(LOG_TAG, "Failed to set I2C1 transmit mode");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 设置默认总线速度为标准模式 */
if (I2C_Control(i2c1_priv.hal_handler, CSK_I2C_BUS_SPEED, CSK_I2C_BUS_SPEED_STANDARD) != 0) {
LISA_LOGE(LOG_TAG, "Failed to set I2C1 bus speed");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 清除总线 */
I2C_Control(i2c1_priv.hal_handler, CSK_I2C_BUS_CLEAR, 0);
/* 配置 I2C1 引脚复用 */
lisa_i2c1_pinmux();
/* 设置默认配置 */
i2c1_priv.config.speed = LISA_I2C_SPEED_STANDARD;
i2c1_priv.config.master_mode = true;
i2c1_priv.config.slave_addr = 0;
LISA_LOGI(LOG_TAG, "I2C1 initialized successfully");
return LISA_DEVICE_OK;
}
#endif
/* ===== 设备注册 ===== */
#if CONFIG_LISA_I2C0
LISA_DEVICE_REGISTER(i2c0, /* 设备名称 */
&arcs_i2c_api, /* API指针 */
&i2c0_priv, /* 私有数据指针 */
NULL, /* 用户数据 */
arcs_i2c0_init, /* 初始化函数 */
LISA_DEVICE_PRIORITY_NORMAL); /* 优先级 */
#endif
#if CONFIG_LISA_I2C1
LISA_DEVICE_REGISTER(i2c1, /* 设备名称 */
&arcs_i2c_api, /* API指针 */
&i2c1_priv, /* 私有数据指针 */
NULL, /* 用户数据 */
arcs_i2c1_init, /* 初始化函数 */
LISA_DEVICE_PRIORITY_NORMAL); /* 优先级 */
#endif