i2cloader.c

来自「This driver supports both master mode, s」· C语言 代码 · 共 1,758 行 · 第 1/5 页

C
1,758
字号
            }
            break;

        case STI2C_MASTER_ADDRESSING_READ:
            if ( (RxData & ACKNOWLEDGE_BIT) != 0 )
            {
                /* Invalid ack so raise an error and terminate transfer */
                CtrlBlk->State             = STI2C_IDLE;
                CtrlBlk->HandlerCondition  = STI2C_ERROR_ADDRESS_ACK;
                I2C_TRACE_ERR_INC;
                I2C_TRACE(CtrlBlk,0xF70,RxData);
                semaphore_signal( &CtrlBlk->IOSemaphore );
            }
            else   /* good ack, so set state to Reading  */
            {
	        /* NB: A master-receiver will not ACK the last byte
		   of a transfer in order to stop the slave-transmitter */
                CtrlBlk->State = STI2C_MASTER_READING;
                if ( CtrlBlk->BufferCnt+1 == CtrlBlk->BufferLen )
                {
                    /* Only 1 byte to read, so don't ack it */
#ifndef STI2C_SW_START_STOP
                    I2cRegPtr [SSC_I2C] = SSC_I2C_ENABLE;
#endif /* STI2C_SW_START_STOP */
                    I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
                    I2C_TRACE(CtrlBlk,0x70,RxData);
                }
                else   /* More than 1 byte to read, so generate acks */
                {
#ifdef STI2C_SW_START_STOP
                    I2cRegPtr [SSC_TX_BUFFER] = 0x1FE;  /* generate s/w ack */
#else
                    I2cRegPtr[SSC_I2C] = ( SSC_I2C_ENABLE | 
					   SSC_I2C_GENERATE_ACKS );
                    I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
#endif /* STI2C_SW_START_STOP */
                    I2C_TRACE(CtrlBlk,0x71,RxData);
                }
            }
            break;

        case STI2C_MASTER_WRITING:
            if (RxData & ACKNOWLEDGE_BIT)
            {
                /* Invalid ack so raise an error and terminate transfer */
                CtrlBlk->State             = STI2C_IDLE;
                CtrlBlk->HandlerCondition  = STI2C_ERROR_WRITE_ACK;
                I2C_TRACE_ERR_INC;
                I2C_TRACE(CtrlBlk,0xF60,RxData);
                semaphore_signal( &CtrlBlk->IOSemaphore );
            }
            else   /* good ack */
            {
                /* If the last byte has been transmitted then tidy up,
                   else buffer the next byte */
                if ( CtrlBlk->BufferCnt >= CtrlBlk->BufferLen )
                {
                    CtrlBlk->State = STI2C_IDLE;
                    I2C_TRACE(CtrlBlk,0x60,RxData);
                    semaphore_signal( &CtrlBlk->IOSemaphore );
                }
                else
                {
                    /* Put the next byte into the buffer byte and transmit */
                    TxData = ((*(CtrlBlk->Buffer++)) << 1) | ACKNOWLEDGE_BIT;
                    I2cRegPtr [SSC_TX_BUFFER] = (U16) TxData;
                    CtrlBlk->BufferCnt++;
                    I2C_TRACE(CtrlBlk,0x61,TxData);
                }
            }
            break;

        case STI2C_MASTER_READING:
            if (Status & SSC_STAT_RX_BUFFER_FULL)   /* Have we got a char? */
            {
                /* Buffer the received char & increment recvd char count */
                *(CtrlBlk->Buffer++) = RxData >> 1;
                CtrlBlk->BufferCnt++;

                /* If last byte has been read, clean up & don't acknowledge */
                if ( CtrlBlk->BufferCnt >= CtrlBlk->BufferLen )
                {
                    CtrlBlk->State = STI2C_IDLE;
                    I2C_TRACE(CtrlBlk,0x80,RxData);
                    semaphore_signal( &CtrlBlk->IOSemaphore );
                }

                else 
                {
                    /* Turn off acks after penultimate char has been read */
                    if ( CtrlBlk->BufferCnt+1 == CtrlBlk->BufferLen )
                    {
#ifndef STI2C_SW_START_STOP
                        /* Stop ack generation from i2c control block */
                        I2cRegPtr [SSC_I2C] = SSC_I2C_ENABLE;
#endif /* STI2C_SW_START_STOP */
                        I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
                        I2C_TRACE(CtrlBlk,0x81,RxData);
                    }
                    else
                    {
#ifdef STI2C_SW_START_STOP
                        I2cRegPtr [SSC_TX_BUFFER] = 0x1FE; /* generate s/w ack*/
#else
                        I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
#endif
                        I2C_TRACE(CtrlBlk,0x82,RxData);
                    }
                }
            }
            else
            {
                I2C_TRACE(CtrlBlk,0x43,RxData);
            }
            break;

