⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.c

📁 三星ARM9系列CPU S3C2440A的WINCE 5.0下的BSP
💻 C
📖 第 1 页 / 共 2 页
字号:

    // write slave address
    rIICDS   = (UCHAR)SlaveAddr;
    rIICSTAT = MTX_START;

    // IST writes the slave word address & data
    if (WAIT_OBJECT_0 != SyncIst(pI2C, TX_TIMEOUT)) {
        
        DEBUGMSG(ZONE_WRITE|ZONE_ERR,(TEXT("TX_TIMEOUT.1\r\n")));

        goto _done;
    }

// LJY, 20040724, commented out
#if 0
    // get ACK
    while(1)
    {
        pI2C->State  = WRITE_ACK;
        pI2C->Status = INVALID_IICSTAT;
        
        rIICDS   = (UCHAR)SlaveAddr;
        rIICSTAT = MTX_START;
        rIICCON  = RESUME_ACK;

        while ( pI2C->Status == INVALID_IICSTAT ) {
            if (WAIT_OBJECT_0 != SyncIst(pI2C, TX_TIMEOUT)) {
                DEBUGMSG(ZONE_WRITE|ZONE_ERR,(TEXT("TX_TIMEOUT.2\r\n")));
                break;
            }
        }

        // done when ACK received
        if ( !(pI2C->Status & 0x1))
            break; 
    }
#endif

_done:
    rIICSTAT = MTX_STOP;     
    rIICCON  = RESUME_ACK;  

    rIICSTAT  = M_IDLE;    // disable Rx/Tx    
    pI2C->State = IDLE;
    pI2C->Data  = NULL;
    pI2C->DataCount = INVALID_DATA_COUNT;

    dwErr = pI2C->LastError;

    LeaveCriticalSection(&pI2C->RegCS);
    
    DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("-I2C_Write: %u \r\n"), dwErr));
    
    return dwErr;
}


static DWORD
I2C_IST(
    LPVOID Context
    )
{
    PI2C_CONTEXT pI2C = (PI2C_CONTEXT)Context;
    DWORD i2cSt;
    BOOL bDone = FALSE;
#ifdef DEBUG
    DWORD r = 0;
#endif

    if ( !pI2C ) {
        TEST_TRAP;
        return ERROR_INVALID_PARAMETER;
    }

    //DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("+I2C_IST[%u, %u, %d] \r\n"), pI2C->Mode, pI2C->State, pI2C->DataCount));

    do  {
        
        if (pI2C->Mode == INTERRUPT) {
            
            DWORD we;

            bDone = FALSE;
            
            we = WaitForSingleObject(pI2C->ISTEvent, INFINITE);
            
            //DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST[%u, %d] \r\n"), pI2C->State, pI2C->DataCount));

            // clear the interrupt here because we re-arm another below
            InterruptDone(gIntrIIC);

            //
            // Ensure correct state initiated by Read/Write
            //
            DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST[%u, %d] \r\n"), 
                pI2C->State, pI2C->DataCount));

            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) {
                        DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("I2C_IST: INVALID_DATA_COUNT\r\n")));
                        continue;
                    }
                    break;
            }
        }

