赞
踩
本文主要描述QNX I2C Drvier的相关内容,并以SA8155处理器为例讲解。
I2C 是经常用到的一种总线协议,它只占用两个IO口资源,分别是SCL时钟信号线与SDA数据线,
两根线就能将连接与总线上的设备实现数据通信,由于它的简便的构造设计,于是成为一种较为
常用的通信方式。在QNX系统里,也提供了I2C驱动框架,整体框架与SPI类似。
I2C总线数据传输和应答
TODO
请查阅 https://blog.csdn.net/liaochaoyun/article/details/127317225
qnx_ap/AMSS/platform/hwdrivers/wired_peripherals/i2c
├── common
│ ├── aarch64
│ │ ├── a-le
│ │ ├── Makefile
│ │ └── so-le
│ ├── arm
│ │ ├── a-le-v7
│ │ ├── Makefile
│ │ └── so-le-v7
│ ├── common.mk
│ ├── Makefile
│ └── src
│ ├── I2cDeviceQup.c
│ └── I2cSys.c
├── inc
│ ├── ddii2c.h
│ ├── I2cDevice.h
│ ├── I2cError.h
│ ├── I2cTransferCfg.h
│ ├── I2cTransfer.h
│ └── I2cTypes.h
├── Makefile
└── platsvc_i2c
├── aarch64
│ ├── a-le
│ ├── Makefile
│ └── so-le
├── arm
│ ├── a-le-v7
│ ├── Makefile
│ └── so-le-v7
├── common.mk
├── inc
│ ├── I2cLog.h
│ ├── I2cPlatBam.h
│ ├── I2cPlatBsp.h
│ ├── I2cPlatSvc.h
│ └── I2cSys.h
├── Makefile
└── src
├── I2cPlatBsp.c
└── I2cPlatSvc.c
qnx_ap/AMSS/platform/resources/i2c_drv
├── aarch64
│ ├── a-le
│ │ └── Makefile
│ ├── Makefile
│ ├── so-le
│ │ └── Makefile
│ └── so-le-g
│ └── Makefile
├── arm
│ ├── a-le-v7
│ │ └── Makefile
│ ├── Makefile
│ └── so-le-v7
│ └── Makefile
├── common.mk
├── i2c_drv.c
├── Makefile
└── protected
└── i2c_devctls.h
qnx_ap/AMSS/platform/services/daemons/i2c_service
├── aarch64
│ ├── Makefile
│ └── o-le
│ └── Makefile
├── arm
│ ├── Makefile
│ └── o-le-v7
│ └── Makefile
├── common.mk
├── Makefile
├── src
│ └── i2cservice_main.c
└── usefile
qnx_ap/AMSS/platform/qal/clients/i2c_client
├── aarch64
│ ├── Makefile
│ ├── so-le
│ │ └── Makefile
│ └── so-le-g
│ └── Makefile
├── arm
│ ├── Makefile
│ └── so-le-v7
│ └── Makefile
├── common.mk
├── i2c_client.c
├── Makefile
└── public
└── amss
└── i2c_client.h
qnx_ap/AMSS/platform/qal/clients/i2c_client/public/amss/i2c_client.h
安装:qnx_ap/install/usr/include/amss/i2c_client.h
/*
* gain access to controller/bus driver
* Returns a handle that is passed to all other functions.
* Parameters:
* (in) devname Resource Manager connection(ex. "/dev/i2c1")
*
* Returns:
* >0 success
* -1 failure
*/
int i2c_open(void* devname);/*
* releases access to controller/bus driver
* Frees memory associated with "fd".
* Parameters:
* (in) fd Handle returned from init()
*
*/
void i2c_close(int fd);/*
* Specify the bus clock frequency
* If an invalid bus speed is requested, this function should return
* failure and leave the bus speed unchanged.
* Parameters:
* (in) addr The slave address
* (in) fmt The slave address format
* Returns:
* 0 success
* -1 failure
*/
int i2c_set_slave_addr(int fd, uint32_t addr, uint32_t fmt);/*
* Specify the bus clock frequency
* If an invalid bus speed is requested, this function should return
* failure and leave the bus speed unchanged.
* Parameters:
* (in) bus_clock_freq.
* Returns:
* 0 success
* -1 failure
*/
int i2c_set_bus_speed(int fd, uint32_t speed, uint32_t * ospeed);/*
* Lock this I2C controller/bus
* Parameters:
* (in) fd Handle returned from init()
* Returns:
* 0 success
* -1 failure
*/
int i2c_bus_lock(int fd);/*
* Unlock this I2C controller/bus
* Parameters:
* (in) fd Handle returned from init()
* Returns:
* 0 success
* -1 failure
*/
int i2c_bus_unlock(int fd);/*
* Write
* Parameters:
* (in) fd Handle returned from init()
* (in) buf Buffer of data to write
* (in) len Length in bytes of buf
* Returns:
* Number of bytes read
*/
int i2c_write(int fd, void *buf, uint32_t len);/*
* Read
* Parameters:
* (in) fd Handle returned from init()
* (in) buf Buffer for read data
* (in) len Length in bytes of buf
* Returns:
* >=0 Number of bytes read
* <0 Error # from errno.h
*/
int i2c_read(int fd, void *buf, uint32_t len);/*
* Combined Write Read
* Parameters:
* (in) fd Handle returned from init()
* (in) wbuf Buffer of data to send
* (in) wlen Length in bytes of wbuf
* (in) rbuff Buffer for received data
* (in) rlen Length in bytes of wbuf
* Returns:
* >=0 Number of bytes read
* <0 Error # from errno.h
*/
int i2c_combined_writeread(int fd, void * wbuff, uint32_t wlen, void* rbuff, uint32_t rlen );
/*
* Request info about the driver.
* Returns:
* 0 success
* -1 failure
*/
int i2c_driver_info(int fd, i2c_driver_info_t *info);
文件引用:#include <amss/i2c_client.h>
资源管理器接口的主要优点是:
- 它为应用程序开发人员提供了一个清晰、易于理解的思路。
- 它作为一个中介,在多个应用程序对一个或多个从设备之间进行访问,强制不同I2C接口之间的一致性。
- 对于专用的i2c总线应用程序,硬件访问库更有效;硬件接口定义了这个库的接口,有助于维护和代码可移植性。
通用架构如下如:
核心文件: qnx_ap/AMSS/platform/services/daemons/i2c_service/src/i2cservice_main.c
- int i2c_service_base_init(void)
- {
- //调用i2c_drv 资源管理接口实现i2c资源管理器初始化
- if (-1 == i2c_drv_init()) {
- logger_log(QCLOG_AMSS_QNP_SERVICES_I2C_SERVICE, QCLOG_AMSS_I2C_SERVICE_MINOR,
- QCLOG_ERROR, "i2c_drv_init Failed");
- }
-
- drop_abilities_i2c();
- /* init sysctrl */
- if(DAL_SUCCESS != sysctrl_init()) {
- logger_log(QCLOG_AMSS_QNP_SERVICES_I2C_SERVICE, QCLOG_AMSS_I2C_SERVICE_MINOR,
- QCLOG_ERROR, "sysctrl_init failed, errno: %s", strerror(errno));
- return DAL_ERROR;
- }
-
- return DAL_SUCCESS;
- }
-
- int main(int argc, char *argv[]) {
-
- int c;
- ...
-
- /* QNX IO operation privilege */
- if (ThreadCtl(_NTO_TCTL_IO, 0) == -1)
- {
- PROCESS_ERROR_CRITICAL("i2c_service: ThreadCtl Error");
- return EXIT_FAILURE;
- }
-
- //信号SIGTERM处理
- signal(SIGTERM,handle_sigterm);
-
- // Check if process is running /dev/i2c_service
- if( 0 < open(DEVICE_NAME, O_RDONLY))
- {
- PROCESS_ERROR_CRITICAL("Process [%s] already running.. exiting.", DEVICE_NAME);
- return EXIT_FAILURE;
- }
-
- // Run process in background,进程后台运行
- Resource_Daemonize();
-
- //资源管理器实现接口
- if(i2c_service_base_init() != DAL_SUCCESS)
- {
- PROCESS_ERROR_CRITICAL("i2c_service: i2c_service_core_init failed");
- return EXIT_FAILURE;
- }
- //启动I2C资源管理器服务
- /* the i2c resource manager main loop is going to run after here */
- if(DAL_SUCCESS != sysctrl_start(DEVICE_NAME)) {
- PROCESS_ERROR_CRITICAL("i2c_service: service_init failed");
- return EXIT_FAILURE;
- }
-
- // Code should never reach here
- PROCESS_ERROR_CRITICAL("Exiting i2c_service..");
- return EXIT_SUCCESS;
- }
查看系统进程:
# pidin | grep i2c
40982 1 bin/i2c_service 10r RECEIVE 8
40982 2 bin/i2c_service 15r RECEIVE 2
40982 3 bin/i2c_service 21r SEM fff808a056320f94
40982 4 bin/i2c_service 41r INTR
40982 5 bin/i2c_service 10r RECEIVE 3
40982 6 bin/i2c_service 41r INTR
40982 7 bin/i2c_service 10r RECEIVE 6
40982 8 bin/i2c_service 41r INTR
40982 9 bin/i2c_service 10r RECEIVE 11
核心文件:qnx_ap/AMSS/platform/resources/i2c_drv/i2c_drv.c
入口:
- /******************************************************************************/
- /***************************** startup and config ****************************/
- /******************************************************************************/
-
- int i2c_drv_init(void)
- {
- int i;
- int idx = 0;
- int ret = EOK;
- uint64_t chip_id = 0;
- const void *fdt_paddr = 0;
- pthread_t threadID;
- DALSYSPropertyVar PropVar;
-
- DALSYS_PROPERTY_HANDLE_DECLARE(hDALProps);
- DALSYS_InitMod(NULL);
- DALSYS_RegisterMod(&gDALModDriverInfoList);
-
- int policy;
- struct sched_param param;
- pthread_attr_t attr;
-
- if (waitfor_attach(QCORE_SERVICE, 5000))
- {
- I2C_SLOGE("Timed out waiting for %s to be ready", QCORE_SERVICE);
- return -1;
- }
-
- fdt_paddr = fdt_get_root();
- if (!fdt_paddr) {
- I2C_SLOGE("Failed to load device tree");
- return -1;
- }
- ret = fdt_foreach_subnode_byname((void*) fdt_paddr , "/chip_info",
- &get_chip_info, &chip_id);
- if (ret) {
- I2C_SLOGE("Failed to find dt chip_info");
- return -1;
- }
-
- I2C_SLOGI("Found chip id=%d", (int)chip_id);
-
- //线程配置
- pthread_attr_init(&attr);
- pthread_getschedparam(pthread_self(), &policy, ¶m);
- param.sched_priority = 100;
- pthread_attr_setschedparam(&attr, ¶m);
-
- devs = calloc(MAX_NUM_I2C_DEVS, sizeof(i2c_dev_t));
- if(devs == NULL)
- return -1;
-
- //创建设备
- // create devices , if specified via command line
- for(i = 0; i < MAX_NUM_I2C_DEVS; i++)
- {
- if(DALSYS_GetDALPropertyHandle(DeviceID[i], hDALProps) == DAL_SUCCESS)
- {
- //解析I2C配置,详情看QUP-I2C配置项
- if (DAL_SUCCESS != DALSYS_GetPropertyValue(hDALProps, "I2C_ENABLED", 0, &PropVar)
- || PropVar.Val.dwVal == 0)
- {
- continue;
- }
-
- if (DAL_SUCCESS != DALSYS_GetPropertyValue(hDALProps, "CLOCK_SE_NAME", 0, &PropVar)
- || PropVar.Val.pszVal == 0)
- {
- I2C_SLOGE("Failed to get property CLOCK_SE_NAME");
- return -1;
- }
-
- if (!strncmp(PropVar.Val.pszVal, "scc", 3)) {
- devs[idx].is_ssc = true;
- }
-
- //设备编号,名称等
- snprintf(devs[idx].devname, MAX_NUM_DEVNAME, "/dev/i2c%d", i+1);
- devs[idx].DALDeviceID = DeviceID[i];
- devs[idx].index = idx;
- devs[idx].bus_active = 0;
- devs[idx].timer_created = 0;
-
- //QUP I2C设备初始化
- if (DAL_SUCCESS != I2CDEV_Init(DeviceID[i], &devs[idx].ahI2cDev)) {
- I2C_SLOGE("Failed to initialize I2C %s", devs[idx].devname);
- continue;
- }
- devs[idx].initialized = 1;
-
- //通过线程创建设备,资源管理器及接口。
- ret = pthread_create(&threadID, NULL, (void *)&device_main,
- (void *)&devs[idx]);
- if (EOK == ret) {
- pthread_setname_np(threadID, devs[idx].devname);
- idx++;
- } else {
- I2C_SLOGE("Couldn't create RM thread for device-%d:"
- "name-%s:ret-%d",
- DeviceID[i], devs[idx].devname, ret);
- }
- }
- }
-
- if (ID_6155 == chip_id) {
- if ((ret = i2c_register_ssr())) {
- I2C_SLOGE("Failed to register for SSR ret=%x", ret);
- return -1;
- }
- }
-
- return 0;
- }
资源管理器创建通用步骤:
- 建立一个上下文切换句柄dpp = dispatch_create();这个东东主要用在mainloop中产生一个block特性,可以让我们等待接受消息;
- iofunc初始化。这一步是将自己实现的函数与POSIX层函数进行接口,解析从read、write、devctl等函数传来的消息进行解析,以实现底层与应用层函数之间的交互,通过io_funcs.read = io_read,io_funcs.write = io_write,进行函数重载;
- 注册设备名,使设备在命名空间中产生相应的名称,这一点是整个过程的关键了,形如 pathID = resmgr_attach (dpp, &rattr, "/dev/Null",_FTYPE_ANY, 0, &connect_funcs,&io_funcs, &ioattr),这样不仅注册了一个设备名,还让系统知道了我们实习的IO函数对应关系;
- 为之前创建的上下文句柄分配空间,例如ctp = dispatch_context_alloc (dpp);为了第六步使用;
- 通过不断循环等待dispatch_block()来调用MsgReceive()使Resource manger处于receive block状态,以接收上层发送来的消息,通过dispatch_handler (ctp)去调用我们自己定义的IO函数
资源管理器创建实现:
-
- int device_main(i2c_dev_t *dev)
- {
- resmgr_connect_funcs_t connect_funcs;
- resmgr_io_funcs_t io_funcs;
- resmgr_attr_t rattr;
- iofunc_funcs_t ocb_funcs = { _IOFUNC_NFUNCS, _ocb_calloc, _ocb_free,
- NULL, NULL, NULL };
- iofunc_mount_t mount = { 0, IOFUNC_PC_ACL, 0, 0, &ocb_funcs };
- I2CDEV_PowerStates power_state = 0;
- pthread_condattr_t cond_attr = { 0 };
-
- /* Set up contiguous buffers */
- dev->fd_mmap = posix_typed_mem_open("/ram/dma",
- O_RDWR,
- POSIX_TYPED_MEM_ALLOCATE_CONTIG);
- if (dev->fd_mmap == -1) {
- I2C_SLOGE("%s: posix_typed_mem_open(/ram/dma) failed(%d-%s)",
- __FUNCTION__, errno, strerror(errno));
- exit(1);
- }
-
- /* Configure clocks, gpios at init-time*/
- I2CDEV_GetPowerState(dev->ahI2cDev, &power_state);
- if (POWER_STATE_2 != power_state) {
- I2CDEV_SetPowerState(dev->ahI2cDev , POWER_STATE_2);
- dev->bus_active = 1;
- }
-
- pthread_mutex_init(&dev->mutex, NULL);
-
- pthread_condattr_init(&cond_attr);
- pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
- pthread_cond_init(&dev->cond, &cond_attr);
-
- //创建channel
- dev->chid = ChannelCreate(_NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK);
- if(dev->chid == -1) {
- I2C_SLOGE("ChannelCreate failed (%s)", strerror(errno));
- exit (1);
- }
-
- //第一步
- /*
- * allocate and initialize a dispatch structure for use by our
- * main loop
- */
- I2C_SLOGI("initializing %s\n",dev->devname);
- dev->dpp = dispatch_create_channel ( dev->chid, 0);
- if (dev->dpp == NULL)
- {
- I2C_SLOGE("couldn't dispatch_create: %s\n",strerror(errno));
- exit (1);
- }
-
-
- /*
- * set up the resource manager attributes structure, we'll
- * use this as a way of passing information to resmgr_attach().
- * For now, we just use defaults.
- */
-
- memset (&rattr, 0, sizeof (rattr)); /* using the defaults for rattr */
- rattr.nparts_max = 2; /* Max iov used by client is 2 */
- rattr.msg_max_size = MAX_NUM_I2C_WRITE;
-
- //第二步 iofunc初始化
- /*
- * intialize the connect functions and I/O functions tables to
- * their defaults by calling iofunc_func_init().
- *
- * connect_funcs, and io_funcs variables are already declared.
- *
- */
- iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_funcs,
- _RESMGR_IO_NFUNCS, &io_funcs);
-
- /* over-ride the connect_funcs handler for open with our io_open,
- * and over-ride the io_funcs handlers for read and write with our
- * io_read and io_write handlers
- */
- connect_funcs.open = io_open;
- io_funcs.devctl = io_devctl;
- io_funcs.acl = io_acl;
- io_funcs.close_ocb = io_close;
-
- /* initialize our device description structure
- */
-
- iofunc_attr_init (&dev->hdr, S_IFCHR | 0666, NULL, NULL);
-
- dev->hdr.mount = &mount; // so we can alloc an OCB per open
-
- iofunc_acl_init(&dev->hdr, iofunc_acl_posix_ctrl, 0);
-
- //第三步 注册设备
- /*
- * call resmgr_attach to register our prefix with the
- * process manager, and also to let it know about our connect
- * and I/O functions.
- *
- * On error, returns -1 and errno is set.
- */
- dev->pathID = resmgr_attach(dev->dpp,
- &rattr,
- dev->devname,
- _FTYPE_ANY,
- 0,
- &connect_funcs,
- &io_funcs,
- (RESMGR_HANDLE_T *)dev);
- if (dev->pathID == -1)
- {
- I2C_SLOGE(" couldn't attach pathname: %s\n", strerror (errno));
- exit (1);
- }
-
- //第四步 为dpp分配句柄空间
- dispatch_context_t *ctp;
- dev->ctp = dispatch_context_alloc(dev->dpp);
- if (dev->ctp == NULL)
- {
- dispatch_destroy(dev->dpp);
- return EXIT_FAILURE;
- }
-
- /* Notify bmetrics I2C device is ready */
- int fd = open("/dev/bmetrics", O_WRONLY);
- if (fd == -1) {
- I2C_SLOGE("Failed to open /dev/bmetrics with error:%d\n", errno);
- } else {
- char buf[BM_KPI_BUF_SIZE];
- snprintf(buf, BM_KPI_BUF_SIZE, "bootmarker DRIVER I2C Ready:%s\n",
- dev->devname);
- if (-1 == write(fd, buf, strlen(buf))) {
- I2C_SLOGE("Failed to write /dev/bmetrics with error:%d\n", errno);
- }
- close(fd);
- }
-
- /* register LPM pulses */
- if (EOK != i2c_register_pulse(dev)) {
- I2C_SLOGE("pulse registration for %s failed", dev->devname);
- exit(1);
- }
-
- /* register SSR pulses */
- dev->ssr_coid = ConnectAttach(ND_LOCAL_NODE, 0 /* pid */,
- dev->chid, _NTO_SIDE_CHANNEL, 0);
- if (-1 == dev->ssr_coid) {
- I2C_SLOGE("I2C_RM SSR ConnectAttach failed (%s)", strerror(errno));
- exit(1);
- }
-
- I2C_SLOGE("Initialized %s", dev->devname);
-
- //第五步 通过不断循环等待dispatch_block()来调用MsgReceive()使Resource manger处于receive block状态,以接收上层发送来的消息,通过dispatch_handler (ctp)去调用我们自己定义的IO函数
- while(1) {
- if ((ctp = dispatch_block(dev->ctp)) == NULL) {
- I2C_SLOGE("dispatch_block failed");
- exit(1);
- }
- dispatch_handler(dev->ctp);
- }
-
- return 0;
- }
TODO
拿devctl为例:
TODO
//伪代码如下
- #include <amss/i2c_client.h>
-
- #define DEV_NAME "/dev/i2c_1"
-
- int fd = -1;
- int slaveAddr = 0xAA;
-
- main()
- {
- unsigned char writedata[3];
- writedata[0] = 0x11;
- writedata[1] = 0x22;
- writedata[2] = 0x22;
-
- fd = i2c_open(DEV_NAME );
- i2c_bus_lock ( fd );
- i2c_set_slave_addr(fd, slaveAddr, 0))
- i2c_write(fd, writedata, sizeof(writedata));
- }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。