#ifndef STI2C_MASTER_ONLY
        case STI2C_IDLE:
            /* If Addressed As Slave, we need to go into Slave Mode.
               If we have received a char, this is the address, so the bottom
               bit indicates whether transfer is read or write.
               (NB 'read' is as seen by other master, so we transmit... */
            if (Status & SSC_STAT_AAS)
            {
                /* Must now be ready for Stop */
                IntEnables = DEFAULT_ENABLES | SSC_STAT_STOP;
                if (Status & SSC_STAT_RX_BUFFER_FULL)
                {
                    if (RxData & 0x02)
                    {
                        /* Start of read - notify user, get 1st char to send
                           add 'ack' bit & put in tx buffer. */
                        CtrlBlk->State = STI2C_SLAVE_READ;
                        STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->TxNotifyId,
                                      NULL);
                        STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->TxByteId,
                                      (void *)&TxData);
                        TxData = ((TxData & 0xFF) << 1) | 1;
                        I2cRegPtr [SSC_TX_BUFFER] = (U16) TxData;
                        I2C_TRACE(CtrlBlk,0x02,TxData);
                    }
                    else
                    {   /* Start of write - notify user, turn on acks */
                        CtrlBlk->State = STI2C_SLAVE_WRITE;
                        STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->RxNotifyId,
                                      NULL);
                        I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
                        I2cRegPtr [SSC_I2C]       = SSC_I2C_ENABLE | 
                                                    SSC_I2C_GENERATE_ACKS;
                        I2C_TRACE(CtrlBlk,0x03,RxData);
                    }
                }
                else  /* Nothing received - switch to slave mode, but we
                         don't yet know if read or write. */
                {
                    CtrlBlk->State = STI2C_SLAVE_ADDRESSED;
                    I2C_TRACE(CtrlBlk,0x04,0);
                }
            }
            else
            {
                if (Status & SSC_STAT_STRETCH)
                    I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
                I2C_TRACE(CtrlBlk,0x05,RxData);
            }
            break;

        case STI2C_SLAVE_WAIT_FOR_STOP:
            /* We are waiting for a Stop at the end of a slave read.
               When we get it, go back to idle & notify user. */
            if (Status & SSC_STAT_STOP)
            {
                CtrlBlk->State = STI2C_IDLE;
                IntEnables = DEFAULT_ENABLES;
                I2C_TRACE(CtrlBlk,0x10,0);
                STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->TxCompleteId, NULL);
            }
            else
            {
                I2C_TRACE(CtrlBlk,0x11,0);
            }
            break;

        case STI2C_SLAVE_ADDRESSED:
            /* We have entered slave state, but don't yet know if R or W.
               This state is probably only needed because of a h/w bug, which
               results in AAS being set before 'Rx buffer full'. */
            if (Status & SSC_STAT_RX_BUFFER_FULL)
            {
                if (RxData & 0x02)
                {
                    /* Start of slave read - notify user, get 1st char to send
                       add 'ack' bit & put in tx buffer. */
                    CtrlBlk->State = STI2C_SLAVE_READ;
                    STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->TxNotifyId,
                                      NULL);
                    STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->TxByteId,
                                  (void *)&TxData);
                    TxData = ((TxData &0xFF) << 1) | 1;
                    I2cRegPtr [SSC_TX_BUFFER] = (U16) TxData;
                    I2C_TRACE(CtrlBlk,0x20,TxData);
                }
                else
                {   /* Start of slave write - notify user */
                    CtrlBlk->State = STI2C_SLAVE_WRITE;
                    I2C_TRACE(CtrlBlk,0x21,0);
                    STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->RxNotifyId,
                                  NULL);
                    I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
                    I2cRegPtr [SSC_I2C]       = SSC_I2C_ENABLE | 
                                                SSC_I2C_GENERATE_ACKS;
                }
            }
            else
            {
                I2C_TRACE(CtrlBlk,0x22,RxData);
            }

            if (Status & SSC_STAT_STOP)
            {
                CtrlBlk->State = STI2C_IDLE;
                IntEnables = DEFAULT_ENABLES;
                I2C_TRACE(CtrlBlk,0x23,0);
            }
            break;

        case STI2C_SLAVE_READ:
            if (Status & SSC_STAT_RX_BUFFER_FULL)
            {
                /* Look at ack bit to see if this is the last byte */
                if (RxData & ACKNOWLEDGE_BIT)
                {
                    CtrlBlk->State = STI2C_SLAVE_WAIT_FOR_STOP;
                    I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
                    I2C_TRACE(CtrlBlk,0x30,RxData);
                }
                else   /* not last byte, so get next byte & send it */
                {
                    STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->TxByteId,
                                  (void *)&TxData);
                    TxData = ((TxData & 0xFF) << 1) | 1;
                    I2cRegPtr [SSC_TX_BUFFER] = (U16) TxData;
                    I2C_TRACE(CtrlBlk,0x31,TxData);
                }
            }
            else
            {
                I2C_TRACE(CtrlBlk,0x32,RxData);
            }

            if (Status & SSC_STAT_STOP)
            {
                CtrlBlk->State = STI2C_IDLE;
                IntEnables = DEFAULT_ENABLES;
                I2C_TRACE(CtrlBlk,0x33,0);
                STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->TxCompleteId, NULL);
            }
            break;

        case STI2C_SLAVE_WRITE:
            if (Status & SSC_STAT_RX_BUFFER_FULL)
            {
                /* Read a byte, so notify the user */
                I2C_TRACE(CtrlBlk,0x40,RxData);
                RxData >>= 1;
                STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->RxByteId, &RxData);
                I2cRegPtr [SSC_TX_BUFFER] = 0x1FF;
            }
            else
            {
                I2C_TRACE(CtrlBlk,0x41,RxData);
            }

            if (Status & SSC_STAT_STOP)
            {
                CtrlBlk->State = STI2C_IDLE;
                IntEnables = DEFAULT_ENABLES;
                I2C_TRACE(CtrlBlk,0x42,0);
                STEVT_Notify (CtrlBlk->EVTHandle, CtrlBlk->RxCompleteId, NULL);
            }
            break;
#endif /* STI2C_MASTER_ONLY */

        default:
            I2C_TRACE_ERR_INC;
            I2C_TRACE(CtrlBlk,0xF05,RxData);
            break;
        }              /* end of switch */
    }

    /* Wake up any tasks waiting for a Stop interrupt (see BusAccess) */
    if ((Status & SSC_STAT_STOP) && (CtrlBlk->WaitingForStop))
    {
        CtrlBlk->StopOccurred = TRUE;
        IntEnables &= ~SSC_STAT_STOP;
        I2C_TRACE(CtrlBlk,0x06,0);
        semaphore_signal ( &CtrlBlk->IOSemaphore );
    }

    /* Reenable interrupts */
    I2cRegPtr [SSC_INT_ENABLE] = CtrlBlk->InterruptMask = IntEnables;
    I2C_TRACE(CtrlBlk,0x000a,0);
}

/******************************************************************************
Name        : AllocateI2cOpenBlock
Description : Allocates a new i2c open block, sticks it on the end of the
              linked list, and returnd a pointer to it. If this process fails 
              a null pointer is returned.
Parameters  : None
******************************************************************************/

static i2c_open_block_s *AllocateI2cOpenBlock(ST_Partition_t *partition)
{
    i2c_open_block_s    *OpenPtr =NULL;
    i2c_open_block_s    *Next    =NULL;
    i2c_open_block_s    *Current =NULL;

    /* Allocate a new block */
    OpenPtr = memory_allocate( partition, sizeof(i2c_open_block_s) ); 

    /* Check allocation worked */ 
    if ( OpenPtr != NULL )
    {

        /* Find the end of the current list */
        if ( g_OpenHead == NULL )
        {
            /* There is no current list so set it up */
            g_OpenHead = OpenPtr;
        }
      
        else
        {
            Next = g_OpenHead;
            do
            {
                Current = Next;
                Next = (i2c_open_block_s*) (Current->Next);           
            }
            while ( Next != NULL );

            /* Stick this block to the end of the list */
            Current->Next = (void*)OpenPtr;
        }

        /* Increment the block counter */
        g_OpenBlkCnt++;

        /* Set block values to defaults */
        OpenPtr->Handle         = 0;
        OpenPtr->I2cAddress     = 0;

⌨️ 快捷键说明

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