I3C (bus) using in STM32H5 series

前言

MIPI在I2C的基礎上誕生了I3C,它與I2C一樣使用兩根線,並且支援IBI中斷和熱拔插,同時頻率可以達到較高的頻率,因為它與I2C不同,I2C兩根引腳使用的 是開漏輸出,開漏內部接地是無法輸出高電平的,如果需要輸出高電平必須外接上拉電阻才能實現高電平輸出,但是電阻會阻礙電流導通,所以會比較耗時,I2C 最高也才達到5MB,但I3C可達12.5MB,且功能比I2C強大許多且它支援I2C,向前相容。

I3C Bus介紹

MIPI I3C 結合了傳統I2C和SPI介面的關鍵屬性,以提供統一的、高效能、極低功耗的解決方案。
I3C介面使用的跟I2C類似,也是一條漏級數據線(SDA)和一條推挽式時脈線(SCL),該SDA線上的從設備可以控制資料匯流排,並且可以啟動中斷。
主控透過此SCL線可以將匯流排的時脈頻率調節到12.5MHZ。I3C支援多種類型設備,包括Main Master(目前主設備),secondary master(輔助主設備)、I3C Slave、I2C Slave。

I2C Vs I3C

與 I2C 模式相比,I3C 還降低了功耗,並在 12.5MHz 下提供了更高的資料速率。

I3C仍然支援I2C的ACK確認方式,只是某些情況下I3C要求只能使用I3C的方式來進行ACK,這麼做的目的是忽略掉總線上I2C的設備, 例如分配動態位址是時不想讓I2C設備參與進來那麼久使用這個方式來忽略掉I2C設備,因為傳統I2C設備只會在SCL拉高時來確認ACK,如果I3C將SCL拉低那麼I2C設備會把此 次通訊視為沒有ACK訊息視為失敗則放棄本次通訊

I3C dedicated VDDIO2 supply pin

專用電源接腳 VDDIO2 降至 1.08V。 因此,包括I3C在內的所有這些通訊介面都可以工作電壓為 1.2V

STM32CubeMX – I3C 配置

Bus characteristics

這邊針對2個case計算配置

  • The examples using the sensor shield can reach only 3MHz
  • The examples using Nucleo boards can reach maximum I3C frequency: 12.5 MHz

Sample code

這邊以ST官方這邊提供6種模式範例提供選擇依照客戶需求確認即可

  /* Assign dynamic address processus */
  if (HAL_I3C_Ctrl_DynAddrAssign_IT(&hi3c1, I3C_ONLY_ENTDAA) != HAL_OK)
  {
    /* Error_Handler() function is called when error occurs. */
    Error_Handler();
  }

  /*##- Wait for the end of the transfer ############################################*/
  /*  Before starting a new communication transfer, you need to check the current
  state of the peripheral; if it's busy you need to wait for the end of current
  transfer before starting a new one.
  For simplicity reasons, this example is just waiting till the end of the
  transfer, but application may perform other tasks while transfer operation
  is ongoing. */
  while (HAL_I3C_GetState(&hi3c1) != HAL_I3C_STATE_READY)
  {
  }

  /*##- Prepare context buffers process #############################################*/
  /* Prepare context buffer with the different parameters */
  aContextBuffers[I3C_IDX_FRAME_1].CtrlBuf.pBuffer = aControlBuffer;
  aContextBuffers[I3C_IDX_FRAME_1].CtrlBuf.Size    = COUNTOF(aControlBuffer);
  aContextBuffers[I3C_IDX_FRAME_1].RxBuf.pBuffer   = aRxBuffer;
  aContextBuffers[I3C_IDX_FRAME_1].RxBuf.Size      = 14;

  aContextBuffers[I3C_IDX_FRAME_2].CtrlBuf.pBuffer = aControlBuffer;
  aContextBuffers[I3C_IDX_FRAME_2].CtrlBuf.Size    = COUNTOF(aControlBuffer);
  aContextBuffers[I3C_IDX_FRAME_2].TxBuf.pBuffer   = aTxBuffer;
  aContextBuffers[I3C_IDX_FRAME_2].TxBuf.Size      = 4;

  /*##- Add context buffer Get CCC frame in Frame context ###########################*/
  if (HAL_I3C_AddDescToFrame(&hi3c1,
                             aGET_CCCList,
                             NULL,
                             &aContextBuffers[I3C_IDX_FRAME_1],
                             COUNTOF(aGET_CCCList),
                             I3C_DIRECT_WITHOUT_DEFBYTE_RESTART) != HAL_OK)
  {
    /* Error_Handler() function is called when error occurs. */
    Error_Handler();
  }
/*##- Start the reception process #################################################*/
  /* Receive CCC data processus */
  if (HAL_I3C_Ctrl_ReceiveCCC_DMA(&hi3c1, &aContextBuffers[I3C_IDX_FRAME_1]) != HAL_OK)
  {
    /* Error_Handler() function is called when error occurs. */
    Error_Handler();
  }

  /*##- Wait for the end of the transfer ############################################*/
  /*  Before starting a new communication transfer, you need to check the current
  state of the peripheral; if it's busy you need to wait for the end of current
  transfer before starting a new one.
  For simplicity reasons, this example is just waiting till the end of the
  transfer, but application may perform other tasks while transfer operation
  is ongoing. */
  while (HAL_I3C_GetState(&hi3c1) != HAL_I3C_STATE_READY)
  {
  }

  /*##- Monitor the different value retrieve during CCC get #########################*/
  /*  At the end, of transfer, the application have retrieve all the data of
  the frame in an unique buffer, which must be unfill to retrieve the associated
  value for each get CCC command. */
  /* Display through external Terminal IO the Get CCC associated value received */
  DisplayCCCValue(aGET_CCCList, &aCommandCode[0], &aRxBuffer[0], COUNTOF(aGET_CCCList));

  /*##- Add context buffer Set CCC frame in Frame context ###########################*/
  if (HAL_I3C_AddDescToFrame(&hi3c1,
                             aSET_CCCList,
                             NULL,
                             &aContextBuffers[I3C_IDX_FRAME_2],
                             COUNTOF(aSET_CCCList),
                             I3C_DIRECT_WITHOUT_DEFBYTE_RESTART) != HAL_OK)
  {
    /* Error_Handler() function is called when error occurs. */
    Error_Handler();
  }

Leave a Comment

Your email address will not be published. Required fields are marked *

Shopping Cart