Skip to main content
Visitor II
October 28, 2019
Question

HAL_SMBUS_Master_Transmit_IT XferOptions

  • October 28, 2019
  • 8 replies
  • 6301 views

Can someone explain which XferOptions should be used for which type of SMBUS message? This is what we get in stm32l4xx_hal_smbus.h:

/* List of XferOptions in usage of :

 * 1- Restart condition when direction change

 * 2- No Restart condition in other use cases

 */

#define SMBUS_FIRST_FRAME           SMBUS_SOFTEND_MODE

#define SMBUS_NEXT_FRAME            ((uint32_t)(SMBUS_RELOAD_MODE | SMBUS_SOFTEND_MODE))

#define SMBUS_FIRST_AND_LAST_FRAME_NO_PEC   SMBUS_AUTOEND_MODE

#define SMBUS_LAST_FRAME_NO_PEC        SMBUS_AUTOEND_MODE

#define SMBUS_FIRST_AND_LAST_FRAME_WITH_PEC  ((uint32_t)(SMBUS_AUTOEND_MODE | SMBUS_SENDPEC_MODE))

#define SMBUS_LAST_FRAME_WITH_PEC       ((uint32_t)(SMBUS_AUTOEND_MODE | SMBUS_SENDPEC_MODE))

    This topic has been closed for replies.

    8 replies

    Super User
    October 29, 2019

    I think those defines are not usually used except inside the SMBus STACK code. Where are you trying to use these, and with what SMBus function calls?

    Usually you use the st_command_t structure, and in that structure you set the "query" member to something like "READ", "WRITE", "READ_OR_WRITE", "BLOCK_READ", etc. (search for "STM32_SMBUS_STACK_Defines" [EDIT: fixed spelling of search term] way down in Middlewares\ST\STM32_SMBus_Stack\in\stm32_SMBUS_stack.h. Then you call STACK_SMBUS_HostCommand(). Or pass an array of these commands to STACK_SMBUS_Init().

    GrantWAuthor
    Visitor II
    October 30, 2019

    The simple answer is I'm trying to use the HAL_SMBUS_Master_Transmit_IT() call. The last argument is "uint32_t XferOptions" which seems to determine the message characteristics, so kind of important.

    Specifically, I am sending READ_WORD and WRITE_WORD commands to a Texas Instruments fuel gauge chip (bq40z80) mainly to capture data from it.

    I have looked at the stm32_SMBUS_stack code. I'm really not interested in trying to decipher that unless I am forced to. A user guide would be nice. Or if you are willing to answer lots of questions.

    Super User
    October 30, 2019

    > I'm really not interested in trying to decipher that unless I am forced to.

    Wow... so you would rather spend HOW much time trying to figure out how to use a lower level function?

    Quick snippet that I got from 10 or 20 minutes of looking at the sample SM and PMBus files from the ST app note code. Warning, this was typed, not copied from actual code. It may have typos and not be entirely correct. But you should get the gist.

    st_command_t BatteryModeCmd = {
     0x03, // SmartBattery "BatteryMode" command code
     READ_OR_WRITE, // This command can read current mode or write (some) new mode bits
     3, // WRITE sends 3 bytes: cmd code plus 16 bits of data
     2 // READ receives 2 bytes of data
    };
     
    SMBusStackHandleTypeDef smbusContext = { /*Your cfg data here*/ };
    HAL_StatusTypeDef sts;
     
    // This code presumes your fuel gauge response to the SmartBattery address 0x16
    // Read current battery mode
    sts = STACK_SMBUS_HostCommand( &smbusContext, &BatteryModeCmd, SMBUS_ADDR_SB, READ );
    if ( sts == HAL_OK ) {
     // Wait for transaction to finish. SMBus uses I2C interrupt functions
     while ( STACK_SMBUS_IsBusy(&smbusContext) ) {
     // twiddle your thumbs and check for timeout
     }
     uint8_t *pBuf = STACK_SMBUS_GetBuffer( &smbusContext );
     if ( pBuf != NULL ) {
     // 16-bit data is stored little-endian (LSB first). This matches the STM32 byte order.
     uint16_t mode = *(uint16_t *)pBuf;
     printf( "Battery mode 0x%x\n", mode );
     }
     else {
     // Oops, some error or SMBus still busy
     }
    }
    else {
     // REPORT ERROR HERE
    }

    To write data, get the buffer pointer as above and write the 16-bit data using the same kind of cast as above. The call STACK_SMBUS_HostCommand() with WRITE instead of READ.

    GrantWAuthor
    Visitor II
    October 30, 2019

    I appreciate your help Bob. I didn't think of the HAL_SMBUS functions as low-level. Am trying to get them to do something for me. Right now I am tracing through this call. Its returning HAL_ERROR. hsmbus3 has initialized successfully. We have tested the gas gauge with another device and it is responding.

    uint32_t busStatus = HAL_SMBUS_IsDeviceReady(&hsmbus3, cmdAddr, 10U, 500U);

    Visitor II
    March 2, 2020

    i have the same doubt , please share if you found the solution .

    Visitor II
    March 25, 2020

    1.When I was debugging mlx90615, I used smbus to communicate. The reading function was as follows:

    uint32_t I2C_Read_Cmd_Data (SMBUS_HandleTypeDef *hsmbus1, uint16_t chip, uint8_t *cmdBuffer, int32_t cmdBufferLen, uint8_t *dataBuffer, int32_t dataBufferLen)

    {

     uint32_t ret_code = I2C_OK;

     if(HAL_SMBUS_Master_Transmit_IT(hsmbus1, (uint16_t)chip, (uint8_t*)cmdBuffer, 1, SMBUS_FIRST_FRAME)!= HAL_OK)

     {

    while(1);

     }

    while(HAL_SMBUS_GetState(hsmbus1) != HAL_SMBUS_STATE_READY);

     if(HAL_SMBUS_Master_Receive_IT(hsmbus1, (uint16_t)chip, (uint8_t*)dataBuffer, 3,SMBUS_FIRST_AND_LAST_FRAME_WITH_PEC) != HAL_OK)

     {

    while(1);

     }

    while(HAL_SMBUS_GetState(hsmbus1) != HAL_SMBUS_STATE_READY);

      return ret_code;

    }

    but the measurement waveform found that there was always no ack in the last byte (pec), as shown below

    0693W000000UgI7QAK.jpg

    Would like to ask where the problem is, please answer, thank you very much

    2.As shown above, I have the following options for the last parameter(XferOptions) when using the HAL_SMBUS_Master_Transmit_IT function, the waveform will change when I modify it, I would like to ask how to configure this parameter, thank you!

    /* List of XferOptions in usage of :

     * 1- Restart condition when direction change

     * 2- No Restart condition in other use cases

     */

    #define SMBUS_FIRST_FRAME           SMBUS_SOFTEND_MODE

    #define SMBUS_NEXT_FRAME            ((uint32_t)(SMBUS_RELOAD_MODE | SMBUS_SOFTEND_MODE))

    #define SMBUS_FIRST_AND_LAST_FRAME_NO_PEC   SMBUS_AUTOEND_MODE

    #define SMBUS_LAST_FRAME_NO_PEC        SMBUS_AUTOEND_MODE

    #define SMBUS_FIRST_AND_LAST_FRAME_WITH_PEC  ((uint32_t)(SMBUS_AUTOEND_MODE | SMBUS_SENDPEC_MODE))

    #define SMBUS_LAST_FRAME_WITH_PEC       ((uint32_t)(SMBUS_AUTOEND_MODE | SMBUS_SENDPEC_MODE))

    /* List of XferOptions in usage of :

     * 1- Restart condition in all use cases (direction change or not)

     */

    #define SMBUS_OTHER_FRAME_NO_PEC        (0x000000AAU)

    #define SMBUS_OTHER_FRAME_WITH_PEC       (0x0000AA00U)

    #define SMBUS_OTHER_AND_LAST_FRAME_NO_PEC   (0x00AA0000U)

    #define SMBUS_OTHER_AND_LAST_FRAME_WITH_PEC  (0xAA000000U)

    Visitor II
    May 20, 2020

    Did you ever find out how the SMBus is handled properly?

    I'm having to control a simple LED driver over SMBus, and I don't understand why we need some parts for the code to begin with:

    	uint8_t statusBuffer[] = {
    		TCA6507_COMMAND_AUTOINC_SELECT,	// Start from SELECT0 and auto-increment
    		0x60,	// LED 6 and 7 should blink
    		0x60,	// LED 6 and 7 should blink
    		0x60	// LED 6 and 7 should blink
    	};
     
    	// Transmit the data to the device
    	if (HAL_SMBUS_Master_Transmit_IT(&hsmbus2, TCA6507_ADDRESS, statusBuffer,
    			sizeof(statusBuffer), SMBUS_FIRST_AND_LAST_FRAME_NO_PEC) != HAL_OK) {
    		// production code should return an error
    	}
     
    //	// Wait for the transmission to end
    //	while (HAL_SMBUS_GetState(&hsmbus2) != HAL_SMBUS_STATE_READY) {
    //		// Wait here
    //	}

    I have commented out lines 14-17. What is their purpose? Why are these needed, because like this, the LEDs do not light up. If I uncomment these lines, everything starts working again.

    Best regards

    Super User
    May 20, 2020

    HAL_SMBUS_Master_Transmit_IT() uses interrupts to send the data. It does NOT send the data before it returns to your code, it just starts the process. The lines you have commented out (lines 14-17) wait until the transfer is complete. I suspect that this code that you have shown is part of a function (i.e. not in main()). If you don't wait for the transfer to complete before exiting the function, your statusBuffer[] (which is allocated on the stack) will disappear and be overwritten during other function calls, thereby corrupting the data sent to the SMBus.

    Super User
    March 25, 2020

    First off - according to the SMBus spec, the PEC byte is ALWAYS NACKed to signal the end of the transmission (or the last data byte if not using PEC).

    Second - go find AN4502 and look at the STACK_SMBUS_HostCommand() function. That function encapsulates all the code for the entire transfer. You can use that function instead of stitching together lower-level SMBus function calls yourself, or just see which flags it sets.

    Visitor II
    March 27, 2020

    Bob:

    Thank you very much�?

    I have rewritten my code with reference to AN4502, I have a question, refer to the chip manual, after SCL produces a drop edge, there must be at least 300ns, SDA can be changed, but my measurement result is only 240ns, how should I set it here?

    0693W000000UrUxQAK.png0693W000000UrV2QAK.png

    Super User
    March 27, 2020

    What clock freq to you have feeding the I2C peripheral, and what have you programmed into the I2C_TIMINGR register? If you came up with these values on your own you might try using CubeMX to generate a dummy project and see what values it programs into I2C_TIMINGR (make sure to configure the clock tree in CubeMX to match your code).

    Visitor II
    March 28, 2020

    I have tried to modify the I2C clock frequency to 100K or 50K (according to the range setting given by the datasheet). The clock frequency of oscilloscope measurement SCL also conforms to the set value (50K or 100K), but the corresponding interval time (falling edge and SDA change) has not changed, which is still not in line with the specification.

    My program USES the framework generated automatically by stm32cubeMX.Now there is no train of thought, please help, thank you very much!