📄 f04x_smbus_eeprom.c
字号:
// Parameters : None
//
// This routine initializes the system clock to use the internal oscillator
// at 3.0625 MHz (24.5 / 8 MHz).
//
void SYSCLK_Init (void)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
SFRPAGE = CONFIG_PAGE; // Set SFR page
OSCICN = 0x80; // Set internal oscillator to run
// at 1/8 its maximum frequency
CLKSEL = 0x00; // Select the internal osc. as
// the SYSCLK source
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page
// detector
}
//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure the Crossbar and GPIO ports.
//
// P0.0 digital open-drain SMBus SDA
// P0.1 digital open-drain SMBus SCL
//
// P1.6 digital push-pull LED
//
// all other port pins unused
//
// Note: If the SMBus is moved, the SCL and SDA sbit declarations must also
// be adjusted.
//
void PORT_Init (void)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
SFRPAGE = CONFIG_PAGE;
P0MDOUT = 0x00; // All P0 pins open-drain output
P1MDOUT |= 0x40; // Make the LED (P1.6) a push-pull
// output
XBR0 = 0x01; // Enable SMBus on the crossbar
XBR2 = 0x40; // Enable crossbar and weak pull-ups
P0 = 0xFF;
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page detector
}
//-----------------------------------------------------------------------------
// SMBus_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// The SMBus peripheral is configured as follows:
// - SMBus enabled
// - Assert Acknowledge low (AA bit = 1b)
// - Free and SCL low timeout detection enabled
//
void SMBus_Init (void)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
SFRPAGE = SMB0_PAGE;
SMB0CN = 0x07; // Assert Acknowledge low (AA bit = 1b);
// Enable SMBus Free timeout detect;
// Enable SCL low timeout detect
// SMBus clock rate (derived approximation from the Tlow and Thigh equations
// in the SMB0CR register description)
SMB0CR = 257 - (SYSCLK / (2 * SMB_FREQUENCY));
SMB0ADR = MY_ADDR; // Set own slave address.
SMB0CN |= 0x40; // Enable SMBus;
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page detector
}
//-----------------------------------------------------------------------------
// Timer4_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Timer4 configured for use by the SMBus low timeout detect feature as
// follows:
// - Timer4 in auto-reload mode
// - SYSCLK/12 as Timer4 clock source
// - Timer4 reload registers loaded for a 25ms overflow period
// - Timer4 pre-loaded to overflow after 25ms
// - Timer4 enabled
//
void Timer4_Init (void)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
SFRPAGE = TMR4_PAGE;
TMR4CN = 0x00; // Timer4 external enable off;
// Timer4 in timer mode;
// Timer4 in auto-reload mode
TMR4CF = 0x00; // Timer4 uses SYSCLK/12
// Timer4 output not available
// Timer4 counts up
RCAP4 = -(SYSCLK/12/40); // Timer4 configured to overflow after
TMR4 = RCAP4; // ~25ms (for SMBus low timeout detect)
EIE2 |= 0x04; // Timer4 interrupt enable
TR4 = 1; // Start Timer4
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page detector
}
//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// SMBus Interrupt Service Routine (ISR)
//-----------------------------------------------------------------------------
//
// SMBus ISR state machine
// - Master only implementation - no slave states defined
// - All incoming data is written starting at the global pointer <pSMB_DATA_IN>
// - All outgoing data is read from the global pointer <pSMB_DATA_OUT>
//
void SMBUS_ISR (void) interrupt 7
{
bit FAIL = 0; // Used by the ISR to flag failed
// transfers
static char i; // Used by the ISR to count the
// number of data bytes sent or
// received
static bit SEND_START = 0; // Send a start
// Status code for the SMBus (SMB0STA register)
switch (SMB0STA)
{
// Master Transmitter/Receiver: START condition transmitted.
// Load SMB0DAT with slave device (EEPROM) address.
case SMB_START:
SMB0DAT = TARGET; // Load address of the slave.
SMB0DAT &= 0xFE; // Clear the LSB of the address for the
// R/W bit
SMB0DAT |= SMB_RW; // Load R/W bit
STA = 0; // Manually clear STA bit
i = 0; // reset data byte counter
break;
// Master Transmitter/Receiver: Repeated START condition transmitted.
// For a READ: This state only occurs during an EEPROM read operation
// for the EEPROM's "random read", where a write operation with the
// data address must be done before the read operation.
//
// For a WRITE: N/A
case SMB_RP_START:
SMB0DAT = TARGET; // Load address of the slave.
SMB0DAT |= SMB_RW; // Load R/W bit
STA = 0; // Manually clear START bit.
i = 0; // reset data byte counter
break;
// Master Transmitter: Slave address + WRITE transmitted. ACK received.
// For a READ or WRITE: the word (data) address in the EEPROM must now
// be sent after the slave address
case SMB_MTADDACK:
SMB0DAT = WORD_ADDR; // Send word address
if (SMB_RANDOMREAD)
{
SEND_START = 1; // Send a START after the next ACK cycle
SMB_RW = READ;
}
break;
// Master Transmitter: Slave address + WRITE transmitted. NACK received.
// If the EEPROM should be polled, restart the transfer.
// Otherwise, reset the SMBus
case SMB_MTADDNACK:
if(SMB_ACKPOLL)
{
STA = 1; // Restart transfer
}
else
{
FAIL = 1; // Indicate failed transfer
} // and handle at end of ISR
break;
// Master Transmitter: Data byte transmitted. ACK received.
// For a READ: the word address has been trasmitted, and a repeated
// start should be generated.
//
// For a WRITE: each data word should be sent
case SMB_MTDBACK:
if (SEND_START)
{
STA = 1;
SEND_START = 0;
break;
}
if (SMB_RW==WRITE) // Is this transfer a WRITE?
{
if (i < SMB_DATA_LEN) // Is there data to send?
{
// send data byte
SMB0DAT = *pSMB_DATA_OUT;
// increment data out pointer
pSMB_DATA_OUT++;
// increment number of bytes sent
i++;
}
else
{
STO = 1; // Set STO to terminte transfer
SMB_BUSY = 0; // Clear software busy flag
}
}
else {} // If this transfer is a READ, then
// take no action, as a repeated
// start will be generated for the
// read operation
break;
// Master Transmitter: Data byte transmitted. NACK received.
// If the EEPROM should be polled, restart the transfer.
// Otherwise, reset the SMBus
case SMB_MTDBNACK:
if(SMB_ACKPOLL)
{
STA = 1; // Restart transfer
}
else
{
FAIL = 1; // Indicate failed transfer
} // and handle at end of ISR
break;
// Master Transmitter: Arbitration lost.
case SMB_MTARBLOST:
FAIL = 1; // Indicate failed transfer
// and handle at end of ISR
break;
// Master Receiver: Slave address + READ transmitted. ACK received.
// For a READ: check if this is a one-byte transfer. if so, set the
// NACK after the data byte is received to end the transfer. if not,
// set the ACK and receive the other data bytes.
//
// For a WRITE: N/A
case SMB_MRADDACK:
if (i == SMB_DATA_LEN)
{
AA = 0; // Only one byte in this transfer,
// send NACK after byte is received
}
else
{
AA = 1; // More than one byte in this transfer,
// send ACK after byte is received
}
break;
// Master Receiver: Slave address + READ transmitted. NACK received.
// If the EEPROM should be polled, restart the transfer.
// Otherwise, reset the SMBus
case SMB_MRADDNACK:
if(SMB_ACKPOLL)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -