C8051F34x的SMBus如何跑到400K?? |
缺席
|
phchen0413
一般會員 ![]() ![]() 發表:14 回覆:21 積分:12 註冊:2009-07-01 發送簡訊給我 |
目前我使用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 // 2) Write outgoing data to the // 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 // 2) Call SMB_Write() // 3) Read input data from // 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 // 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, 註解 無‧ |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |