📄 i2cloopback.c
字号:
/*H*****************************************************************************
*
* $Archive:: $
* $Revision:: $
* $Date:: $
* $Author:: $
*
* DESCRIPTION: R2808 Post
*
* GLOBALS
*
* PUBLIC FUNCTIONS:
*
* PRIVATE FUNCTIONS:
*
* USAGE/LIMITATIONS:
*
* NOTES:
*
* (C) Copyright 2004 by Spectrum Digital Incorporated
* All rights reserved
*
*H*****************************************************************************/
#include "DSP280x_Device.h"
#include "r2808cfg.h"
//--------------------------------------------
// Defines
//--------------------------------------------
// Error Messages
#define ERROR 0xFFFF
#define ARB_LOST_ERROR 0x0001
#define NACK_ERROR 0x0002
#define BUS_BUSY_ERROR 0x1000
#define STP_NOT_READY_ERROR 0x5555
#define NO_FLAGS 0xAAAA
#define SUCCESS 0x0000
// Clear Status Flags
#define CLR_AL_BIT 0x0001
#define CLR_NACK_BIT 0x0002
#define CLR_ARDY_BIT 0x0004
#define CLR_RRDY_BIT 0x0008
#define CLR_SCD_BIT 0x0020
// Interrupt Source Messages
#define I2C_NO_ISRC 0x0000
#define I2C_ARB_ISRC 0x0001
#define I2C_NACK_ISRC 0x0002
#define I2C_ARDY_ISRC 0x0003
#define I2C_RX_ISRC 0x0004
#define I2C_TX_ISRC 0x0005
#define I2C_SCD_ISRC 0x0006
#define I2C_AAS_ISRC 0x0007
// I2CMSG structure defines
#define NO_STOP 0
#define YES_STOP 1
#define RECEIVE 0
#define TRANSMIT 1
#define MAX_BUFFER_SIZE 16
// I2C Slave State defines
#define I2C_NOTSLAVE 0
#define I2C_ADDR_AS_SLAVE 1
#define I2C_ST_MSG_READY 2
// I2C Slave Receiver messages defines
#define I2C_SND_MSG1 1
#define I2C_SND_MSG2 2
// I2C State defines
#define I2C_IDLE 0
#define I2C_SLAVE_RECEIVER 1
#define I2C_SLAVE_TRANSMITTER 2
#define I2C_MASTER_RECEIVER 3
#define I2C_MASTER_TRANSMITTER 4
// I2C Message Commands for I2CMSG struct
#define I2C_MSGSTAT_INACTIVE 0x0000
#define I2C_MSGSTAT_SEND_WITHSTOP 0x0010
#define I2C_MSGSTAT_WRITE_BUSY 0x0011
#define I2C_MSGSTAT_SEND_NOSTOP 0x0020
#define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021
#define I2C_MSGSTAT_RESTART 0x0022
#define I2C_MSGSTAT_READ_BUSY 0x0023
// Generic defines
#define TRUE 1
#define FALSE 0
#define YES 1
#define NO 0
#define I2C_DUMMY_BYTE 0
//--------------------------------------------
// Structures
//--------------------------------------------
// I2C Message Structure
struct I2CMSG {
Uint16 MsgStatus; // Word stating what state msg is in:
// I2C_MSGCMD_INACTIVE = do not send msg
// I2C_MSGCMD_BUSY = msg start has been sent,
// awaiting stop
// I2C_MSGCMD_SEND_WITHSTOP = command to send
// master trans msg complete with a stop bit
// I2C_MSGCMD_SEND_NOSTOP = command to send
// master trans msg without the stop bit
// I2C_MSGCMD_RESTART = command to send a restart
// as a master receiver with a stop bit
Uint16 SlaveAddress; // I2C address of slave msg is intended for
Uint16 NumOfBytes; // Num of valid bytes in (or to be put in MsgBuffer)
Uint16 MemoryHighAddr; // EEPROM address of data associated with msg (high byte)
Uint16 MemoryLowAddr; // EEPROM address of data associated with msg (low byte)
Uint16 MsgBuffer[MAX_BUFFER_SIZE]; // Array holding msg data - max that
// MAX_BUFFER_SIZE can be is 16 due to
// the FIFO's
};
unsigned Error_I2C = 0;
struct I2CMSG I2cMsgOut1={ I2C_MSGSTAT_SEND_WITHSTOP, 0x50, 16, 0x00,0x30,
0xA5, 0x86, 0X11, 0X22, 0X33, 0X44, 0X55, 0X66,
0X77, 0X88, 0X99, 0XAA, 0XBB, 0XCC, 0XDD, 0XEE};
struct I2CMSG I2cMsgIn1={I2C_MSGSTAT_SEND_NOSTOP, 0x50, 16, 0x00,0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
struct I2CMSG *CurrentMsgPtr; // Used in interrupts
// -----------------------------------------------------------
// PIE Group 8 - MUXed into CPU INT8
// -----------------------------------------------------------
// INT8.1
interrupt void ICINTR1A_ISR(void) // I2C-A
{
Uint16 IntSource, i;
// Read interrupt source
IntSource = I2caRegs.I2CISRC.all;
// Interrupt source = stop condition detected
if(IntSource == I2C_SCD_ISRC)
{
// If completed message was writing data, reset msg to inactive state
if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
{
CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
}
else
{
// If a message receives a NACK during the address setup portion of the
// EEPROM read, the code further below included in the register access ready
// interrupt source code will generate a stop condition. After the stop
// condition is received (here), set the message status to try again.
// User may want to limit the number of retries before generating an error.
if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
}
// If completed message was reading EEPROM data, reset msg to inactive state
// and read data from FIFO.
else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
{
CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
for(i=0; i<16; i++)
{
CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
}
}
}
} // end of stop condition detected
// Interrupt source = Register Access Ready
// This interrupt is used to determine when the EEPROM address setup portion of the
// read data communication is complete. Since no stop bit is commanded, this flag
// tells us when the message has been sent instead of the SCD flag. If a NACK is
// received, clear the NACK bit and command a stop. Otherwise, move on to the read
// data portion of the communication.
else if(IntSource == I2C_ARDY_ISRC)
{
if(I2caRegs.I2CSTR.bit.NACK == 1)
{
I2caRegs.I2CMDR.bit.STP = 1;
I2caRegs.I2CSTR.all = CLR_NACK_BIT;
}
else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
}
} // end of register access ready
// Enable future I2C interrupts
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}
Uint16 I2CA_WriteData(struct I2CMSG *msg)
{
Uint16 i;
// Wait until the STP bit is cleared from any previous master communication.
// Clearing of this bit by the module is delayed until after the SCD bit is
// set. If this bit is not checked prior to initiating a new message, the
// I2C could get confused.
if (I2caRegs.I2CMDR.bit.STP == 1)
{
return STP_NOT_READY_ERROR;
}
// Setup slave address
I2caRegs.I2CSAR = msg->SlaveAddress;
// Check if bus busy
if (I2caRegs.I2CSTR.bit.BB == 1)
{
return BUS_BUSY_ERROR;
}
// Setup number of bytes to send
I2caRegs.I2CCNT = msg->NumOfBytes;
// Setup data to send
I2caRegs.I2CDXR = msg->MemoryHighAddr;
I2caRegs.I2CDXR = msg->MemoryLowAddr;
for (i=0; i<msg->NumOfBytes-2; i++)
{
I2caRegs.I2CDXR = *(msg->MsgBuffer+i);
}
// Send start as master transmitter
I2caRegs.I2CMDR.all = 0x6E20;
return SUCCESS;
}
Uint16 I2CA_ReadData(struct I2CMSG *msg)
{
// Wait until the STP bit is cleared from any previous master communication.
// Clearing of this bit by the module is delayed until after the SCD bit is
// set. If this bit is not checked prior to initiating a new message, the
// I2C could get confused.
if (I2caRegs.I2CMDR.bit.STP == 1)
{
return STP_NOT_READY_ERROR;
}
I2caRegs.I2CSAR = msg->SlaveAddress;
if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
{
// Check if bus busy
if (I2caRegs.I2CSTR.bit.BB == 1)
{
return BUS_BUSY_ERROR;
}
I2caRegs.I2CCNT = 2;
I2caRegs.I2CDXR = msg->MemoryHighAddr;
I2caRegs.I2CDXR = msg->MemoryLowAddr;
I2caRegs.I2CMDR.all = 0x2620; // Send data to setup EEPROM address
}
else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)
{
I2caRegs.I2CCNT = msg->NumOfBytes; // Setup how many bytes to expect
I2caRegs.I2CMDR.all = 0x2C20; // Send restart as master receiver
}
return SUCCESS;
}
void I2CA_Init(void)
{
DINT;
EALLOW;
PieCtrlRegs.PIECTRL.bit.ENPIE = 0;
PieVectTable.ICINTR1A = ICINTR1A_ISR;
// Enable CPU INT8 which is connected to I2C
IFR &= ~M_INT8;
IER |= M_INT8;
// Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1
PieCtrlRegs.PIEIER8.bit.INTx1 = 1;
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;
// Enables PIE to drive a pulse into the CPU
PieCtrlRegs.PIEACK.all = 0xFFFF;
EDIS;
EINT;
// Initialize I2C
I2caRegs.I2CSAR = 0x0050; // Slave address - EEPROM control code
I2caRegs.I2CPSC.all = 9; // Prescaler - need 7-12 Mhz on module clk
I2caRegs.I2CCLKL = 10; // NOTE: must be non zero
I2caRegs.I2CCLKH = 5; // NOTE: must be non zero
I2caRegs.I2CIER.all = 0x24; // Enable SCD & ARDY interrupts
I2caRegs.I2CMDR.all = 0x0020; // Take I2C out of reset
// Stop I2C when suspended
I2caRegs.I2CFFTX.all = 0x6000; // Enable FIFO mode and TXFIFO
I2caRegs.I2CFFRX.all = 0x2040; // Enable RXFIFO, clear RXFFINT,
}
int I2C_LoopBack(void)
{
Uint16 Error;
long Timeout;
int i;
CurrentMsgPtr = &I2cMsgOut1;
for(i=0; i<I2cMsgIn1.NumOfBytes; i++ )
{
I2cMsgIn1.MsgBuffer[i] = 0;
}
I2cMsgOut1.MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP;
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
I2CA_Init();
// Application loop
Timeout = 1000000;
do
{
//////////////////////////////////
// Write data to EEPROM section //
//////////////////////////////////
// Check the outgoing message to see if it should be sent.
// In this example it is initialized to send with a stop bit.
if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)
{
Error = I2CA_WriteData(&I2cMsgOut1);
// If communication is correctly initiated, set msg status to busy
// and update CurrentMsgPtr for the interrupt service routine.
// Otherwise, do nothing and try again next loop. Once message is
// initiated, the I2C interrupts will handle the rest. Search for
// ICINTR1A_ISR in the i2c_eeprom_isr.c file.
if (Error == SUCCESS)
{
CurrentMsgPtr = &I2cMsgOut1;
I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
break;
}
} // end of write section
}while( Timeout-- );
if( Timeout <= 0 ) {
Error_I2C = (unsigned)-1;
return( -1 );
}
///////////////////////////////////
// Read data from EEPROM section //
//////////////////////////////////
Timeout = 1000000;
do
{
// Check outgoing message status. Bypass read section if status is
// not inactive.
if (I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)
{
// Check incoming message status.
if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
{
// EEPROM address setup portion
while(I2CA_ReadData(&I2cMsgIn1) != SUCCESS)
{
// Maybe setup an attempt counter to break an infinite while
// loop. The EEPROM will send back a NACK while it is performing
// a write operation. Even though the write communique is
// complete at this point, the EEPROM could still be busy
// programming the data. Therefore, multiple attempts are
// necessary.
}
// Update current message pointer and message status
CurrentMsgPtr = &I2cMsgIn1;
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;
}
// Once message has progressed past setting up the internal address
// of the EEPROM, send a restart to read the data bytes from the
// EEPROM. Complete the communique with a stop bit. MsgStatus is
// updated in the interrupt service routine.
else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)
{
// Read data portion
while(I2CA_ReadData(&I2cMsgIn1) != SUCCESS)
{
// Maybe setup an attempt counter to break an infinite while
// loop.
}
// Update current message pointer and message status
CurrentMsgPtr = &I2cMsgIn1;
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY;
}
else if( I2cMsgIn1.MsgStatus == I2C_MSGSTAT_INACTIVE )
{
break;
}
} // end of read section
}while( Timeout-- );
if( Timeout <= (long)0 ) {
Error_I2C = (unsigned)-1;
return( -1 );
}
for(i=0; i<I2cMsgIn1.NumOfBytes-2; i++ )
{
if( I2cMsgIn1.MsgBuffer[i] != I2cMsgOut1.MsgBuffer[i] )
{
Error_I2C = (unsigned)-1;
}
}
return((int)Error_I2C);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -