I am having problems with this state machine on setting up an LTC1380 Mux Device. It is really hard to track progress of this state machine without disrupting the bus for logging or stepping through the code/ISR. Has anyone any comments on why this is failing? Greatly appreciated in-advance. void initializeSMBus0(void) { BUSY = 0; ENSMB = 1; STA = 0; STO = 0; SI = 1; AA = 1; SMBFTE = 0; SMBTOE = 0; } int getAllADCMuxDataFromInternalBank0ADCs(void){ volatile int i; volatile int j; volatile int retVal; retVal = NO_ADC_ERROR; for (i=0;i<NUMBER_SMBUS_MUX_CHANNELS; i++) { theSMBusMuxChannel = i; for (j=0;j<NUMBER_SMBUS_MUX_BANKS; j++) { theSMBusMuxBank = j; DISABLE_INTERRUPT_INTERNAL_UART0; ENABLE_INTERRUPT_SMBUS; setupSMBusMuxBankAndChannel(); DISABLE_INTERRUPT_SMBUS; ENABLE_INTERRUPT_INTERNAL_UART0; AMX0SL = j; // Internal ADC 0 MUX CHANNEL SELECTION. AD0INT = 0; // Set complete conversion interrupt flag to conversion not completed. AD0BUSY = 1; // Initiates ADC0 conversion if AD0STM1-0 = 00b (set in init above). while(AD0BUSY !=0){} // Wait for conversion to complete. printf ("B[%i] CH[%i] ",j,i); printf (" 0x%2x ",ADC0H); printf ("0x%2x ",ADC0L); printf("SMBusCntr=%d",SMBusCntr++); printf("\r\n"); } } return (retVal); } int setupSMBusMuxBankAndChannel(void){ volatile int retVal; SMBusDevicesClass = EXTERNAL_SMB_MUXS; ENSMB = 0; // Reset Bus. ENSMB = 1; SI = 0; delayTime(DELAY_WAIT_EXTERNAL_SMBUS_RESET_BUS); // Hangs Here on second iteration...??? //while (BUSY == SMBUS_BUSY_IS_BUSY){} // If SMBus is busy then stay here. //?? an113 PG 25 // BUSY = 0; // App note say to do this. // Start the setting of the Mux STO = 0; STA = 1; return(retVal); } void SMBus_ISR(void) interrupt 7 using 2 { switch (SMBusDevicesClass){ { // Linear SMBus device LTC1380 case EXTERNAL_SMB_MUXS: switch(SMB0STA & 0xF8) { case 0x08: // Start condition transmitted. switch(theSMBusMuxBank){ case 0: theSMBusMuxCommand = SMBUS_MUX_BANK_0; // 0x90 break; case 1: theSMBusMuxCommand = SMBUS_MUX_BANK_1; // 0x92 break; case 2: theSMBusMuxCommand = SMBUS_MUX_BANK_2; // 0x94 break; default:; } SMB0DAT = theSMBusMuxCommand; STA = 0; break; case 0x18: // ACK from slave was received for valid address. STO = 0; switch(theSMBusMuxChannel) { case DAQ_CHANNEL_OVEN1 : theSMBusMuxCommand = 0x08; // 0x08 | 0x00 break; case DAQ_CHANNEL_BLOWER : theSMBusMuxCommand = 0x09; // 0x08 | 0x01 break; default:; } SMB0DAT = theSMBusMuxCommand; break; case 0x20: // NACK was received from Slave. Retry Address. STO = 1; // Set Stop Mode STA = 1; // Set Start Master Mode. switch(theSMBusMuxBank){ case 0: theSMBusMuxCommand = SMBUS_MUX_BANK_0; // 0x90 break; case 1: theSMBusMuxCommand = SMBUS_MUX_BANK_1; // 0x92 break; case 2: theSMBusMuxCommand = SMBUS_MUX_BANK_2; // 0x94 break; default:; } SMB0DAT = theSMBusMuxCommand; break; case 0x28: // Data was sent to slave and received ACK back. STO = 0; // Done with the single channel data send to slave MUX. break; case 0x30: // Data was sent to slave and received NACK back. // Retry data send to slave MUX. // NOTE: NEED COUNTER HERE FOR NOT GETTING STUCK IN AN INFINATE LOOP. // And a global flag for indicating that this happened. switch(theSMBusMuxChannel) { case DAQ_CHANNEL_OVEN1 : theSMBusMuxCommand = 0x08; // 0x08 | 0x00 break; case DAQ_CHANNEL_BLOWER : theSMBusMuxCommand = 0x09; // 0x08 | 0x01 break; default:; } SMB0DAT = theSMBusMuxCommand; // Maybe need to reboot (book offers opinion.) break; case 0x38: // Arbitration lost. // Save Current data. // Nothing to do here for Master to Slave MUX devices. // ?? // Well maybe keep last value logged in sampling averaging.??? break; case 0x00: // Bus Error (Illegal Stop Start) STO = 1; // Reset Bus. break; case 0xF8: // IDLE - Does not set Interrupt; // NOTE: Can poll to send START. break; default:; } break; } case EXTERNAL_SMB_RTC: break; default:; } SI = 0; // Clear SMBus Interrupt. }
I won't bother looking at the code since you didn't bother using the <pre>/</pre> tags to maintain its formatting. That aside, if you are having trouble with tracking the state machine, maybe monitoring the bus itself would be helpful. http://www.usbee.com has some inexpensive I2C/SMBUS monitoring intruments.
OK, formatting is in... It is really hard to track progress of this state machine without disrupting the bus for logging or stepping through the code/ISR. Has anyone any comments on why this is failing? Only using SiLabs F021 MCU as master to 2 slave MUX devices. Greatly appreciated in-advance.
#define DISABLE_INTERRUPT_INTERNAL_UART0 IE = IE & 0xFE; // Bit 0 is UART 0 Interrupt. #define ENABLE_INTERRUPT_INTERNAL_UART0 IE = IE | 0x01; #define DISABLE_INTERRUPT_SMBUS EIP1 = EIP1 & 0xFD; #define ENABLE_INTERRUPT_SMBUS EIP1 = EIP1 | 0x02; void initializeSMBus0(void) { BUSY = 0; ENSMB = 1; STA = 0; STO = 0; SI = 1; AA = 1; SMBFTE = 0; SMBTOE = 0; } int getAllADCMuxDataFromInternalBank0ADCs(void){ volatile int i; volatile int j; volatile int retVal; retVal = NO_ADC_ERROR; for (i=0;i<NUMBER_SMBUS_MUX_CHANNELS; i++) { theSMBusMuxChannel = i; for (j=0;j<NUMBER_SMBUS_MUX_BANKS; j++) { theSMBusMuxBank = j; DISABLE_INTERRUPT_INTERNAL_UART0; ENABLE_INTERRUPT_SMBUS; setupSMBusMuxBankAndChannel(); DISABLE_INTERRUPT_SMBUS; ENABLE_INTERRUPT_INTERNAL_UART0; AMX0SL = j; // Internal ADC 0 MUX CHANNEL SELECTION. AD0INT = 0; // Set complete conversion interrupt flag to conversion not completed. AD0BUSY = 1; // Initiates ADC0 conversion if AD0STM1-0 = 00b (set in init above). while(AD0BUSY !=0){} // Wait for conversion to complete. printf ("B[%i] CH[%i] ",j,i); printf ( " 0x%2x ",ADC0H); printf ("0x%2x ",ADC0L); printf("SMBusCntr=%d",SMBusCntr++); printf(" \r\n"); } } return (retVal); } int setupSMBusMuxBankAndChannel(void){ volatile int retVal; SMBusDevicesClass = EXTERNAL_SMB_MUXS; ENSMB = 0; // Reset Bus. ENSMB = 1; SI = 0; delayTime(DELAY_WAIT_EXTERNAL_SMBUS_RESET_BUS); // Hangs Here on second iteration...??? //while (BUSY == SMBUS_BUSY_IS_BUSY){} // If SMBus is busy then stay here. //?? an113 PG 25 // BUSY = 0; // App note say to do this. // Start the setting of the Mux STO = 0; STA = 1; return(retVal); } void SMBus_ISR(void) interrupt 7 using 2 { switch (SMBusDevicesClass){ { // Linear SMBus device LTC1380 case EXTERNAL_SMB_MUXS: switch(SMB0STA & 0xF8) { case 0x08: // Start condition transmitted. switch(theSMBusMuxBank){ case 0: theSMBusMuxCommand = SMBUS_MUX_BANK_0; // 0x90 break; case 1: theSMBusMuxCommand = SMBUS_MUX_BANK_1; // 0x92 break; case 2: theSMBusMuxCommand = SMBUS_MUX_BANK_2; // 0x94 break; default:; } SMB0DAT = theSMBusMuxCommand; STA = 0; break; case 0x18: // ACK from slave was received for valid address. STO = 0; switch(theSMBusMuxChannel) { case DAQ_CHANNEL_OVEN1 : theSMBusMuxCommand = 0x08; // 0x08 | 0x00 break; case DAQ_CHANNEL_BLOWER : theSMBusMuxCommand = 0x09; // 0x08 | 0x01 break; default:; } SMB0DAT = theSMBusMuxCommand; break; case 0x20: // NACK was received from Slave. Retry Address. STO = 1; // Set Stop Mode STA = 1; // Set Start Master Mode. switch(theSMBusMuxBank){ case 0: theSMBusMuxCommand = SMBUS_MUX_BANK_0; // 0x90 break; case 1: theSMBusMuxCommand = SMBUS_MUX_BANK_1; // 0x92 break; case 2: theSMBusMuxCommand = SMBUS_MUX_BANK_2; // 0x94 break; default:; } SMB0DAT = theSMBusMuxCommand; break; case 0x28: // Data was sent to slave and received ACK back. STO = 0; // Done with the single channel data send to slave MUX. break; case 0x30: // Data was sent to slave and received NACK back. // Retry data send to slave MUX. // NOTE: NEED COUNTER HERE FOR NOT GETTING STUCK IN AN INFINATE LOOP. // And a global flag for indicating that this happened. switch(theSMBusMuxChannel) { case DAQ_CHANNEL_OVEN1 : theSMBusMuxCommand = 0x08; // 0x08 | 0x00 break; case DAQ_CHANNEL_BLOWER : theSMBusMuxCommand = 0x09; // 0x08 | 0x01 break; default:; } SMB0DAT = theSMBusMuxCommand; // Maybe need to reboot (book offers opinion.) break; case 0x38: // Arbitration lost. // Save Current data. // Nothing to do here for Master to Slave MUX devices. // ?? // Well maybe keep last value logged in sampling averaging.??? break; case 0x00: // Bus Error (Illegal Stop Start) STO = 1; // Reset Bus. break; case 0xF8: // IDLE - Does not set Interrupt; // NOTE: Can poll to send START. break; default:; } break; } case EXTERNAL_SMB_RTC: break; default:; } SI = 0; // Clear SMBus Interrupt. }
"Has anyone any comments on why this is failing?" You haven't actually stated in what way you think it's failing!
"It is really hard to track progress of this state machine without disrupting the bus for logging or stepping through the code/ISR." That's true of just about any real-time debugging! Have you tried just doing a "manual" code walk-through? You can do this as a pen-and-paper exercise, just following the code as you apply the appropriate events... You could do a similar thing in the simulator... Do you have a design in state charts, diagrams, or whatever? Have you tried walking through that to ensure that the design is correct? To trace real-time execution, you could write event & state info to some area of RAM, then examine that after a suitable period...
One thing that looks a little fishy, is that you enable the SMBus interrupt and call setupSMBusMuxBankAndChannel() which towards its end "Start[s] the setting of the Mux" (presumably all the action happens in the ISR), then immediately disable the SMBus interrupt upon returning. How can the ISR ever have a chance to do its work?
I thought the ISR would remain in effect until the state machine finishes in the ISR?
Or should I place a while(!done) loop wrapping the switch state machine?
Ok, I've changed some things and implemented a history buffer. The history buffer for thr entries are always 0x08 - bus start.??? Why not progressing?
#include <stdio.h> #include "c8051F020.h" #include "debug.h" #include "error.h" #include "errorCodesForSMBus.h" #include "externalSMBus.h" #include "externalSMBusADCMuxs.h" #include "sio.h" #include "systemGlobals.h" #include "utilityRoutines.h" int setupSMBusMuxBankAndChannel(void){ volatile int retVal; SMBusDevicesClass = EXTERNAL_SMB_MUXS; switch(theSMBusMuxBank){ case 0: theSMBusMuxBankSelectCommand = SMBUS_MUX_BANK_0; // 0x90 break; case 1: theSMBusMuxBankSelectCommand = SMBUS_MUX_BANK_1; // 0x92 break; case 2: theSMBusMuxBankSelectCommand = SMBUS_MUX_BANK_2; // 0x94 break; default:; } switch(theSMBusMuxChannel) { case DAQ_CHANNEL_OVEN1 : theSMBusMuxChannelSelectCommand = 0x08; // 0x08 | 0x00 break; case DAQ_CHANNEL_BLOWER : theSMBusMuxChannelSelectCommand = 0x09; // 0x08 | 0x01 break; default:; } resetSMBus0(); // ENSMB = 0; ENSMB = 1; SI = 0; // Start the setting of the Mux STO = 0; STA = 1; SMBusDone = FALSE; while (SMBusDone == FALSE){} return(retVal); } void SMBus_ISR(void) interrupt 7 using 2 { switch (SMBusDevicesClass){ { // Linear SMBus device LTC1380 case EXTERNAL_SMB_MUXS: switch(SMB0STA & 0xF8) { //---------------------------------------------------------------- // MASTER TRANSMITTER //---------------------------------------------------------------- case 0x08: // Start condition transmitted. #if (DEBUG_SMBUS_USE_HISTORY_BUFFER == 1) SMBusStateHistoryBuffer[SMBusHistoryLogIndex++] = 0x08; if (SMBusHistoryLogIndex == 50) while(1){} #endif SMB0DAT = theSMBusMuxBankSelectCommand; STA = 0; break; case 0x18: // ACK from slave was received for valid address. #if (DEBUG_SMBUS_USE_HISTORY_BUFFER == 1) SMBusStateHistoryBuffer[SMBusHistoryLogIndex++] = 0x18; if (SMBusHistoryLogIndex == 50) while(1){} #endif SMB0DAT = theSMBusMuxChannelSelectCommand; STO = 0; break; case 0x20: // NACK was received from Slave. Retry Address. #if (DEBUG_SMBUS_USE_HISTORY_BUFFER == 1) SMBusStateHistoryBuffer[SMBusHistoryLogIndex++] = 0x20; if (SMBusHistoryLogIndex == 50) while(1){} #endif STO = 1; // Set Stop Mode STA = 1; // Set Start Master Mode. SMB0DAT = theSMBusMuxBankSelectCommand; break; case 0x28: // Data was sent to slave and received ACK back. #if (DEBUG_SMBUS_USE_HISTORY_BUFFER == 1) SMBusStateHistoryBuffer[SMBusHistoryLogIndex++] = 0x28; if (SMBusHistoryLogIndex == 50) while(1){} #endif // STO = 0; // Done with the single channel data send to slave MUX. STO = 1; // Done with the single channel data send to slave MUX. BUSY = 0; // FROM an113 SiLabs SMBusDone = TRUE; break; case 0x30: // Data was sent to slave and received NACK back. // Retry data send to slave MUX. // NOTE: NEED COUNTER HERE FOR NOT GETTING STUCK IN AN INFINATE LOOP. // And a global flag for indicating that this happened. #if (DEBUG_SMBUS_USE_HISTORY_BUFFER == 1) SMBusStateHistoryBuffer[SMBusHistoryLogIndex++] = 0x28; if (SMBusHistoryLogIndex == 50) while(1){} #endif SMB0DAT = theSMBusMuxChannelSelectCommand; // Maybe need to reboot (book offers opinion.) break; case 0x38: // Arbitration lost. // Save Current data. // Nothing to do here for Master to Slave MUX devices. #if (DEBUG_SMBUS_USE_HISTORY_BUFFER == 1) SMBusStateHistoryBuffer[SMBusHistoryLogIndex++] = 0x38; if (SMBusHistoryLogIndex == 50) while(1){} #endif // ?? // Well maybe keep last value logged in sampling averaging.??? break; //---------------------------------------------------------------- // ALL. //---------------------------------------------------------------- case 0x00: // Bus Error (Illegal Stop Start) #if (DEBUG_SMBUS_USE_HISTORY_BUFFER == 1) SMBusStateHistoryBuffer[SMBusHistoryLogIndex++] = 0x00; if (SMBusHistoryLogIndex == 50) while(1){} #endif STO = 1; // Reset Bus. break; case 0xF8: // IDLE - Does not set Interrupt; // NOTE: Can poll to send START. #if (DEBUG_SMBUS_USE_HISTORY_BUFFER == 1) SMBusStateHistoryBuffer[SMBusHistoryLogIndex++] = 0xF8; if (SMBusHistoryLogIndex == 50) while(1){} #endif break; //---------------------------------------------------------------- // STATUS CODE NOT IDENTIFIED. //---------------------------------------------------------------- default:; } break; } case EXTERNAL_SMB_RTC: break; default:; } }
You clearly use a derivative with SMbus hardware interface. Such derivatives are NOT identical. Erik
Got it working. Anyway, SiLabs LTC1380 is the devices. What I last posted I just needed a SI=0; at the end of the ISR. Was very close. I was entering an infinite loop. The mux's are working correctly now.