概述
8150代码中当前能够使用的还只是sensor。我们来看下其中的定义以及对应的使用方法。如果支持I3C,那么SSC_TARGET_NO_I3C_SUPPORT该宏将不会被定义。
AMSS/slpi_proc/ssc/build/ssc.scons
#'SSC_TARGET_NO_I3C_SUPPORT' to be removed after core team gives support
env.Append(CPPDEFINES = ['SSC_TARGET_NO_I3C_SUPPORT'])
高通有给出一个地磁传感器的例子,我们就以Qcom给出的这个sensor入手
/AMSS/slpi_proc/ssc/sensors/ak0991x/src/sns_ak0991x_lite.h
#ifndef SSC_TARGET_NO_I3C_SUPPORT
#define AK0991X_ENABLE_I3C_SUPPORT // Enable support for I3C bus
#endif
在ak0991x_sensor_process_registry_event方法中会给I3C需要的信息进行赋值
#ifdef AK0991X_ENABLE_I3C_SUPPORT
state->com_port_info.i3c_address = state->registry_pf_cfg.i3c_address;
// if I3C mode, set up the com port to always use the I3C address
if(state->com_port_info.com_config.bus_type == SNS_BUS_I3C_SDR ||
state->com_port_info.com_config.bus_type == SNS_BUS_I3C_HDR_DDR )
{
state->com_port_info.com_config.slave_control = state->com_port_info.i3c_address;
}
#endif
到这里我们就需要去看下对应I3C的这个结构体成员。
首先state是ak0991x_state实例,com_port_info又是ak0991x_com_port_info实例,跟到这发现也仅仅是不存I3C的地址而已。
typedef struct ak0991x_com_port_info
{
sns_com_port_config com_config;
sns_sync_com_port_handle *port_handle;
uint8_t i2c_address;
uint8_t i3c_address;
bool in_i3c_mode;
} ak0991x_com_port_info;
再看下bus_type:
sns_bus_type bus_type; /* Bus type from sns_bus_type.*/
可以看出这里可以区分使用的是I2C还是I3C,而且还可以看到上面有SDR和HDR_DDR(double data rate)两种,MIPI联盟其实还定义了一种是HDR-TSL/TSP(ternary symbol)。
我们可以看下高通对于sensor通信端口类型的分类:
typedef enum
{
SNS_BUS_MIN = 0,
SNS_BUS_I2C = SNS_BUS_MIN,
SNS_BUS_SPI = 1,
SNS_BUS_UART = 2, // DEPRECATED. Please use the async_uart sensor
SNS_BUS_I3C_SDR = 3, // I3C Standard Data Rate
SNS_BUS_I3C_HDR_DDR = 4, // I3C Double Data Rate
SNS_BUS_I3C_I2C_LEGACY = 5, // for I2C devices on an I3C bus
SNS_BUS_MAX = SNS_BUS_I3C_I2C_LEGACY,
} sns_bus_type;
如上可以看到有关I3C的有SDR(12.5Mbps)、HDR_DDR(16.84Mbps)、I3C_I2C_LEGACY(I2C设备挂载到I3C总线上,快速模式下(FM)和快速模式+(FM+)速率下与I2C从设备进行通信,速率分别为400 Kbps或1 Mbps),如下是MIPI联盟定义的在不同模式下的数据传输速率:
回过头我们再来看state->com_port_info.com_config.slave_control = state->com_port_info.i3c_address;。看下slave_control的定义,可以看到如果是I3C设备,则为动态为从设备分配地址。
typedef struct
{
sns_bus_type bus_type; /* Bus type from sns_bus_type.*/
uint32_t slave_control; /* Slave Address for I2C.
Dynamic slave address I3C.
Chip Select for SPI.*/
sns_reg_addr_type reg_addr_type; /* Register address type for the slave.*/
uint32_t min_bus_speed_KHz; /* Minimum bus clock supported by slave in kHz.*/
uint32_t max_bus_speed_KHz; /* Maximum bus clock supported by slave in kHz.*/
uint8_t bus_instance; /* Platform bus instance number (BLSP number).*/
} sns_com_port_config;
我们再来看看该sensor中另一个与I3C相关的方法——ak0991x_enter_i3c_mode,该方法功能是如果配置的总线类型为i3c,则将AK0991X硬件从i2c切换到i3c模式,并配置i3c设置,如最大读取长度等。
/**
* Enters I3C mode.
*
* If the configured bus type is I3C, this will switch the AK0991x
* hardware from I2C to I3C mode and configure I3C settings such as
* maximum read length.
* This function will do nothing for non-I3C bus types.
*
* @param[i] instance Pointer to instance. May be NULL if called from sensor.
* @param[i] com_port pointer to com port structure
* @param[i] scp_service synch COM port service
*
* @return sns_rc
* SNS_RC_FAILED - COM port failure, or bus type is not I3C
* SNS_RC_SUCCESS
*/
sns_rc ak0991x_enter_i3c_mode(sns_sensor_instance *const instance,
ak0991x_com_port_info *com_port,
sns_sync_com_port_service * scp_service);
我们一点点来看下该方法具体做了什么配置工作:
sns_rc ak0991x_enter_i3c_mode(sns_sensor_instance *const instance,
ak0991x_com_port_info *com_port,
sns_sync_com_port_service * scp_service)
{
... ...
i2c_com_config.slave_control = com_port->i2c_address;
//注册串行通信端口,返回成功或者失败,但是此时不会打开端口
rv = scp_service->api->sns_scp_register_com_port(&i2c_com_config, &i2c_port_handle);
... ...
//此处为根据i2c_port_handle打开对应的通讯端口
rv = scp_service->api->sns_scp_open(i2c_port_handle);
... ...
/**----------为I3C设备动态分配地址----------**/
rv = scp_service->api->
sns_scp_issue_ccc( i2c_port_handle,
SNS_SYNC_COM_PORT_CCC_SETDASA,
buffer, 1, &xfer_bytes );
//sns_scp_issue_ccc该方法是主设备向从设备发送一个CCCs命令(MIPI联盟规范中定义为“通用命令代码”)
//重点关注的是第二个参数,此参数即可知道是什么类型的命令。详细的命令解释请参照结构体:sns_sync_com_port_ccc[注1]
//此处的意思是将动态地址分配给具有已知静态地址的从设备,写两个byte
//需要注意的是使用SNS_SYNC_COM_PORT_CCC_SETDASA命令,必须在使用从设备的I2C静态地址打开的端口上发送,且如果地址更改,端口必须关闭并重新打开
... ...
/**----------设置最大读取的大小----------**/
... ...
rv = scp_service->api->
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_SETMRL,//在单个命令中设置最大读取长度,写两个或三个byte
buffer, 3, &xfer_bytes );
... ...
/**----------禁用中断----------**/
buffer[0] = 0x1;
... ...
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_DISEC,//禁用从设备驱动的中断,1代表关闭中断,写一个byte
buffer, 1, &xfer_bytes );
... ...
/**----------获取debug信息----------**/
... ...
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_GETMWL,//获得最大写入长度,以字节为单位的最大长度(最高位优先),读两个byte
buffer, 2, &xfer_bytes );
... ...
rv = scp_service->api->
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_SETMWL,//设置最大写入长度,以字节为单位的最大长度(最高位优先),读两个byte
buffer, 2, &xfer_bytes );
... ...
rv = scp_service->api->
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_GETMRL,//获取最大读取长度,最大读取长度:2字节(最高位优先)
buffer, 2, &xfer_bytes );
... ...
rv = scp_service->api->
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_GETPID,//获取从设备的临时ID(PID),读取6个byte
buffer, 6, &xfer_bytes );
... ...
rv = scp_service->api->
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_GETBCR,//获取设备的总线特性,读一个byte
buffer, 1, &xfer_bytes );
... ...
rv = scp_service->api->
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_GETDCR,//获取设备的设备特性,读一个byte
buffer, 1, &xfer_bytes );
... ...
rv = scp_service->api->
sns_scp_issue_ccc( com_port->port_handle,
SNS_SYNC_COM_PORT_CCC_GETSTATUS,//获取设备的运行状态,读两个byte,
buffer, 2, &xfer_bytes );
我们再来看下在api中是如何定义的AMSS/slpi_proc/core/api/buses/i2c_api.h
#define I3C_FLAG_USE_7E 0x00010000 /**< Must be set to send out a 0x7E for I3C. */
#define I3C_FLAG_IBI_CTRL 0x00020000 /**< When set IBI is either ACKed or NACKed based on a preconfigured table in HW. */
#define I3C_FLAG_CONTINUE 0x00040000 /**< Set internally for DAA transfers. */
//I2C与I3C速率对比
#define I2C_STANDARD_MODE_FREQ_KHZ 100 /**< I2C stadard speed 100 KHz. */
#define I2C_FAST_MODE_FREQ_KHZ 400 /**< I2C fast mode speed 400 KHz. */
#define I2C_FAST_MODE_PLUS_FREQ_KHZ 1000 /**< I2C fast mode plus speed 1 MHz. */
#define I3C_I2C_ENUMERATE_MODE_FREQ_KHZ 370 /**< I3C enumeration speed 370 KHz. */
#define I3C_SDR_DATA_RATE_12500_KHZ 12500 /**< I3C SDR speed 12.5 MHz. */
//如下可以看到总线类型已经支持I3C
typedef enum
{
I2C = 0, /**< I2C protocol. */
SMBUS = 1, /**< SMBUS protocol. */
I3C = 2 /**< I3C protocol. */
} bus_protocol;
//I3C支持的通信方式
typedef enum
{
//传统I2C设备之间的通讯
I2C_LEGACY = 0, /**< Communicate with an I2C device on I3C bus. */
//与支持SDR的从设备进行通讯
I3C_SDR = 1, /**< Communicate with a slave supporting I3C Standard Data Rate. */
//与支持HDR_DDR的从设备进行通讯
I3C_HDR_DDR = 2, /**< Communicate with a slave supporting I3C HDR Dual Data Rate. */
//通用命令代码传输
I3C_CCC = 3, /**< Common Command Code transfers. */
//从支持它的从属节点读取IBI有效负载
I3C_IBI_READ = 4 /**< Read IBI payload from slaves that support it. */
} i3c_mode;
typedef enum i3c_ccc
{
B_ENEC = (0x0000 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Enable slave event driven interrupts. */
B_DISEC = (0x0001 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Disable slave event driven interrupts. */
B_ENTAS0 = (0x0002 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Set activity state 0 (normal operation). */
B_ENTAS1 = (0x0003 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Set activity state 1. */
B_ENTAS2 = (0x0004 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Set activity state 2. */
B_ENTAS3 = (0x0005 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Set activity state 3. */
B_RSTDAA = (0x0006 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Forget current dynamic dddress and wait for new assignment. */
B_ENTDAA = (0x0007 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Entering master initiation of slave dynamic address assignment. */
B_DEFSLVS = (0x0008 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Master defines dynamic address, dcr type, and static address (or 0) per slave. */
B_SETMWL = (0x0009 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Maximum write length in a single command. */
B_SETMRL = (0x000a | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Maximum read length in a single command. */
B_ENTTM = (0x000b | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Master has entered test mode. */
B_ENTHDR0 = (0x0020 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Master has entered hdr - ddr mode. */
B_ENTHDR1 = (0x0021 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Master has entered hdr - tsp mode. */
B_ENTHDR2 = (0x0022 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Master has entered hdr - tsl mode. */
B_ENTHDR3 = (0x0023 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Master has entered hdr - future. */
B_ENTHDR4 = (0x0024 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Master has entered hdr - future. */
B_ENTHDR5 = (0x0025 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Master has entered hdr - future. */
B_ENTHDR6 = (0x0026 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Master has entered hdr - future. */
B_ENTHDR7 = (0x0027 | (I3C_CCC_NO_PAYLOAD << 8)), /**< Master has entered hdr - future. */
B_SETXTIME = (0x0028 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Framework for exchanging event timing information. */
D_ENEC = (0x0080 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Enable slave event driven interrupts. */
D_DISEC = (0x0081 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Disable slave event driven interrupts. */
D_ENTAS0 = (0x0082 | (I3C_CCC_SLAVE_PAYLOAD << 8)), /**< Set activity state 0 (normal operation). */
D_ENTAS1 = (0x0083 | (I3C_CCC_SLAVE_PAYLOAD << 8)), /**< Set activity state 1. */
D_ENTAS2 = (0x0084 | (I3C_CCC_SLAVE_PAYLOAD << 8)), /**< Set activity state 2. */
D_ENTAS3 = (0x0085 | (I3C_CCC_SLAVE_PAYLOAD << 8)), /**< Set activity state 3. */
D_RSTDAA = (0x0086 | (I3C_CCC_SLAVE_PAYLOAD << 8)), /**< Forget current dynamic address and wait for new assignment. */
D_SETDASA = (0x0087 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Master assigns a dynamic address to a slave with a known static address. */
D_SETNEWDA = (0x0088 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Master assigns a new dynamic address to any i3c slave. */
D_SETMWL = (0x0089 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Maximum write length in a single command. */
D_SETMRL = (0x008a | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Maximum read length in a single command. */
D_GETMWL = (0x008b | (I3C_CCC_READ_PAYLOAD << 8)), /**< Get slave's maximum possible write length. */
D_GETMRL = (0x008c | (I3C_CCC_READ_PAYLOAD << 8)), /**< Get a slave's maximum possible read length. */
D_GETPID = (0x008d | (I3C_CCC_READ_PAYLOAD << 8)), /**< Get a slave's provisional id. */
D_GETBCR = (0x008e | (I3C_CCC_READ_PAYLOAD << 8)), /**< Get a device's bus characteristic register (bcr). */
D_GETDCR = (0x008f | (I3C_CCC_READ_PAYLOAD << 8)), /**< Get a device's device characteristics register (dcr). */
D_GETSTATUS = (0x0090 | (I3C_CCC_READ_PAYLOAD << 8)), /**< Get a device's operating status. */
D_GETACCMST = (0x0091 | (I3C_CCC_READ_PAYLOAD << 8)), /**< Current master is requesting and confirming a bus mastership from a secondary master. */
D_SETBRGTGT = (0x0093 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Master tells bridge (to/from i2c, spi, uart, etc.) what endpoints it is talking to (by dynamic address and type/id). */
D_GETMXDS = (0x0094 | (I3C_CCC_READ_PAYLOAD << 8)), /**< Master asks slave for its sdr mode max. read and write data speeds (& optionally max. read turnaround time). */
D_GETHDRCAP = (0x0095 | (I3C_CCC_READ_PAYLOAD << 8)), /**< Master asks slave what hdr modes it supports. */
D_SETXTIME = (0x0098 | (I3C_CCC_WRITE_PAYLOAD << 8)), /**< Framework for exchanging event timing information. */
D_GETXTIME = (0x0099 | (I3C_CCC_READ_PAYLOAD << 8)), /**< Framework for exchanging event timing information. */
} i3c_ccc;
//I3C设备信息
typedef struct i3c_device
{
uint8 dynamic_slave_addr; /**< Dynamic slave address assigned to the slave. */
uint8 bcr; /**< BCR value obtained during broadcast ENTDAA CCC. */
uint8 dcr; /**< DCR value obtained during broadcast ENTDAA CCC. */
uint8 pid[6]; /**< PID value obtained during broadcast ENTDAA CCC. */
boolean allocated; /**< Flag to denote that the address is in use. */
void *ibi_handle; /**< Handle to the i3c core that processes the IBI event. */
void (*ibi_cb)(uint32 status,
uint32 xfered,
void *ctxt); /**< Client callback called to notify IBI event. */
void *ibi_ctxt; /**< Client context called to notify IBI event. */
uint8 *ibi_rbuffer; /**< IBI mandatory bytes. */
uint32 ibi_rlen; /**< Number of IBI mandatory bytes. */
} i3c_device;
注1:
AMSS/slpi_proc/ssc/inc/utils/sns_com_port_types.h
typedef enum sns_sync_com_port_ccc
{
SNS_SYNC_COM_PORT_CCC_ENEC,
/**< Enable slave event driven interrupts. Write. One byte.
* Set to 1 to enable interrupts. See spec for other values */
SNS_SYNC_COM_PORT_CCC_DISEC,
/**< Disable slave event driven interrupts. Write. One byte.
* Set to 1 to disable interrupts. See spec for other values */
SNS_SYNC_COM_PORT_CCC_SETDASA,
/**< Assigns a dynamic address to a slave with a known static address. Write. One byte.
* The dynamic address (left shifted one bit to allow for r/w bit).
* NOTE: this must be sent on a port opened with the slave's I2C static address.
* The port must be closed & re-opened if the address changes */
SNS_SYNC_COM_PORT_CCC_RSTDAA,
/**< Resets dynamic address assignment. Zero bytes.
* NOTE: This must be sent on a port opened with the slave's current I3C dynamic
* address.
* The port must be closed & re-opened to communicate with the slave if the
* I2C static address is not the same as the previously assigned I3C address */
SNS_SYNC_COM_PORT_CCC_SETMWL,
/**< Set maximum write length. Write. Two bytes.
* Max length in bytes (MSB first) */
SNS_SYNC_COM_PORT_CCC_SETMRL,
/**< Set maximum read length in a single command. Write. Two or Three bytes.
* Max read length: 2 bytes (MSB first). Max IBI read length (if IBI data supported) */
SNS_SYNC_COM_PORT_CCC_GETMWL,
/**< Get maximum write length. Read. Two bytes.
* Max length in bytes (MSB first) */
SNS_SYNC_COM_PORT_CCC_GETMRL,
/**< Get maximum read length. Read. Two or Three bytes
* Max read length: 2 bytes (MSB first). Max IBI read length (if IBI data supported) */
SNS_SYNC_COM_PORT_CCC_GETPID,
/**< Get a slave's provisional id (PID). Read. Six bytes */
SNS_SYNC_COM_PORT_CCC_GETBCR,
/**< Get a device's bus characteristic (BCR). Read. One byte */
SNS_SYNC_COM_PORT_CCC_GETDCR,
/**< Get a device's device characteristics (DCR). Read. One byte */
SNS_SYNC_COM_PORT_CCC_GETSTATUS,
/**< Get a device's operating status. Read. Two bytes
* MSB first: vendor reserved byte
* LSB second: see SNS_CCC_STATUS_* masks */
SNS_SYNC_COM_PORT_CCC_GETMXDS,
/**< Get sdr mode max read and write data speeds (& optionally max read turnaround time).
* Read. Two or Five bytes
* byte[0]: Max write clock
* byte[1]: Max Read clock | clock to data turnaround time:
* optional bytes[2..4]: Max read turnaround time in uSec, LSB first.
* */
SNS_SYNC_COM_PORT_CCC_SETXTIME,
/**< Framework for exchanging event timing information. Write. Various number of bytes
* byte[0]: SETXTIME defining byte
* optional bytes: See SNS_CCC_SETXTIME_* for number of optional bytes */
SNS_SYNC_COM_PORT_CCC_GETXTIME,
/**< Framework for exchanging event timing information. Read. Four bytes.
* byte[0]: Supported modes. See SNS_CCC_GETXTIME_SUPPORT_*
* byte[1]: State. See SNS_CCC_GETXTIME_STATE_
* byte[2]: Internal oscilator frequency, in increments of 0.5 MHz (0-->~32kHz)
* byte[3]: Inaccuracy byte. Max variation of slave's oscillator, in 0.1% increments */
} sns_sync_com_port_ccc;
最后
以上就是殷勤豌豆为你收集整理的I3C——代码相关(杂记)的全部内容,希望文章能够帮你解决I3C——代码相关(杂记)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复