Windows CE6.0 S3C2440A IIC驱动编码解析

简介: S3C2440A RISC微处理器可以支持多主设备IIC总线串行接口。专用串行总线(SDA)和串行时钟线(SCL)承载总线主机设备和连接IIC总线的外围设备之间的信息。

S3C2440A RISC微处理器可以支持多主设备IIC总线串行接口。专用串行总线(SDA)和串行时钟线(SCL)承载总线主机设备和连接IIC总线的外围设备之间的信息。SDASCL线都是双向的。本章采用TQ2440开发板进行分析,我们先来看看其硬件电路图;

从这里可以看的出 TQ2440 采用的是AT24C02A IIC器件,其中I2CSCLI2CSDA分别表示时钟线和数据线。接下来看看IIC寄存器的相关结构体;

typedef struct _I2C_CONTEXT {

    DWORD   Sig;    // Signature

    volatile S3C2440A_IICBUS_REG *pI2CReg; // I2C Registers

    volatile S3C2440A_IOPORT_REG *pIOPReg;   // GPIO Ports

    volatile S3C2440A_CLKPWR_REG *pCLKPWRReg; // Clock / Power

    CRITICAL_SECTION RegCS; // Register CS

    I2C_MODE    Mode; // State

    I2C_STATE   State;

    int         Status;

    FLAGS       Flags;

    // Data

    PUCHAR      Data;           // pointer to R/W data buffer

    int         DataCount;      // nBytes to R/W to/from data buffer

    UCHAR       WordAddr;       // slave word address

    UCHAR       RxRetAddr;      // returned slave address on Rx

    DWORD       SlaveAddress;   // Our I2C Slave Address

    HANDLE      DoneEvent;      // I/O Done Event

    HANDLE      ISTEvent;       // IST Event

    HANDLE      IST;            // IST Thread

    DWORD       OpenCount;

    DWORD       LastError;

    HANDLE      hProc;

    CEDEVICE_POWER_STATE    Dx;

} I2C_CONTEXT, *PI2C_CONTEXT;

在这个结构体中pI2CRegpIOPRegpCLKPWRReg都扮演着非常重要的角色,如下来看看如何实现这上个寄存器初始化工作,后面将介绍IIC驱动的几个关键部分代码;

bMapReturn = VirtualCopy( pVMem,(LPVOID)(S3C2440A_BASE_REG_PA_IICBUS>>8),        PAGE_SIZE,PAGE_READWRITE | PAGE_NOCACHE |PAGE_PHYSICAL);

       pI2C->pI2CReg = (volatile S3C2440A_IICBUS_REG*)(pVMem);

        pVMem += PAGE_SIZE;

VirtualCopy(pVMem,(LPVOID)(S3C2440A_BASE_REG_PA_IOPORT>>8),

     PAGE_SIZE,PAGE_READWRITE | PAGE_NOCACHE |PAGE_PHYSICAL);

pI2C->pIOPReg = (volatile S3C2440A_IOPORT_REG*)(pVMem);

pVMem += PAGE_SIZE;

VirtualCopy(pVMem,(LPVOID)(S3C2440A_BASE_REG_PA_CLOCK_POWER>>8),

PAGE_SIZE,PAGE_READWRITE | PAGE_NOCACHE |PAGE_PHYSICAL);

pI2C->pCLKPWRReg = (volatile S3C2440A_CLKPWR_REG*)(pVMem);

中断模式处理

   Windows CE当中中断处理的常用的几个函数有KernelIoControlInterruptInitializeInterruptDisableInterruptDone函数,如下所示是其处理过程。

Irq = IRQ_IIC;

KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(UINT32), &gIntrIIC, sizeof(UINT32), NULL))      

// initialize the interrupt

InterruptInitialize(gIntrIIC, pI2C->ISTEvent, NULL, 0) ) ;

InterruptDone(gIntrIIC);

// create the IST

pI2C->IST = CreateThread(NULL, 0, I2C_IST, (LPVOID)pI2C, 0, NULL));

CeSetThreadPriority(pI2C->IST, I2C_THREAD_PRIORITY));

