📄 8051 smb.c
字号:
//------------------------------------------------------------------------------------
//
// Copyright 2001 Cygnal Integrated Products, Inc.
//
// FILE NAME : SMB_Ex3.c
// TARGET DEVICE : C8051F000
// CREATED ON : 2/20/01
// CREATED BY : JS
//
// Example code to demonstrate the use of the SMBus interface between two CF000 devices.
// The devices operate in a peer-to-peer configuration.
//
// Demonstration includes use of op codes for each device to command the other to:
//
// 1) Write a byte to DAC0
// 2) Write a byte to a data buffer
// 3) Perform an ADC conversion
// 4) Read a byte from a data buffer
//
// These op codes are can be tested easily if each chip has DAC0 routed to AIN0.
// With this configuration, a READ_ADC command can be used to test the output
// of a WRITE_DAC command.
//
// Code assumes that two CF0xx devices are connected via SCL and SDA, with
// slave addresses (held by register SMB0ADR)
// CHIP_A = 1111000
// CHIP_B = 1110000
//
// Test code is included. For testing purposes, the test code should be omitted
// in one device, and run in the other. This can be accomplished by commenting
// the OP_CODE_HANDLER() call before the test code in the device that will assume
// the master role.
//
// PLEASE NOTE that the constant MY_ADD must correspond with the
// current device - change it to CHIP_B when downloading code to CHIP_B.
//
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------------
#include <c8051f000.h> // SFR declarations
//------------------------------------------------------------------------------------
// Global CONSTANTS
//------------------------------------------------------------------------------------
#define WRITE 0x00 // WRITE direction bit
#define READ 0x01 // READ direction bit
// Device addresses
#define CHIP_A 0xF0
#define CHIP_B 0xE0
#define MY_ADD CHIP_A // Corresponds to the chip currently
// being programmed.
// Peer-to-Peer OP_CODEs
#define READ_ADC 0x01 // OP_CODE to read from slave ADC
#define WRITE_DAC 0x02 // OP_CODE to write to slave DAC
#define WRITE_BUF 0x03 // OP_CODE to write to slave buffer
#define READ_BUF 0x04 // OP_CODE to read from slave buffer
//SMBus states:
// MT = Master Transmitter
// MR = Master Receiver
// ST = Slave Transmitter
// SR = Slave Receiver
#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
#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
//-----------------------------------------------------------------------------------
//Global VARIABLES
//-----------------------------------------------------------------------------------
char COMMAND; // Holds the slave address + R/W bit for
// use in the SMBus ISR.
char WORD; // Holds data to be transmitted by the SMBus
// OR data that has just been received.
char OP_CODE; // Holds an op code to be sent or one
// that has just been received.
char LOST_COMMAND, LOST_WORD, LOST_CODE; // Used to hold relevant data after a
// lost arbitration.
char DATA_BUF[16]; // Data buffer accessed by OP_CODE_HANDLER
bit LOST; // Arbitration lost flag, set when
// arbitration is lost while in master mode.
// Used to resume a failed transfer.
bit SM_BUSY; // This bit is set when a send or receive
// is started. It is cleared by the
// ISR when the operation is finished.
bit VALID_OP; // Flag used to determine if byte received
// as a slave is an OP_CODE or data.
bit DATA_READY; // Used by OP_CODE handler to flag when
// valid data has been received from the
// master
//------------------------------------------------------------------------------------
// Function PROTOTYPES
//------------------------------------------------------------------------------------
void SMBUS_ISR (void);
char SLA_READ(char chip_select, char out_op);
void SLA_SEND(char chip_select, char out_op, char out_data);
void OP_CODE_HANDLER(void);
//------------------------------------------------------------------------------------
// MAIN Routine
//------------------------------------------------------------------------------------
void MAIN (void)
{
char i, check_1, check_2; // Variables used for testing purposes only.
WDTCN = 0xde; // disable watchdog timer
WDTCN = 0xad;
XBR0 = 0x01; // Route SMBus to GPIO pins through crossbar
XBR2 = 0x40; // Enable crossbar and weak pull-ups
SMB0CN = 0x44; // Enable SMBus with acknowledge low (AA = 1)
SMB0CR = -80; // SMBus clock rate = 100 kHz
SMB0ADR = MY_ADD; // Set own slave address.
ADC0CN = 0x80; // Enable ADC, conversions to start with
// write to ADBUSY.
ADC0CN |= 0x01; // ADC data registers left-justified.
DAC0CN = 0x84; // enable DAC0, with left justified data
// registers.
REF0CN = 0x03; // reference voltage enabled.
EIE1 |= 2; // SMBus interrupt enable
EA = 1; // Global interrupt enable
SM_BUSY = 0; // Free bus for first transfer.
SI = 0; //
// OP_CODE_HANDLER(); // This line should be commented in only
// one of the two peer devices. It is
// for testing purposes only.
// In a normal setup, the OP_CODE_HANDLER
// would be running at all times in order
// to react to OP_CODES being sent to the
// device.
// TEST CODE--------------------------------------------------------------------------
// This code is used only to test the interface between the two devices. If
// the above OP_CODE_HANDLER line is commented out, this device assumes the master
// role. The other device should be running the OP_CODE_HANDLER at all times, to
// respond to the OP_CODEs below.
SLA_SEND(CHIP_B, (0x40 | WRITE_BUF), 0x24); // Write to index 4
// in the data buffer
SLA_SEND(CHIP_B, (0x60 | WRITE_BUF), 0x25); // Write to index 6
SLA_SEND(CHIP_B, (0x80 | WRITE_BUF), 0x26); // Write to index 8
SLA_SEND(CHIP_B, (0x10 | WRITE_BUF), 0x27); // Write to index 1
check_1 = SLA_READ(CHIP_B, (0x40 | READ_BUF)); // Read index 4 from the buffer
check_1 = SLA_READ(CHIP_B, (0x60 | READ_BUF)); // Read index 6
check_1 = SLA_READ(CHIP_B, (0x80 | READ_BUF)); // Read index 8
check_1 = SLA_READ(CHIP_B, (0x10 | READ_BUF)); // Read index 1
// Loop to continuously increase the DAC output on CHIP_B, and read its
// ADC each round. DAC output on CHIP_B should ramp.
for (i=0;i<50;i++){
SLA_SEND(CHIP_B, WRITE_DAC, 2*i); // Write 2*i to DAC0 on CHIP_B
check_1 = SLA_READ(CHIP_B, READ_ADC); // Read AIN0 on CHIP_B
check_2 = 2*i;} // check_1 should be approximately
// the same as check_2.
// END TEST CODE----------------------------------------------------------------------
}
//------------------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------------------
// Send to slave.
// The send function transmits two bytes to the slave device: an op code, and a data
// byte. There are two op code choices for sending data: WRITE_DAC and WRITE_BUF.
// If the op code is WRITE_BUF, then the upper 4 bits of the op code should contain
// the buffer index. For example, to write to index 2 of the data buffer, the
// op_code parameter should be (0x20 | WRITE_BUF).
//
// chip_select = address of slave device.
// out_op = OP_CODE to be sent.
// out_data = data byte to be sent.
void SLA_SEND(char chip_select, char out_op, char out_data){
while(SM_BUSY); // Wait while SMBus is busy.
SM_BUSY = 1; // SMBus busy flag set.
SMB0CN = 0x44; // SMBus enabled, ACK low.
COMMAND = (chip_select | WRITE); // COMMAND = 7 address bits + WRITE.
OP_CODE = out_op; // WORD = OP_CODE to be transmitted.
WORD = out_data; // DATA = data to be transmitted.
STO = 0;
STA = 1; // Start transfer.
}
// Read from slave.
// The read function transmits a 1-byte op code, then issues a repeated start
// to request a 1-byte read. The two op code choices are READ_ADC and READ_BUF.
// If the op code is READ_BUF, then the upper 4 bits of the op code should
// contain the buffer index. For example, to read index 5 of the data buffer,
// the op code should be (0x50 | READ_BUF).
//
// chip_select = address of slave device.
// out_op = OP_CODE to be sent.
char SLA_READ(char chip_select, char out_op){
while(SM_BUSY); // Wait while SMBus is busy.
SM_BUSY = 1; // Set busy flag.
SMB0CN = 0x44; // Enable SMBus, ACK low.
COMMAND = (chip_select | READ); // COMMAND = 7 address bits + READ
OP_CODE = out_op;
STO = 0;
STA = 1; // Start transfer.
while(SM_BUSY); // Wait for transfer to finish.
return WORD; // Return received word.
}
// OP_CODE handler.
// Decodes incoming op codes and performs tasks according to those op codes.
// A call to this function runs forever.
//
// The VALID_OP bit flags when a valid op code has been received. Upon receipt,
// the handler decodes the op code, performs the task, then clears
// VALID_OP to wait for another code.
void OP_CODE_HANDLER(void){
char index; // data buffer index
while (1){ // run forever
VALID_OP = 0; // Wait for a valid OP_CODE
while (!VALID_OP); //
// The lower 4 bits of the OP_CODE are used to determine the action, while the
// upper 4 bits are used to index the DATA_BUF array when the READ_BUF or
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -