This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PM: SMBus slave not sending data

Part Number: TM4C123GH6PM

Hello,

I'm implementing a SMBus slave device with the libraries provided for SMBus communication (SMBus.h and SMBus.c).  I'm using an interrupt based approach and I'm using the base code provided in the SW-TM4C-UTILS-UG document as a template for my code. When the communication starts, the slave device is able to send the data correctly only on the first word. In subsequent read word operations, the slave is not sending the intended data and it's only sending 0xFF in every byte. I've been trying to figure it out, but so far no luck. I'd appreciate some help on this. Check the Slave ISR code below and a screenshoot of a piece of the SMBus capture. 

struct battData {
uint8_t voltage[2];
uint8_t current[2];
uint8_t relsoc[2];
uint8_t remCap[2];
uint8_t fullCap[2];
uint8_t time2empty[2];
uint8_t status[2];
uint8_t temperature[2];
};

struct battData battery = {{0x01,0x02},{0x03,0x04},{0x05,0x06},{0x07,0x08},{0x09,0x0A},{0x0B,0x0C},{0x0D,0x0E},{0x0F,0x10}};

void I2C0SlaveIntHandler(void){
    tSMBusStatus eStatus;
    eStatus = SMBusSlaveIntProcess(&g_sSlave);

    // See if the first byte/command was received.
    if(eStatus == SMBUS_SLAVE_FIRST_BYTE){

        switch(SMBusSlaveCommandGet(&g_sSlave)){

            case SMBUS_VOLTAGE:
            {
            SMBusSlaveTxBufferSet(&g_sSlave, battery.voltage, 2);
            break;
            }

            case SMBUS_CURRENT:
            {
            SMBusSlaveTxBufferSet(&g_sSlave, battery.current, 2);
            break;
            }

            case SMBUS_RELATIVE_STATE_OF_CHARGE:
            {
            SMBusSlaveTxBufferSet(&g_sSlave, battery.relsoc, 2);
            break;
            }

            case SMBUS_REMAINING_CAPACITY:
            {
            SMBusSlaveTxBufferSet(&g_sSlave, battery.remCap, 2);
            break;
            }

            case SMBUS_FULL_CHARGE_CAPACITY:
            {
            SMBusSlaveTxBufferSet(&g_sSlave, battery.fullCap, 2);
            break;
            }

            case SMBUS_RUN_TIME_TO_EMPTY:
            {
            SMBusSlaveTxBufferSet(&g_sSlave, battery.time2empty, 2);
            break;
            }

            case SMBUS_BATTERY_STATUS:
            {
            SMBusSlaveTxBufferSet(&g_sSlave, battery.status, 2);
            break;
            }

            case SMBUS_TEMPERATURE:
            {
            SMBusSlaveTxBufferSet(&g_sSlave, battery.temperature, 2);
            break;
            }
        }
    }

}
 
  • Hi,

      If you put a breakpoint in I2C0SlaveIntHandler, is the CPU halted when you are about the transmit the "FF" data?

      What does eStatus  return?

  • Hi Charles,

    The ISR is being executed every time data is received. eStatus is returning SMBUS_SLAVE_FIRST_BYTE as expected. Additionally, I toggled GPIOs inside every case in the switch statement to make sure the commands were being detected and they are. The screenshoot below show another debugging I did. Channel 2 (red marker) should go high if eStatus returns SMBUS_SLAVE_NOT_READY and as you can see is always low. Channel 3 toggles every time sStatus returns SMBUS_TRANSFER_COMPLETE. So, in general everything looks good and yet, data is not being send accordingly. 

  • Alberto,

      I'm still trying to make sense myself. From what I can tell by comparing a TM4C129 and a TM4C123 datasheet, the TM4C123 MCU doesn't seem to support SMbus, at least as a master. There is a section about SMbus in the TM4C129 datasheet and an elaborate register description on how to support SMbus but this is nowhere to be found in the TM4C123 MCU. SMbus is not supported at least from a SMbus master point of view. As for slave, I don't know what is the problem that it is sending 0xFF as I'm not very familiar with smbus.c file myself. 

      Can you single-step through SMBusSlaveIntProcess starting at line 3994 and compare between when the first two bytes are transferred successfully vs the next two bytes where they are transferred as 0xFF. I wonder if some condition is not met and result in 0xFF getting transferred. 

  • Charles,

    The problem is that the state machine is getting stuck in the SMBUS_STATE_WRITE_DONE state. In SMBus.c line 4294 you can see that there is no assignment to a next state, therefore, the slave is sending 0xFF all the time. This seems like a bug. What do you advice? 

  • Hi,

     I must say that I don't have much experience with SMbus in general. This is the first time I'm reading the smbus.c. This file has been in the TivaWare SDK for a very long time and it is carried over from a prior generation of Stellaris MCU. Although hardly used by customers (you are probably the first person to raise a question about smbus.c in the last few years), I tend to think it should be thoroughly tested. Perhaps it may have something to do how to properly use the SMbus stack but I don't really know what is wrong with your current situation. 

      Having said that, I think SMBusSlaveTxBufferSet() seems to only put data in the tx buffer. It does not initiate a I2C bus transaction. I wonder how the transaction is started if you break out immediately after calling SMBusSlaveTxBufferSet. Can you do an experiment to call SMBusSlaveIntProcess after SMBusSlaveTxBufferSet. I wonder what does that do. 

  • Hi Charles,

    I was able to make it work. There is an API named SMBusSlaveTransferInit that needs to be called every time a SMBus transfer is complete. Unfortunately, this isn't mentioned anywhere. There is plenty of room for improvement when it comes down to the documentation in general. The ISR code is as shown below:

    void I2C0SlaveIntHandler(void){
        tSMBusStatus eStatus;
        eStatus = SMBusSlaveIntProcess(&g_sSlave);
    
        // See if the first byte/command was received.
        if(eStatus == SMBUS_SLAVE_FIRST_BYTE){
    
            switch(SMBusSlaveCommandGet(&g_sSlave)){
    
                case SMBUS_VOLTAGE:
                {
                SMBusSlaveTxBufferSet(&g_sSlave, battery.voltage, 2);
                break;
                }
    
                case SMBUS_CURRENT:
                {
                SMBusSlaveTxBufferSet(&g_sSlave, battery.current, 2);
                break;
                }
    
                case SMBUS_RELATIVE_STATE_OF_CHARGE:
                {
                SMBusSlaveTxBufferSet(&g_sSlave, battery.relsoc, 2);
                break;
                }
    
                case SMBUS_REMAINING_CAPACITY:
                {
                SMBusSlaveTxBufferSet(&g_sSlave, battery.remCap, 2);
                break;
                }
    
                case SMBUS_FULL_CHARGE_CAPACITY:
                {
                SMBusSlaveTxBufferSet(&g_sSlave, battery.fullCap, 2);
                break;
                }
    
                case SMBUS_RUN_TIME_TO_EMPTY:
                {
                SMBusSlaveTxBufferSet(&g_sSlave, battery.time2empty, 2);
                break;
                }
    
                case SMBUS_BATTERY_STATUS:
                {
                SMBusSlaveTxBufferSet(&g_sSlave, battery.status, 2);
                break;
                }
    
                case SMBUS_TEMPERATURE:
                {
                SMBusSlaveTxBufferSet(&g_sSlave, battery.temperature, 2);
                break;
                }
                
            }
        }
        else if(eStatus == SMBUS_TRANSFER_COMPLETE){
                SMBusSlaveTransferInit(&g_sSlave);
            }
    }

  • Hi Alberto,

      Thank you very much for your investigation into the SMBusSlaveTransferInit requirement. Understand that the documentation is a bit lacking. If anything, I also learn something new for my own. I will bookmark this post for future reference.