IST函数

    PI2C_CONTEXT pI2C = (PI2C_CONTEXT)Context;

    DWORD i2cSt;

    BOOL bDone = FALSE;

    do  {

        if (pI2C->Mode == INTERRUPT) {

            DWORD we;

            bDone = FALSE;

            we = WaitForSingleObject(pI2C->ISTEvent, INFINITE);

            // clear the interrupt here because we re-arm another below

            InterruptDone(gIntrIIC);

            switch(pI2C->State)

            {

                case OFF:

                    DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST: ExitThread /r/n")));

                    ExitThread(ERROR_SUCCESS);

                    break;

                case IDLE:

                    DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST: IDLE /r/n")));

                    continue;

                    break;

                default:

                    if (pI2C->State != WRITE_ACK &&

                        pI2C->State != RESUME &&

                        pI2C->DataCount == INVALID_DATA_COUNT) {

                        continue;

                    }

                    break;

            }

        }

//        EnterCriticalSection(&pI2C->RegCS);

        __try {

            switch(pI2C->State)

            {

                case IDLE:

                case SUSPEND:

                    continue;

                    break;

                case RESUME:

                    InitRegs(pI2C);

                    pI2C->LastError = ERROR_OPERATION_ABORTED;

                    SetEvent(pI2C->DoneEvent);

                    break;

                case SET_READ_ADDR:

                    if ( (pI2C->DataCount--) == 0 )

                    {

                        bDone = TRUE;

                        break;

                    }      

                    // write word address

                    // For setup time of SDA before SCL rising edge, rIICDS must be written

                    // before clearing the interrupt pending bit.

                    if (pI2C->Flags.WordAddr) {

                        rIICDS = pI2C->WordAddr;

                        // clear interrupt pending bit (resume)

                        rIICCON = RESUME_IIC_CON;

                        pI2C->Flags.WordAddr = FALSE;

                    }

                    break;

                case READ_DATA:                   

                    ASSERT(pI2C->Data);

                    if ( (pI2C->DataCount--) == 0 )

                    {

                        bDone = TRUE;

                   

                        *pI2C->Data = (UCHAR)rIICDS;

                        pI2C->Data++;

                        rIICSTAT = MRX_STOP;   

                        rIICCON  = RESUME_IIC_CON;  // resume operation.                   

break;   

                    }

                    // Drop the returned Slave WordAddr?

                    if ( pI2C->Flags.DropRxAddr )

                    {

                        pI2C->RxRetAddr = (UCHAR)rIICDS;

                        pI2C->Flags.DropRxAddr = FALSE;                       

                    } else {

                        *pI2C->Data = (UCHAR)rIICDS;

                        pI2C->Data++;

                    }

                    // The last data is read with no ack.

                    if ( pI2C->DataCount == 0 ) {

                        rIICCON = RESUME_NO_ACK;    // resume operation with NOACK. 

                        DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("R1:0x%X /r/n"), r));

                    } else {

                        rIICCON = RESUME_IIC_CON;       // resume operation with ACK

                        DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("R2:0x%X /r/n"), r));

                    }

                    break;

                case WRITE_DATA:                       

                    ASSERT(pI2C->Data);

                    if ( (pI2C->DataCount--) == 0 )

                    {

                        bDone = TRUE;

                        rIICSTAT = MTX_STOP;   

                        rIICCON  = RESUME_IIC_CON;  // resume operation.

                        //The pending bit will not be set after issuing stop condition.

                        break;   

                    }

                        rIICDS = (UCHAR)*pI2C->Data;

                        pI2C->Data++;

                    }

                    rIICCON = RESUME_IIC_CON;   // resume operation.

                    break;

            }

       

        } _except(EXCEPTION_EXECUTE_HANDLER) {

            rIICSTAT = (pI2C->State == READ_DATA) ? MRX_STOP : MTX_STOP;

            rIICCON  = RESUME_IIC_CON;

 

            pI2C->DataCount = INVALID_DATA_COUNT;

            pI2C->LastError = GetExceptionCode();

        }

        if (bDone) {

            DEBUGMSG(ZONE_IST, (TEXT("SetEvent DONE/r/n")));

            SetEvent(pI2C->DoneEvent);

        }           

} while (pI2C->Mode == INTERRUPT);   

return ERROR_SUCCESS;

}

读取数据操作

驱动采用的是中断方式读取数据,其中数据指针保存在pI2C->pData当中,其中为了保证用户区缓冲和驱动内核区缓冲一致,还必须调用GetCallerProcess() MapPtrToProcess()GetCurrentProcessID()函数,这几个函数的具体用法可以查询MSDN帮助即可,这部分代码如下;

pI2C->State     = WRITE_DATA;

pI2C->DataCount = 1 + Count; // slave word address + data

pI2C->WordAddr  = WordAddr;

pI2C->Flags.WordAddr = TRUE;   

pI2C->Data = pData;

// write slave address

rIICDS   = (UCHAR)SlaveAddr;

rIICSTAT = MTX_START;

// IST writes the slave word address & data

if (WAIT_OBJECT_0 != SyncIst(pI2C, TX_TIMEOUT)) {

goto _done;

}

写数据操作

写操作和读操作方法很类似,是其反过程,代码很简单,这里就不多讲了,具体在S3C2440A BSP中可以看到。

这个IIC驱动是一个典型的Windows CE流接口驱动程序,是一个很好的学习范例,特写至此,希望对来客有写帮助。

目录
相关文章
|
1月前
|
消息中间件 Cloud Native Java
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
|
2月前
|
人工智能 安全 大数据
开源软件全景解析:驱动技术创新与行业革新的力量
开源软件全景解析:驱动技术创新与行业革新的力量
396 0
开源软件全景解析:驱动技术创新与行业革新的力量
|
3月前
|
存储 机器学习/深度学习 数据挖掘
数据仓库与数据湖:解析数据驱动的未来
在数字化时代,数据成为企业决策的核心资源。本文将深入探讨数据仓库和数据湖的概念、特点以及应用场景,分析其在实现数据驱动决策过程中的重要性和优势,并展望数据驱动的未来发展趋势。
53 5
|
3月前
|
Dubbo Java 应用服务中间件
微服务框架(十七)Dubbo协议及编码过程源码解析
  此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。   本文为Dubbo协议、线程模型、和其基于Netty的NIO异步通讯机制及源码
|
3月前
|
数据安全/隐私保护
URL编码解析方式-特殊字符加密和解密
URL编码解析方式-特殊字符加密和解密
29 0
|
4月前
|
监控 安全 API
5.9 Windows驱动开发:内核InlineHook挂钩技术
在上一章`《内核LDE64引擎计算汇编长度》`中,`LyShark`教大家如何通过`LDE64`引擎实现计算反汇编指令长度,本章将在此基础之上实现内联函数挂钩,内核中的`InlineHook`函数挂钩其实与应用层一致,都是使用`劫持执行流`并跳转到我们自己的函数上来做处理,唯一的不同的是内核`Hook`只针对`内核API`函数,但由于其身处在`最底层`所以一旦被挂钩其整个应用层都将会受到影响,这就直接决定了在内核层挂钩的效果是应用层无法比拟的,对于安全从业者来说学会使用内核挂钩也是很重要。
40 1
5.9 Windows驱动开发:内核InlineHook挂钩技术
|
4月前
|
监控 API C++
8.4 Windows驱动开发:文件微过滤驱动入门
MiniFilter 微过滤驱动是相对于`SFilter`传统过滤驱动而言的,传统文件过滤驱动相对来说较为复杂,且接口不清晰并不符合快速开发的需求,为了解决复杂的开发问题,微过滤驱动就此诞生,微过滤驱动在编写时更简单,多数`IRP`操作都由过滤管理器`(FilterManager或Fltmgr)`所接管,因为有了兼容层,所以在开发中不需要考虑底层`IRP`如何派发,更无需要考虑兼容性问题,用户只需要编写对应的回调函数处理请求即可,这极大的提高了文件过滤驱动的开发效率。
41 0
|
4月前
|
监控 Windows
7.4 Windows驱动开发:内核运用LoadImage屏蔽驱动
在笔者上一篇文章`《内核监视LoadImage映像回调》`中`LyShark`简单介绍了如何通过`PsSetLoadImageNotifyRoutine`函数注册回调来`监视驱动`模块的加载,注意我这里用的是`监视`而不是`监控`之所以是监视而不是监控那是因为`PsSetLoadImageNotifyRoutine`无法实现参数控制,而如果我们想要控制特定驱动的加载则需要自己做一些事情来实现,如下`LyShark`将解密如何实现屏蔽特定驱动的加载。
32 0
7.4 Windows驱动开发:内核运用LoadImage屏蔽驱动
|
19天前
|
监控 安全 API
7.3 Windows驱动开发:内核监视LoadImage映像回调
在笔者上一篇文章`《内核注册并监控对象回调》`介绍了如何运用`ObRegisterCallbacks`注册`进程与线程`回调,并通过该回调实现了`拦截`指定进行运行的效果,本章`LyShark`将带大家继续探索一个新的回调注册函数,`PsSetLoadImageNotifyRoutine`常用于注册`LoadImage`映像监视,当有模块被系统加载时则可以第一时间获取到加载模块信息,需要注意的是该回调函数内无法进行拦截,如需要拦截则需写入返回指令这部分内容将在下一章进行讲解,本章将主要实现对模块的监视功能。
37 0
7.3 Windows驱动开发:内核监视LoadImage映像回调
|
4月前
|
监控 安全 API
7.2 Windows驱动开发:内核注册并监控对象回调
在笔者上一篇文章`《内核枚举进程与线程ObCall回调》`简单介绍了如何枚举系统中已经存在的`进程与线程`回调,本章`LyShark`将通过对象回调实现对进程线程的`句柄`监控,在内核中提供了`ObRegisterCallbacks`回调,使用这个内核`回调`函数,可注册一个`对象`回调,不过目前该函数`只能`监控进程与线程句柄操作,通过监控进程或线程句柄,可实现保护指定进程线程不被终止的目的。
30 0
7.2 Windows驱动开发:内核注册并监控对象回调

推荐镜像

更多