全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1550
推到 Plurk!
推到 Facebook!

C8051F34x的SMBus如何跑到400K??

缺席
phchen0413
一般會員


發表:14
回覆:21
積分:12
註冊:2009-07-01

發送簡訊給我
#1 引用回覆 回覆 發表時間:2011-08-23 13:51:39 IP:211.75.xxx.xxx 訂閱
目前我使用C8051F347的MCU在寫SMBus功能,我是使用Sample code修改我想要的功能,
目前SCL從10K~100K都可以達到目標,但請問各位大大該如何將此SCL提升至400KHz??

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------

#include

//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------

#define SYSCLK 12000000 // System clock frequency in Hz

#define SMB_FREQUENCY 100000 // Target SCL clock rate
// This example supports between 10kHz
// and 100kHz

#define WRITE 0x00 // SMBus WRITE command
#define READ 0x01 // SMBus READ command

#define SLAVE_ADDR 0x5B // Device address for slave target

// Status vector - top 4 bits only
#define SMB_MTSTA 0xE0 // (MT) start transmitted
#define SMB_MTDB 0xC0 // (MT) data byte transmitted
#define SMB_MRDB 0x80 // (MR) data byte received
// End status vector definition

//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------
unsigned char NUM_BYTES_WR;
unsigned char NUM_BYTES_RD;
// Global holder for SMBus data
// All receive data is written here
unsigned char xdata SMB_DATA_IN[64];

// Global holder for SMBus data.
// All transmit data is read from here
unsigned char xdata SMB_DATA_OUT[64];


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

unsigned long NUM_ERRORS; // Counter for the number of errors.

// 16-bit SFR declarations
sfr16 TMR3RL = 0x92; // Timer3 reload registers
sfr16 TMR3 = 0x94; // Timer3 counter registers

//sbit LED = P2^2; // LED on port P2.2
sbit SDA = P0^0; // SMBus on P0.0
sbit SCL = P0^1; // and P0.1
//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------

void SMBus_Init (void);
void Timer1_Init (void);
void Timer3_Init (void);
void Port_Init (void);

void SMBus_ISR (void);
void Timer3_ISR (void);

void SMB_Write (void);
void SMB_Read (void);
void T0_Wait_ms (unsigned char ms);

//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
//
// Main routine performs all configuration tasks, then loops forever sending
// and receiving SMBus data to the slave.
//
void main (void)
{
//volatile unsigned char dat; // Test counter
//volatile unsigned char data_count; // SMB_DATA_IN and SMB_DATA_OUT counter
unsigned char i; // Dummy variable counters

PCA0MD &= ~0x40; // WDTE = 0 (watchdog timer enable bit)

OSCICN |= 0x03; // Set internal oscillator to highest
// setting of 12000000

// 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

Timer1_Init (); // Configure Timer1 for use as SMBus
// clock source

Timer3_Init(); // Configure Timer3 for use with SMBus
// low timeout detect

SMBus_Init (); // Configure and enable SMBus

EIE1 |= 0x01; // Enable the SMBus interrupt

EA = 1; // Global interrupt enable

//while(1)
//{

for(i=0;i<=63;i )
SMB_DATA_OUT[i]=i;
NUM_BYTES_WR=0x40;
TARGET=SLAVE_ADDR<<1;
SMB_Write();

T0_Wait_ms(NUM_BYTES_WR*30);
//}
}

//-----------------------------------------------------------------------------
// Initialization Routines
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// SMBus_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// SMBus configured as follows:
// - SMBus enabled
// - Slave mode inhibited
// - Timer1 used as clock source. The maximum SCL frequency will be
// approximately 1/3 the Timer1 overflow rate
// - Setup and hold time extensions enabled
// - Bus Free and SCL Low timeout detection enabled
//
void SMBus_Init (void)
{
SMB0CF = 0x5D; // Use Timer1 overflows as SMBus clock
// source;
// Disable slave mode;
// Enable setup & hold time
// extensions;
// Enable SMBus Free timeout detect;
// Enable SCL low timeout detect;

SMB0CF |= 0x80; // Enable SMBus;

}

//-----------------------------------------------------------------------------
// Timer1_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Timer1 configured as the SMBus clock source as follows:
// - Timer1 in 8-bit auto-reload mode
// - SYSCLK or SYSCLK / 4 as Timer1 clock source
// - Timer1 overflow rate => 3 * SMB_FREQUENCY
// - The resulting SCL clock rate will be ~1/3 the Timer1 overflow rate
// - Timer1 enabled
//
void Timer1_Init (void)
{

// Make sure the Timer can produce the appropriate frequency in 8-bit mode
// Supported SMBus Frequencies range from 10kHz to 100kHz. The CKCON register
// settings may need to change for frequencies outside this range.
#if ((SYSCLK/SMB_FREQUENCY/3) < 255)
#define SCALE 1
CKCON |= 0x08; // Timer1 clock source = SYSCLK
#elif ((SYSCLK/SMB_FREQUENCY/4/3) < 255)
#define SCALE 4
CKCON |= 0x01;
CKCON &= ~0x0A; // Timer1 clock source = SYSCLK / 4
#endif

TMOD = 0x20; // Timer1 in 8-bit auto-reload mode

// Timer1 configured to overflow at 1/3 the rate defined by SMB_FREQUENCY
TH1 = -(SYSCLK/SMB_FREQUENCY/SCALE/3);

TL1 = TH1; // Init Timer1

TR1 = 1; // Timer1 enabled
}

//-----------------------------------------------------------------------------
// Timer3_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// 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
//
// P2.2 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

P2MDOUT |= 0x04; // Make the LED (P2.2) a push-pull
// output

XBR0 = 0x04; // Enable SMBus pins
XBR1 = 0x40; // Enable crossbar and weak pull-ups

P0 = 0xFF;
}

//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// SMBus Interrupt Service Routine (ISR)
//-----------------------------------------------------------------------------
//
// SMBus ISR state machine
// - Master only implementation - no slave or arbitration states defined
// - All incoming data is written to global variable array
// - All outgoing data is read from global variable array
//
void SMBus_ISR (void) interrupt 7
{
bit FAIL = 0; // Used by the ISR to flag failed
// transfers

static unsigned char sent_byte_counter;
static unsigned char rec_byte_counter;

if (ARBLOST == 0) // Check for errors
{
// Normal operation
switch (SMB0CN & 0xF0) // Status vector
{
// 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
rec_byte_counter = 1; // Reset the counter
sent_byte_counter = 1; // Reset the counter
break;

// Master Transmitter: Data byte transmitted
case SMB_MTDB:
if (ACK) // Slave ACK
{
if (SMB_RW == WRITE) // If this transfer is a WRITE,
{
if (sent_byte_counter <= NUM_BYTES_WR)
{
// send data byte
SMB0DAT = SMB_DATA_OUT[sent_byte_counter-1];
sent_byte_counter ;
}
else
{
STO = 1; // Set STO to terminate transfer
SMB_BUSY = 0; // And free SMBus interface
}
}
else {} // If this transfer is a READ,
// proceed with transfer without
// writing to SMB0DAT (switch
// to receive mode)
}
else // If slave NACK,
{
STO = 1; // Send STOP condition, followed
STA = 1; // By a START
NUM_ERRORS ; // Indicate error
}
break;

// Master Receiver: byte received
case SMB_MRDB:
if (rec_byte_counter < NUM_BYTES_RD)
{
SMB_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received
// byte
ACK = 1; // Send ACK to indicate byte received
rec_byte_counter ; // Increment the byte counter
}
else
{
SMB_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received
// byte
SMB_BUSY = 0; // Free SMBus interface
ACK = 0; // Send NACK to indicate last byte
// of this transfer

STO = 1; // Send STOP to terminate transfer
}
break;

default:
FAIL = 1; // Indicate failed transfer
// and handle at end of ISR
break;

} // end switch
}
else
{
// ARBLOST = 1, error occurred... abort transmission
FAIL = 1;
} // end ARBLOST if

if (FAIL) // If the transfer failed,
{
SMB0CF &= ~0x80; // Reset communication
SMB0CF |= 0x80;
STA = 0;
STO = 0;
ACK = 0;

SMB_BUSY = 0; // Free SMBus

FAIL = 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
// variable.
// Calling sequence:
// 1) Write target slave address to the variable
// 2) Write outgoing data to the variable array
// 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
}

//-----------------------------------------------------------------------------
// SMB_Read
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Reads a single byte from the slave with address specified by the
// variable.
// Calling sequence:
// 1) Write target slave address to the variable
// 2) Call SMB_Write()
// 3) Read input data from variable array
//
void SMB_Read (void)
{
while (SMB_BUSY); // Wait for bus to be free.
SMB_BUSY = 1; // Claim SMBus (set to busy)
SMB_RW = 1; // Mark this transfer as a READ
STA = 1; // Start transfer

while (SMB_BUSY); // Wait for transfer to complete
}

//-----------------------------------------------------------------------------
// T0_Wait_ms
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters :
// 1) unsigned char ms - number of milliseconds to wait
// range is full range of character: 0 to 255
//
// Configure Timer0 to wait for milliseconds using SYSCLK as its time
// base.
//
void T0_Wait_ms (unsigned char ms)
{
TCON &= ~0x30; // Stop Timer0; Clear TF0
TMOD &= ~0x0f; // 16-bit free run mode
TMOD |= 0x01;

CKCON |= 0x04; // Timer0 counts SYSCLKs

while (ms) {
TR0 = 0; // Stop Timer0
TH0 = -(SYSCLK/1000 >> 8); // Overflow in 1ms
TL0 = -(SYSCLK/1000);
TF0 = 0; // Clear overflow indicator
TR0 = 1; // Start Timer0
while (!TF0); // Wait for overflow
ms--; // Update ms counter
}

TR0 = 0; // Stop Timer0
}

//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------

編輯記錄
phchen0413 重新編輯於 2011-08-23 00:18:15, 註解 無‧
phchen0413 重新編輯於 2011-08-24 19:36:43, 註解 無‧
phchen0413 重新編輯於 2011-08-24 19:37:17, 註解 無‧
phchen0413 重新編輯於 2011-08-24 19:40:47, 註解 無‧
phchen0413 重新編輯於 2011-08-26 01:00:42, 註解 無‧
phchen0413 重新編輯於 2011-08-26 01:03:38, 註解 無‧
系統時間:2024-04-19 20:37:17
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!