C8051F34x的SMBus如何跑到100K和400K??
目前我使用C8051F347的MCU在寫SMBus功能,我是使用Sample code修改我想要的功能,比較怪的地方是當SMB_FREQUENCY定義從10000~70000都可以進行while(1)動作,但我若把SMB_FREQUENCY改為100000就無法進行while(1)動作,這樣就無法跑到100K~400K的速率了..
#include <C8051F340.h>
#define SYSCLK 12000000
#define SMB_FREQUENCY 100000
#define WRITE 0x00
#define READ 0x01
#define SLAVE_ADDR 0x5B
#define SMB_MTSTA 0xE0
#define SMB_MTDB 0xC0
#define SMB_MRDB 0x80
unsigned char NUM_BYTES_WR;
unsigned char NUM_BYTES_RD;
unsigned char xdata SMB_DATA_IN[64];
unsigned char xdata SMB_DATA_OUT[64];
unsigned char TARGET;
bit SMB_BUSY;
bit SMB_RW;
unsigned long NUM_ERRORS;
sfr16 TMR3RL = 0x92;
sfr16 TMR3 = 0x94;
sbit SDA = P0^0;
sbit SCL = P0^1;
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 main (void)
{
unsigned char i;
PCA0MD &= ~0x40;
OSCICN |= 0x03;
while(!SDA)
{
XBR1 = 0x40;
SCL = 0;
for(i = 0; i < 255; i++);
SCL = 1;
while(!SCL);
for(i = 0; i < 10; i++);
XBR1 = 0x00;
}
Port_Init ();
Timer1_Init ();
Timer3_Init();
SMBus_Init ();
EIE1 |= 0x01;
EA = 1;
while(1)
{
NUM_BYTES_WR=0x40;
for(i=0;i<=63;i++)
SMB_DATA_OUT=i;
TARGET=SLAVE_ADDR<<1;
SMB_Write();
T0_Wait_ms(NUM_BYTES_WR);
}
}
void SMBus_Init (void)
{
SMB0CF = 0x5D;
SMB0CF |= 0x80;
}
void Timer1_Init (void)
{
#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
}
void Timer3_Init (void)
{
TMR3CN = 0x00;
CKCON &= ~0x40;
TMR3RL = -(SYSCLK/12/40);
TMR3 = TMR3RL;
EIE1 |= 0x80;
TMR3CN |= 0x04;
}
void PORT_Init (void)
{
P0MDOUT = 0x00;
P2MDOUT |= 0x04;
XBR0 = 0x04;
XBR1 = 0x40;
P0 = 0xFF;
}
void SMBus_ISR (void) interrupt 7
{
bit FAIL = 0;
static unsigned char sent_byte_counter;
static unsigned char rec_byte_counter;
if (ARBLOST == 0)
{
switch (SMB0CN & 0xF0)
{
// Master Transmitter/Receiver: START condition transmitted.
case SMB_MTSTA:
SMB0DAT = TARGET;
//SMB0DAT &= 0xFF; // 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
}
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
}
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
}
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
}