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 + -
显示快捷键?