//        EnterCriticalSection(&pI2C->RegCS);
        
        i2cSt = rIICSTAT; 

        if (i2cSt & 0x8) {
            DEBUGMSG(ZONE_ERR,(TEXT("I2C_IST[%u, %d]: bus arbitration failed \r\n"), 
                pI2C->State, pI2C->DataCount));
           RETAILMSG(1, (TEXT("I2C_IST[%u, %d]: bus arbitration failed \r\n"), 
                pI2C->State, pI2C->DataCount));
        } 

        if (i2cSt & 0x4) {
            DEBUGMSG(ZONE_ERR,(TEXT("I2C_IST[%u, %d]: slave address matches IICADD \r\n"), 
                pI2C->State, pI2C->DataCount));
            RETAILMSG(1, (TEXT("I2C_IST[%u, %d]: slave address matches IICADD \r\n"), 
                pI2C->State, pI2C->DataCount));
        }
        
        if (i2cSt & 0x2) {
            DEBUGMSG(ZONE_ERR,(TEXT("I2C_IST[%u, %d]: received slave address 0x0 \r\n"), 
                pI2C->State, pI2C->DataCount));
            RETAILMSG(1, (TEXT("I2C_IST[%u, %d]: received slave address 0x0 \r\n"), 
                pI2C->State, pI2C->DataCount));
        }

        if (i2cSt & 0x1) {
            DEBUGMSG(ZONE_READ|ZONE_WRITE,(TEXT("I2C_IST[%u, %d]: ACK NOT received \r\n"), 
                pI2C->State, pI2C->DataCount));
            RETAILMSG(1, (TEXT("I2C_IST[%u, %d]: ACK NOT received \r\n"), 
                pI2C->State, pI2C->DataCount));
        }

        __try {
                
            switch(pI2C->State)
            {
                case IDLE:
                case SUSPEND:
                    continue;
                    break;
                    
                case RESUME:
                    DEBUGMSG(ZONE_WRN, (TEXT("I2C_IST: RESUME \r\n")));
                  RETAILMSG(1,  (TEXT("I2C_IST: RESUME \r\n")));
                    InitRegs(pI2C);
                    pI2C->LastError = ERROR_OPERATION_ABORTED;
                    SetEvent(pI2C->DoneEvent);
                    break;

                case SET_READ_ADDR:
                    if ( (pI2C->DataCount--) == 0 )
                    {
                        DEBUGMSG(ZONE_READ|ZONE_TRACE, (TEXT("A2[%d] \r\n"), 
                            pI2C->DataCount ));
                        RETAILMSG(1, (TEXT("A2[%d] \r\n"), 
           		 pI2C->DataCount ));
                        bDone = TRUE;
                        break;
                    }

                    DEBUGMSG(ZONE_READ|ZONE_TRACE, (TEXT("A1[%d]: 0x%X \r\n"), 
                        pI2C->DataCount, pI2C->WordAddr));
                    RETAILMSG(1, (TEXT("A1[%d]: 0x%X \r\n"), 
                        pI2C->DataCount, pI2C->WordAddr));                    
                    // 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_ACK;
                        pI2C->Flags.WordAddr = FALSE;
                    }
                    break;


                case READ_DATA:                    
                    ASSERT(pI2C->Data);
                    if ( (pI2C->DataCount--) == 0 )
                    {
                        bDone = TRUE;
                    
                        *pI2C->Data = (UCHAR)rIICDS;
#ifdef DEBUG                        
                        r = *pI2C->Data;
                        
                        //RETAILMSG(1,(TEXT("R3_1:0x%X, pI2C->Data(0x%X) \r\n"), r, pI2C->Data));
                        //RETAILMSG(1,(_T("pI2C->Data(0x%X)\r\n"), pI2C->Data));
#endif
                        pI2C->Data++;
                        
                        rIICSTAT = MRX_STOP;    
                        rIICCON  = RESUME_ACK;  // resume operation.
                        
                        //RETAILMSG(1,(_T("pI2C->Data(0x%X)\r\n"), pI2C->Data));
                        //RETAILMSG(1,(TEXT("R3_2:0x%X, pI2C->Data(0x%X) \r\n"), r, pI2C->Data));
                        //DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("R3:0x%X \r\n"), r));
                                    
                        //The pending bit will not be set after issuing stop condition.
                        break;    
                    }

                    // Drop the returned Slave WordAddr?
                    if ( pI2C->Flags.DropRxAddr )
                    {
                        pI2C->RxRetAddr = (UCHAR)rIICDS;
                        pI2C->Flags.DropRxAddr = FALSE;
                        DEBUGMSG(ZONE_READ|ZONE_TRACE,(TEXT("Drop: 0x%X \r\n"), 
                            pI2C->RxRetAddr));
                        
                    } else {
                        *pI2C->Data = (UCHAR)rIICDS;
#ifdef DEBUG
                        r = *pI2C->Data;
#endif
                        pI2C->Data++;
                    }

					//RETAILMSG(1,(TEXT("R3_3:0x%X, pI2C->Data(0x%X) \r\n"), r, 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_ACK;       // 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 )
                    {
                        DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("W3[%d] \r\n"), pI2C->DataCount));
                        //RETAILMSG(1,(TEXT("W3[%d] \r\n"), pI2C->DataCount));
                        
                        bDone = TRUE;

                        rIICSTAT = MTX_STOP;    
                        rIICCON  = RESUME_ACK;  // resume operation.

                        //The pending bit will not be set after issuing stop condition.
                        break;    
                    }
                    
                    if (pI2C->Flags.WordAddr) {
                        rIICDS = pI2C->WordAddr;
                        DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("W1[%d]: 0x%X \r\n"), 
                            pI2C->DataCount, pI2C->WordAddr));
                        pI2C->Flags.WordAddr = FALSE;
                    } else {
                        DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("W2[%d]: 0x%X \r\n"), 
                            pI2C->DataCount, *pI2C->Data));
                        
                        rIICDS = (UCHAR)*pI2C->Data;
                        pI2C->Data++;
                    }

                    rIICCON = RESUME_ACK;   // resume operation.
                    break;


                case WRITE_ACK:
                    DEBUGMSG(ZONE_WRITE|ZONE_TRACE,(TEXT("WRITE_ACK \r\n") ));
                    //RETAILMSG(1,(TEXT("WRITE_ACK \r\n") ));
                    pI2C->Status = i2cSt;
                    bDone = TRUE;
                    break;


                case IO_COMPLETE:
                    DEBUGMSG(ZONE_IST, (TEXT("IO_COMPLETE \r\n")));
                    bDone = TRUE;
                    break;


                case IO_ABANDONED:
                    DEBUGMSG(ZONE_ERR|ZONE_WRN,(TEXT("IO_ABANDONED \r\n") ));
                    bDone = TRUE;
                    break;


                default:
                    DEBUGMSG(ZONE_ERR,(TEXT("!!! I2C_IST ERROR: Invalid State: %u !!!\r\n"), 
                        pI2C->State));
                    bDone = TRUE;
                    break;    
            }
        
        } _except(EXCEPTION_EXECUTE_HANDLER) {
            
            rIICSTAT = (pI2C->State == READ_DATA) ? MRX_STOP : MTX_STOP;
            rIICCON  = RESUME_ACK;

            pI2C->DataCount = INVALID_DATA_COUNT;
        
            pI2C->LastError = GetExceptionCode();
            RETAILMSG(1,(TEXT("!!! I2C_IST EXCEPTION: 0x%X !!!\r\n"), pI2C->LastError ));
        }

            
        if (bDone) {
            DEBUGMSG(ZONE_IST, (TEXT("SetEvent DONE\r\n")));
            SetEvent(pI2C->DoneEvent);
        }            

