📄 f31x_smbus_multimaster.c
字号:
//
// Timer3 configured for use by the SMBus low timeout detect feature as
// follows:
// - Timer3 in 16-bit auto-reload mode
// - SYSCLK/12 as Timer3 clock source
// - Timer3 reload registers loaded for a 25ms overflow period
// - Timer3 pre-loaded to overflow after 25ms
// - Timer3 enabled
//
void Timer3_Init (void)
{
TMR3CN = 0x00; // Timer3 configured for 16-bit auto-
// reload, low-byte interrupt disabled
CKCON &= ~0x40; // Timer3 uses SYSCLK/12
TMR3RL = -(SYSCLK/12/40); // Timer3 configured to overflow after
TMR3 = TMR3RL; // ~25ms (for SMBus low timeout detect):
// 1/.025 = 40
EIE1 |= 0x80; // Timer3 interrupt enable
TMR3CN |= 0x04; // Start Timer3
}
//-----------------------------------------------------------------------------
// 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
//
// P0.7 digital open-drain SW (switch)
//
// P3.3 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)
{
P0MDOUT = 0x00; // All P0 pins open-drain output
P3MDOUT |= 0x08; // Make the LED (P3.3) a push-pull
// output
XBR0 = 0x04; // Enable SMBus pins
XBR1 = 0x40; // Enable crossbar and weak pull-ups
P0 = 0xFF;
}
//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Timer0 Interrupt Service Routine (ISR)
//-----------------------------------------------------------------------------
//
// Timer0 blinks the LED when instructed by the other multimaster.
//
void Timer0_ISR (void) interrupt 1
{
static unsigned char count = 0; // Count up to 256 Timer0 interrupts
// before switching the LED
// otherwise, it won't be visible to
// the eye
if (count == 255)
{
LED = ~LED; // Turn the LED on and off
count = 0;
}
else
{
count++;
}
}
//-----------------------------------------------------------------------------
// SMBus Interrupt Service Routine (ISR)
//-----------------------------------------------------------------------------
//
// SMBus ISR state machine
// - Master only implementation - no slave or arbitration states defined
// - Incoming master data is written to global variable <SMB_DATA_IN_MASTER>
// - Incoming slave data is written to global variable <SMB_DATA_IN_SLAVE>
// - Outgoing master data is read from global variable <SMB_DATA_OUT_MASTER>
// - Outgoing slave data is read from global variable <SMB_DATA_OUT_SLAVE>
//
void SMBus_ISR (void) interrupt 7
{
bit M_FAIL = 0; // Used by the master states to flag a
// bus error condition
// transfers
static bit ADDR_SEND = 0; // Used by the ISR to flag byte
// transmissions as slave addresses
static bit arbitration_lost = 0; // Used by the ISR to flag whether
// arbitration was lost and the transfer
// should be rescheduled
// Normal operation
switch (SMB0CN & 0xF0) // Status vector
{
// MASTER ---------------------------------------------------------------
// Master Transmitter/Receiver: START condition transmitted.
case SMB_MTSTA:
SMB0DAT = TARGET; // Load address of the target 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 START bit
ADDR_SEND = 1;
break;
// Master Transmitter: Data byte transmitted
case SMB_MTDB:
if (ARBLOST == 0) // Check for a bus error
{
if (ACK) // Slave ACK?
{
if (ADDR_SEND) // If the previous byte was a slave
{ // address,
ADDR_SEND = 0; // Next byte is not a slave address
if (SMB_RW == WRITE) // If this transfer is a WRITE,
{
// Send data byte
SMB0DAT = SMB_DATA_OUT_MASTER;
}
else {} // If this transfer is a READ,
// proceed with transfer without
// writing to SMB0DAT (switch
// to receive mode)
}
else // If previous byte was not a slave
{ // address,
STO = 1; // Set STO to terminate transfer
SMB_BUSY = 0; // And free SMBus interface
}
}
else // If slave NACK,
{
STO = 1; // Send STOP condition, followed
STA = 1; // By a START
NUM_ERRORS++; // Indicate error
}
}
else
{
M_FAIL = 1; // If a bus error occurs, reset
}
break;
// Master Receiver: byte received
case SMB_MRDB:
if (ARBLOST == 0) // Check for a bus error
{
// Store received byte
SMB_DATA_IN_MASTER = SMB0DAT;
SMB_BUSY = 0; // Free SMBus interface
ACK = 0; // Send NACK to indicate last byte
// of this transfer
STO = 1; // Send STOP to terminate transfer
}
else
{
M_FAIL = 1; // If a bus error occurs, reset
}
break;
// ----------------------------------------------------------------------
// SLAVE ----------------------------------------------------------------
// Slave Receiver: Start+Address received
case SMB_SRADD:
if (ARBLOST == 1)
{
arbitration_lost = 1; // Indicate lost arbitration
}
STA = 0; // Clear STA bit
if((SMB0DAT&0xFE) == (MY_ADDR&0xFE)) // Decode address
{ // If the received address matches,
ACK = 1; // ACK the received slave address
if((SMB0DAT&0x01) == READ) // If the transfer is a master READ
{
// Prepare outgoing byte
SMB0DAT = SMB_DATA_OUT_SLAVE;
}
}
else // If received slave address does not
{ // match,
ACK = 0; // NACK received address
}
break;
// Slave Receiver: Data received
case SMB_SRDB:
if (ARBLOST == 0) // No bus error
{
// Store incoming data
SMB_DATA_IN_SLAVE = SMB0DAT;
DATA_READY = 1; // Indicate new data received
ACK = 1; // ACK received data
}
else // Bus error detected
{
STA = 0;
STO = 0;
ACK = 0;
}
break;
// Slave Receiver: Stop received while either a Slave Receiver or Slave
// Transmitter
case SMB_SRSTO:
if (arbitration_lost == 1)
{
STA = 1; // The ARBLOST bit indicated the master
// lost arbitration
// reschedule the transfer
arbitration_lost = 0;
}
STO = 0; // STO must be cleared by software when
// a STOP is detected as a slave
break;
// Slave Transmitter: Data byte transmitted
case SMB_STDB:
// No action required;
// one-byte transfers
// only for this example
break;
// Slave Transmitter: Arbitration lost, Stop detected
//
// This state will only be entered on a bus error condition.
// In normal operation, the slave is no longer sending data or has
// data pending when a STOP is received from the master, so the TXMODE
// bit is cleared and the slave goes to the SRSTO state.
case SMB_STSTO:
STO = 0; // STO must be cleared by software when
// a STOP is detected as a slave
break;
// Default: all other cases undefined
// ----------------------------------------------------------------------
default:
M_FAIL = 1; // Indicate failed transfer
// and handle at end of ISR
break;
} // end switch
if (M_FAIL) // If the transfer failed,
{
SMB0CF &= ~0x80; // Reset communication
SMB0CF |= 0x80;
STA = 0;
STO = 0;
ACK = 0;
SMB_BUSY = 0; // Free SMBus
M_FAIL = 0;
LED = 0;
NUM_ERRORS++; // Indicate an error occurred
}
SI = 0; // Clear interrupt flag
}
//-----------------------------------------------------------------------------
// Timer3 Interrupt Service Routine (ISR)
//-----------------------------------------------------------------------------
//
// A Timer3 interrupt indicates an SMBus SCL low timeout.
// The SMBus is disabled and re-enabled here
//
void Timer3_ISR (void) interrupt 14
{
SMB0CF &= ~0x80; // Disable SMBus
SMB0CF |= 0x80; // Re-enable SMBus
TMR3CN &= ~0x80; // Clear Timer3 interrupt-pending flag
STA = 0;
SMB_BUSY = 0; // Free SMBus
}
//-----------------------------------------------------------------------------
// Support Functions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// SMB_Write
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Writes a single byte to the slave with address specified by the <TARGET>
// variable.
// Calling sequence:
// 1) Write target slave address to the <TARGET> variable
// 2) Write outgoing data to the <SMB_data_out> variable
// 3) Call SMB_Write()
//
void SMB_Write (void)
{
while (SMB_BUSY); // Wait for SMBus to be free.
SMB_BUSY = 1; // Claim SMBus (set to busy)
SMB_RW = 0; // Mark this transfer as a WRITE
STA = 1; // Start transfer
}
//-----------------------------------------------------------------------------
// Blink_LED
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Starts the LED blinking.
//
void Blink_LED (void)
{
TR0 = 1;
}
//-----------------------------------------------------------------------------
// Stop_LED
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Stops the LED from blinking.
//
void Stop_LED (void)
{
TR0 = 0;
LED = 0; // Turn the LED off when it's not
// blinking
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -