發新話題
打印

C8051F34x的SMBus如何跑到100K和400K??

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
}

TOP

目前此sample code的SCL可以達到100KHz,但是若為400Khz該要怎麼設定才可以跑到此頻率呢??

TOP

可以用 CW2 軟體來設定,步驟如附圖:
附件: 您所在的用戶組無法下載或查看附件

TOP

引用:
原帖由 Stevenyang 於 2011-8-31 10:53 發表
可以用 CW2 軟體來設定,步驟如附圖:
謝謝版大回覆,步驟詳細...

TOP

發新話題