//        LeaveCriticalSection(&pI2C->RegCS);
                    
    } while (pI2C->Mode == INTERRUPT);


    //DEBUGMSG(ZONE_IST|ZONE_TRACE,(TEXT("-I2C_IST[%u] \r\n"), pI2C->Mode));

    return ERROR_SUCCESS;
}


BOOL
HW_PowerUp(
    PI2C_CONTEXT pI2C
   )
{
    pI2C->State = RESUME;
    SetInterruptEvent(gIntrIIC);
    return TRUE;
}


BOOL
HW_PowerDown(
    PI2C_CONTEXT pI2C
   )
{
    // set idle
    rIICSTAT = M_IDLE;
    
    // turn off our clock
    pI2C->pCLKPWRReg->CLKCON &= ~I2C_POWER_ON;
    
    pI2C->State = SUSPEND;
    return TRUE;
}


BOOL
HW_PowerCapabilities(
    PI2C_CONTEXT pI2C,
    PPOWER_CAPABILITIES ppc
    )
{
    memset(ppc, 0, sizeof(*ppc));

    //
    // SPECIAL CASE: support D0 only. 
    // If we power off outside of system state Suspend then the PCF50606 
    // will no longer work, which means the whole system could be forced off 
    // by an internal PCF transition. The Battery driver would not work either.
    //
    // If we knew we did not have to support the PCF50606,
    // or didn't know what I2C Client drivers we could have,
    // then we should support D0 and D4. In this case you would use
    // RegisterPowerRelationship and serve as the Bus driver (parent/proxy)
    // to forward power transitions to all the I2C Client drivers.
    //
    ppc->DeviceDx = 0x1;    // D0

    // no wake
    // no inrush

    // Report our power consumption in uAmps rather than mWatts. 
    ppc->Flags = POWER_CAP_PREFIX_MICRO | POWER_CAP_UNIT_AMPS;
    ppc->Power[D0] = 600;   // 0.6 mA or 600 uA @ 200 MHz

    // no latency issues

    return TRUE;
}


BOOL
HW_PowerSet(
    PI2C_CONTEXT pI2C,
    PCEDEVICE_POWER_STATE pDx   // IN, OUT
   )
{   
    CEDEVICE_POWER_STATE NewDx = *pDx;

    if ( VALID_DX(NewDx) ) 
    {
        // We only support D0, so do nothing.
        // Just return current state.
        pI2C->Dx = *pDx = D0;

        DEBUGMSG(ZONE_POWER, (TEXT("I2C: IOCTL_POWER_SET: D%u => D%u \r\n"),
            NewDx, pI2C->Dx));

        return TRUE;
    }

    return FALSE;
}


BOOL
HW_PowerGet(
    PI2C_CONTEXT pI2C,
    PCEDEVICE_POWER_STATE pDx
   )
{   
    // return our Current Dx value
    *pDx = pI2C->Dx;

    DEBUGMSG(ZONE_POWER, (TEXT("I2C: IOCTL_POWER_GET: D%u \r\n"), pI2C->Dx));

    return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -