mohammadsdtmnd
mohammadsdtmnd

Reputation: 390

what's the application of sequential transmission of I2C in HAL library in STM32f746ng

I can understand that you can use first frame option for first frame and next frame options for others, but since you can use them as FIRS_FRAME_LAST_FRAME, what is the advantage of other? and when we must use them?

Findings: A code use wile to continuously transmit two number and get a callback to see if module has accepted that, if this happen correctly the led must blink.

In this simple code I've tested every xferoption of sequential transmission, every options worked except: I2C_LAST_FRAME_NO_STOP and I2C_FIRST_FRAME. Code:

while (1)
  {
      value=300;
      *(uint16_t*) buffer=(value<<8)|(value>>8);//Data prepared for DAC module
      HAL_I2C_Master_Seq_Transmit_IT (&hi2c1, (MCP4725A0_ADDR_A00<<1), buffer, 2,I2C_LAST_FRAME_NO_STOP);
      HAL_Delay(1);
      HAL_I2C_Master_Receive(&hi2c1, (MCP4725A0_ADDR_A00<<1), rxbuffer, 3, 1000);
      if( (uint16_t)(((uint16_t)rxbuffer[1])<<8|((uint16_t)rxbuffer[2]))>>4 == value ){
          HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);}

      HAL_Delay(50);

      value=4000;
      *(uint16_t*) buffer=(value<<8)|(value>>8);
      HAL_I2C_Master_Seq_Transmit_IT (&hi2c1, (MCP4725A0_ADDR_A00<<1), buffer, 2,I2C_LAST_FRAME_NO_STOP);
      HAL_Delay(1);
      HAL_I2C_Master_Receive(&hi2c1, (MCP4725A0_ADDR_A00<<1), rxbuffer, 3, 1000);
      if( (uint16_t)(((uint16_t)rxbuffer[1])<<8|((uint16_t)rxbuffer[2]))>>4 == value ){
          HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);}

      HAL_Delay(50);
}

Upvotes: 3

Views: 2239

Answers (1)

Adehad
Adehad

Reputation: 579

The HAL sometimes poorly documents these variables functions, and you will need to dive into the reference manual !

Looking at what the #defines are

https://github.com/STMicroelectronics/STM32CubeF7/blob/f8bda023e34ce9935cb4efb9d1c299860137b6f3/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c.h#L302-L307

/** @defgroup I2C_XFEROPTIONS  I2C Sequential Transfer Options
  * @{
  */
#define I2C_FIRST_FRAME                 ((uint32_t)I2C_SOFTEND_MODE)
#define I2C_FIRST_AND_NEXT_FRAME        ((uint32_t)(I2C_RELOAD_MODE | I2C_SOFTEND_MODE))
#define I2C_NEXT_FRAME                  ((uint32_t)(I2C_RELOAD_MODE | I2C_SOFTEND_MODE))
#define I2C_FIRST_AND_LAST_FRAME        ((uint32_t)I2C_AUTOEND_MODE)
#define I2C_LAST_FRAME                  ((uint32_t)I2C_AUTOEND_MODE)
#define I2C_LAST_FRAME_NO_STOP          ((uint32_t)I2C_SOFTEND_MODE)

We can see references to RELOAD and AUTOEND and SOFTEND.

Digging into the reference manual

https://www.st.com/resource/en/reference_manual/rm0385-stm32f75xxx-and-stm32f74xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf#page=969

i2c reference manual page, looking at the AUTOEND and RELOAD bit

So we can see here the reference to

  1. AUTOEND - as a way to automatically implement a STOP condition after the set bytes end
  2. SOFTEND as a way to prevent the automatic STOP condition and require the software to decide.

Relationship to your observed behaviour

  1. The define's using the SOFTEND mode is where you saw things not working, and this is to be expected, the I2C protocol was not being fulfilled as there was nothing in the code to indicate the STOP condition.

So what does this mean you can do - an example of a variable byte i2c slave receiver

I haven't found a shining example from ST for this, but let me illustrate an example I have implemented in a project for an I2C Slave.

Let us look at the callbacks that are called:

https://github.com/STMicroelectronics/STM32CubeF7/blob/master/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c.c#L76-L97

*** Interrupt mode IO operation ***
===================================
[..]
  (+) Transmit in master mode an amount of data in non-blocking mode using HAL_I2C_Master_Transmit_IT()
  (+) At transmission end of transfer, HAL_I2C_MasterTxCpltCallback() is executed and users can
       add their own code by customization of function pointer HAL_I2C_MasterTxCpltCallback()
  (+) Receive in master mode an amount of data in non-blocking mode using HAL_I2C_Master_Receive_IT()
  (+) At reception end of transfer, HAL_I2C_MasterRxCpltCallback() is executed and users can
       add their own code by customization of function pointer HAL_I2C_MasterRxCpltCallback()
  (+) Transmit in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Transmit_IT()
  (+) At transmission end of transfer, HAL_I2C_SlaveTxCpltCallback() is executed and users can
       add their own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback()
  (+) Receive in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Receive_IT()
  (+) At reception end of transfer, HAL_I2C_SlaveRxCpltCallback() is executed and users can
       add their own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback()
  (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and users can
       add their own code by customization of function pointer HAL_I2C_ErrorCallback()
  (+) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT()
  (+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and users can
       add their own code by customization of function pointer HAL_I2C_AbortCpltCallback()
  (+) Discard a slave I2C process communication using __HAL_I2C_GENERATE_NACK() macro.
       This action will inform Master to generate a Stop condition to discard the communication.

Therefore, you could implement a I2C slave that could read a variable/dynamic amount of data:

  1. Receive 1 byte - using the SOFTEND based options
  2. This prevents the stop condition being raised, but once this first byte is received will trigger the HAL_I2C_SlaveRxCpltCallback().
  3. In the HAL_I2C_SlaveRxCpltCallback() check the value of the first byte and then request more data of any further length, but this time using an AUTOEND based option.

Upvotes: 3

Related Questions