?? f12x_smbus_multimaster.c
字號:
//-----------------------------------------------------------------------------
// F12x_SMBus_Multimaster.c
//-----------------------------------------------------------------------------
// Copyright 2006 Silicon Laboratories, Inc.
// http://www.silabs.com
//
// Program Description:
//
// Example software to demonstrate the C8051F12x SMBus interface in
// a Multi-Master environment.
// - Interrupt-driven SMBus implementation
// - Master and slave states defined
// - 1-byte SMBus data holders used for each transmit and receive
// - Timer3 used by SMBus for SCL low timeout detection
// - SCL frequency defined by <SMB_FREQUENCY> constant
// - ARBLOST support included
// - When another master attempts to transmit at the same time:
// - the 'F12x SMBus master should detect any conflict using ARBLOST
// - the 'F12x SMBus master should give up the bus, if necessary, and
// switch to slave receiver mode
// - the 'F12x SMBus master should transmit after the other master is done
// - Pinout:
// P0.0 -> SDA (SMBus)
// P0.1 -> SCL (SMBus)
//
// P1.6 -> LED
//
// P3.7 -> SW
//
// all other port pins unused
//
// How To Test:
//
// 1) Download code to a 'F12x device that is connected to another C8051Fxxx
// SMBus multimaster.
// 2) Run the code. The test will indicate proper communication with the
// other C8051Fxxx device by blinking the LED on the other device on and
// off each time SW is pressed, even if the buttons on both boards are
// pressed at the same time.
//
// 'F12x Multimaster Other C8051Fxxx Multimaster
// LED (blinks) <------------------------------ Switch
// SW --------------------------------> LED (blinks)
//
// NOTE: Before running the test, verify that MY_ADDR and MULTI_ADDR are
// defined to the proper values.
//
// FID: 12X000017
// Target: C8051F12x
// Tool chain: Keil C51 7.50 / Keil EVAL C51
// Command Line: None
//
// Release 1.0
// -Initial Revision (TP)
// -20 APR 2006
//
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <C8051F120.h> // SFR declarations
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define SYSCLK 6125000L // System clock frequency in Hz
#define SMB_FREQUENCY 10000L // Target SCL clock rate
// This example supports between 10kHz
// and 100kHz
#define WRITE 0x00 // WRITE direction bit
#define READ 0x01 // READ direction bit
// Device addresses (7 bits, lsb is a don't care)
#define MY_ADDR 0x02 // Device address for this device target
#define MULTI_ADDR 0xF0 // Device address for other multimaster
// target
// Master States
#define SMB_BUS_ERROR 0x00 // (all modes) BUS ERROR
#define SMB_START 0x08 // (MT & MR) START transmitted
#define SMB_RP_START 0x10 // (MT & MR) repeated START
#define SMB_MTADDACK 0x18 // (MT) Slave address + W transmitted;
// ACK received
#define SMB_MTADDNACK 0x20 // (MT) Slave address + W transmitted;
// NACK received
#define SMB_MTDBACK 0x28 // (MT) data byte transmitted;
// ACK rec'vd
#define SMB_MTDBNACK 0x30 // (MT) data byte transmitted;
// NACK rec'vd
#define SMB_MTARBLOST 0x38 // (MT) arbitration lost
#define SMB_MRADDACK 0x40 // (MR) Slave address + R transmitted;
// ACK received
#define SMB_MRADDNACK 0x48 // (MR) Slave address + R transmitted;
// NACK received
#define SMB_MRDBACK 0x50 // (MR) data byte rec'vd;
// ACK transmitted
#define SMB_MRDBNACK 0x58 // (MR) data byte rec'vd;
// NACK transmitted
// Slave States
#define SMB_SROADACK 0x60 // (SR) SMB's own slave address + W
// rec'vd; ACK transmitted
#define SMB_SROARBLOST 0x68 // (SR) SMB's own slave address + W
// rec'vd; arbitration lost
#define SMB_SRGADACK 0x70 // (SR) general call address rec'vd;
// ACK transmitted
#define SMB_SRGARBLOST 0x78 // (SR) arbitration lost when
// transmitting slave addr + R/W as
// master; general call address
// rec'vd; ACK transmitted
#define SMB_SRODBACK 0x80 // (SR) data byte received under own
// slave address; ACK returned
#define SMB_SRODBNACK 0x88 // (SR) data byte received under own
// slave address; NACK returned
#define SMB_SRGDBACK 0x90 // (SR) data byte received under general
// call address; ACK returned
#define SMB_SRGDBNACK 0x98 // (SR) data byte received under general
// call address; NACK returned
#define SMB_SRSTOP 0xa0 // (SR) STOP or repeated START received
// while addressed as a slave
#define SMB_STOADACK 0xa8 // (ST) SMB's own slave address + R
// rec'vd; ACK transmitted
#define SMB_STOARBLOST 0xb0 // (ST) arbitration lost in transmitting
// slave address + R/W as master; own
// slave address rec'vd; ACK
// transmitted
#define SMB_STDBACK 0xb8 // (ST) data byte transmitted; ACK
// rec'ed
#define SMB_STDBNACK 0xc0 // (ST) data byte transmitted; NACK
// rec'ed
#define SMB_STDBLAST 0xc8 // (ST) last data byte transmitted
// (AA=0); ACK received
#define SMB_SCLHIGHTO 0xd0 // (ST & SR) SCL clock high timer per
// SMB0CR timed out (FTE=1)
#define SMB_IDLE 0xf8 // (all modes) Idle
// Data to indicate the switch was pressed or released
#define SW_PRESSED 0x0A
#define SW_RELEASED 0x50
//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------
// Global holder for SMBus master data. All receive data is written here
// while in master mode
// Slave->Master
unsigned char SMB_DATA_IN_MASTER = 0x00;
// Global holder for SMBus master data. All transmit data is read from here
// while in master mode
// Master->Slave
unsigned char SMB_DATA_OUT_MASTER = 0x00;
// Global holder for SMBus slave data. All receive data is written here
// while slave mode
// Master->Slave
unsigned char SMB_DATA_IN_SLAVE = 0x00;
// Global holder for SMBus slave data. All transmit data is read from here
// while in slave mode
// Slave->Master
unsigned char SMB_DATA_OUT_SLAVE = 0x00;
bit DATA_READY = 0; // Set to '1' by the SMBus ISR
// when a new data byte has been
// received in slave mode.
unsigned char TARGET; // Target SMBus slave address
bit SMB_BUSY; // Software flag to indicate when the
// SMB_Read() or SMB_Write() functions
// have claimed the SMBus
bit SMB_RW; // Software flag to indicate the
// direction of the current transfer
// 16-bit SFR declarations
sfr16 RCAP3 = 0xCA; // Timer3 reload registers
sfr16 TMR3 = 0xCC; // Timer3 counter registers
sbit LED = P1^6; // LED on P1.6
sbit SW = P3^7; // Switch on P3.7
sbit SDA = P0^0; // SMBus on P0.0
sbit SCL = P0^1; // and P0.1
//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------
void SYSCLK_Init(void);
void Port_Init(void);
void SMBus_Init(void);
void Timer0_Init (void);
void Timer1_Init (void);
void Timer3_Init(void);
void SMBus_ISR(void);
void Timer3_ISR(void);
void SMB_Write (void);
void Blink_LED (void);
void Stop_LED (void);
//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void MAIN (void)
{
bit switch_pressed_flag = 0; // Used to detect when the switch is
// released
unsigned char i; // Dummy variable counters
WDTCN = 0xde; // Disable watchdog timer
WDTCN = 0xad;
SYSCLK_Init (); // Set internal oscillator to a setting
// of 6125000 Hz
// If slave is holding SDA low because of an improper SMBus reset or error
while(!SDA)
{
// Provide clock pulses to allow the slave to advance out
// of its current state. This will allow it to release SDA.
XBR1 = 0x40; // Enable Crossbar
SCL = 0; // Drive the clock low
for(i = 0; i < 255; i++); // Hold the clock low
SCL = 1; // Release the clock
while(!SCL); // Wait for open-drain
// clock output to rise
for(i = 0; i < 10; i++); // Hold the clock high
XBR1 = 0x00; // Disable Crossbar
}
Port_Init (); // Initialize Crossbar and GPIO
// Turn off the LED before the test starts
LED = 0;
SMBus_Init (); // Configure and enable SMBus
Timer3_Init (); // Configure and enable Timer3
Timer0_Init (); // Configure Timer0 for the LED
EIE1 |= 0x02; // Enable the SMBus interrupt
ET0 = 1; // Enable the Timer0 interrupt
PT0 = 1; // Make the Timer0 interrupt high
// priority
EA = 1; // Global interrupt enable
SFRPAGE = SMB0_PAGE;
SI = 0;
while (1)
{
// Check if the switch was just pressed
if ((switch_pressed_flag == 0) && (SW == 0))
{
// SMBus Write Sequence
// Tell the other device the switch was pressed
SMB_DATA_OUT_MASTER = SW_PRESSED;
TARGET = MULTI_ADDR; // Target the other multimaster device
SMB_Write(); // Initiate SMBus write
switch_pressed_flag = 1;
}
// Determine if the switch was just released
if ((switch_pressed_flag == 1) && (SW != 0))
{
// SMBus Write Sequence
// Tell the other device the switch was released
SMB_DATA_OUT_MASTER = SW_RELEASED;
TARGET = MULTI_ADDR; // Target the other multimaster device
SMB_Write(); // Initiate SMBus write
switch_pressed_flag = 0;
}
// Check if data was sent to this device from the other multimaster
// device
if (DATA_READY == 1)
{
if (SMB_DATA_IN_SLAVE == SW_PRESSED)
{
Blink_LED();
}
else
{
if (SMB_DATA_IN_SLAVE == SW_RELEASED)
{
Stop_LED();
}
}
DATA_READY = 0;
}
} // Loop forever
}
//-----------------------------------------------------------------------------
// Initialization Routines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// SYSCLK_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// This routine initializes the system clock to use the internal oscillator
// at 6.125 MHz (24.5 / 4 MHz).
//
void SYSCLK_Init (void)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
SFRPAGE = CONFIG_PAGE; // Set SFR page
OSCICN = 0x81; // Set internal oscillator to run
// at 1/4 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
//
// P3.7 digital open-drain SW (switch)
//
// 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 / (8 * SMB_FREQUENCY));
SMB0ADR = MY_ADDR; // Set own slave address.
SMB0CN |= 0x40; // Enable SMBus;
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page detector
}
//-----------------------------------------------------------------------------
// Timer0_Init
//-----------------------------------------------------------------------------
//
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -