HAL I2C Use Cases

Prerequisite

@startuml
==Prerequisite==

participant App as "User application"
participant "HAL GENERIC" as GENERIC
participant "HAL RCC" as RCC

App -> GENERIC : HAL_Init
GENERIC --> App 
App -> RCC : Configure system clock
RCC --> App
@enduml

Full I2C Initialization Sequence

@startuml

participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
participant "HAL CORTEX\n(NVIC)" as CORTEX
participant "HAL DMA" as DMA
participant "HAL RCC" as RCC
participant "HAL GPIO" as GPIO

==I2C HAL Initialization  ==
App -> I2C : HAL_I2C_Init
alt#grey #lightgrey If USE_HAL_I2C_CLK_ENABLE_MODEL > HAL_CLK_ENABLE_NO
I2C->RCC : Enable the I2C clock
RCC-->I2C
end
App <-- I2C : HAL_OK

==I2C System Initialization==
Note over I2C : I2C System initialization can be called before\nI2C HAL initialization

alt#grey #lightgrey If USE_HAL_I2C_DMA == 1
App->DMA : Initialization of DMA
DMA-->App
App->I2C : HAL_I2C_SetTxDMA / HAL_I2C_SetRxDMA
DMA-->App
end

alt#grey #lightgrey If Interrupt needed
App->CORTEX : Enable needed Interrupt
CORTEX-->App
end

alt#grey #lightgrey If GPIO(s) needed
App->GPIO : Initialization of GPIOs
GPIO-->App
end

alt#grey #lightgrey If USE_HAL_I2C_CLK_ENABLE_MODEL == HAL_CLK_ENABLE_NO
App->RCC : Enable the I2C clock
RCC --> App
end

==I2C Configuration==
App -> I2C : HAL_I2C_SetConfig
App <-- I2C :HAL_OK

note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
==Advanced I2C Configuration==
App -> I2C : HAL_I2C_EnableAnalogFilter
App <-- I2C :HAL_OK
App -> I2C : HAL_I2C_SetConfigXXX
App <-- I2C :HAL_OK
App -> I2C : HAL_I2C_EnableXXX
App <-- I2C :HAL_OK
@enduml

Called functions:

Full I2C Deinitialization Sequence

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
participant "HAL CORTEX\n(NVIC)" as CORTEX
participant "HAL DMA" as DMA
participant "HAL RCC" as RCC
participant "HAL GPIO" as GPIO

==I2C DeInitialisation==
App->I2C : HAL_I2C_DeInit
App<--I2C

==I2C system DeInitalization==
alt#grey #lightgrey If USE_HAL_I2C_DMA == 1
App->DMA : DeInitialization of DMA
DMA-->App
end

alt#grey #lightgrey If Interrupt needed
App->CORTEX : Disable needed Interrupt
CORTEX-->App
end

alt#grey #lightgrey If GPIO(s) needed
App->GPIO : DeInitialization of GPIOs
GPIO-->App
end

App->RCC : Disable the I2C clock
RCC --> App
@enduml

Called functions:

Process Polling

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C

==Process :  Master Transmit Polling==
App -> I2C : HAL_I2C_MASTER_Transmit(...,uint32_t timeout_ms)

alt successful case
   App <-- I2C : HAL_OK
else invalid param
   App <-- I2C : HAL_INVALID_PARAM
else busy
   App <-- I2C : HAL_BUSY
   note over App : Another Process is running...\nPlease wait and retry.
else timeout 
   App <-- I2C : HAL_TIMEOUT
else error case 
   App <-- I2C : HAL_ERROR
App -> I2C : \

alt#grey #lightgrey If USE_HAL_I2C_GET_LAST_ERRORS == 1
App->I2C : HAL_I2C_GetLastErrors()
App <-- I2C : \
(HAL_I2C_ERROR_XXX | HAL_I2C_ERROR_YYY)
end

end
note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Process Master Transmit IT

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C

==Process :  Master Transmit IT==
App -> I2C : HAL_I2C_MASTER_Transmit_IT(handle, addr, &buffer,\n size_in_byte = N)
App <-- I2C : HAL_OK
...
loop while (size-- != 0)
   "I2Cx_IRQHandler" <- : I2Cx interrupt TXIS, Byte 1 ... Byte N 
   I2C <- "I2Cx_IRQHandler" : HAL_I2C_EV_IRQHandler
   note over I2C : I2C_Master_ISR()
   alt if (size-- != 0)
      note over I2C : buffer++;\nTXDR = buffer[0];
   end
   I2C --> "I2Cx_IRQHandler"
   "I2Cx_IRQHandler" -->
end
...
"I2Cx_IRQHandler" <- : I2Cx interrupt STOP
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : Clear Flag STOP
App <- I2C : HAL_I2C_MASTER_TxCpltCallback
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->

note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Process Slave Transmit IT

@startuml
==Process :  Slave Transmit IT==
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C

App -> I2C : HAL_I2C_SLAVE_Transmit_IT(handle, addr, &buffer,\n size_in_byte = N)
App <-- I2C : HAL_OK
...
"I2Cx_IRQHandler" <- : I2Cx interrupt ADDR
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : Clear Flag ADDR
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->
...


loop while (size-- != 0)
   "I2Cx_IRQHandler" <- : I2Cx interrupt TXIS, Byte 1 ... Byte N 
   I2C <- "I2Cx_IRQHandler" : HAL_I2C_EV_IRQHandler
   note over I2C : I2C_Slave_ISR()
   alt if (size-- != 0)
      note over I2C : buffer++;\nTXDR = buffer[0];
   end
   I2C --> "I2Cx_IRQHandler"
   "I2Cx_IRQHandler" -->
end
...
"I2Cx_IRQHandler" <- : I2Cx interrupt STOP
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : Clear Flag STOP
App <- I2C : HAL_I2C_SLAVE_TxCpltCallback
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->

note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Slave Receive IT

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C

==Process :  Slave Receive IT==
App -> I2C : HAL_I2C_SLAVE_Receive_IT(handle, addr, &buffer,\n size_in_byte = N)
App <-- I2C : HAL_OK
...
"I2Cx_IRQHandler" <- : I2Cx interrupt ADDR
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : Clear Flag ADDR
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->
...
loop while (size-- != 0)
   "I2Cx_IRQHandler" <- : I2Cx interrupt RXNE\nByte 1 ...  Byte N
   I2C <- "I2Cx_IRQHandler" : HAL_I2C_EV_IRQHandler
   note over I2C : I2C_Slave_ISR()
   alt if (size-- != 0)
      note over I2C : buffer++;\nbuffer[0] = RXDR;
   end
   I2C --> "I2Cx_IRQHandler"
   "I2Cx_IRQHandler" -->
end
...
"I2Cx_IRQHandler" <- : I2Cx interrupt STOP
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : Clear Flag STOP
App <- I2C : HAL_I2C_SLAVE_RxCpltCallback
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->

note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Master Mode IT

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
==Process :  Master Mode. Send CMD M bytes + Receive N bytes ==

App -> I2C : HAL_I2C_MASTER_SEQ_Transmit_IT(handle, addr, &buffer,\n size_in_byte = M, I2C_FIRST_FRAME)
App <-- I2C : HAL_OK
...
loop while (size-- != 0)
   "I2Cx_IRQHandler" <- : I2Cx interrupt TXIS\nCMD Byte 1 ... CMD Byte M 
   I2C <- "I2Cx_IRQHandler" : HAL_I2C_EV_IRQHandler
   note over I2C : I2C_Master_ISR()
   alt if (size-- != 0)
      note over I2C : buffer++;\nTXDR = buffer[0];
   else else
      App <- I2C : HAL_I2C_MASTER_TxCpltCallback
      App --> I2C
   end

   I2C --> "I2Cx_IRQHandler"
   "I2Cx_IRQHandler" -->
end
...
App -> I2C : HAL_I2C_MASTER_SEQ_Receive_IT(handle, addr, &buffer,\n size_in_byte = N bytes, I2C_LAST_FRAME)
App <-- I2C : HAL_OK
...
loop while (size-- != 0)
   "I2Cx_IRQHandler" <- : I2Cx interrupt RXNE\nByte 1 ...  Byte N
   I2C <- "I2Cx_IRQHandler" : HAL_I2C_EV_IRQHandler
   note over I2C : I2C_Master_ISR()
   alt if (size-- != 0)
      note over I2C : buffer++;\nbuffer[0] = RXDR;
   end
   I2C --> "I2Cx_IRQHandler"
   "I2Cx_IRQHandler" -->
end
...
"I2Cx_IRQHandler" <- : I2Cx interrupt STOP
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : Clear Flag STOP
App <- I2C : HAL_I2C_MASTER_RxCpltCallback
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->

note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Slave Mode IT

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
==Process :  Slave Mode. Receive CMD M bytes + Send N bytes ==

App -> I2C : HAL_I2C_SLAVE_EnableListen_IT(handle)
note over I2C : Enable ADDRI, STOPI, NACKI, ERRI
App <-- I2C : HAL_OK
...
"I2Cx_IRQHandler" <- : I2Cx interrupt ADDR, DIR=Wr
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : I2C_Slave_ISR()
App <- I2C : HAL_I2C_SLAVE_AddrCallback(handle,\nDirection=Write, Addr Match code)
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->
...
App -> I2C : HAL_I2C_SLAVE_SEQ_Receive_IT(handle, addr, &buffer,\n size_in_byte = M, I2C_FIRST_FRAME)
App <-- I2C : HAL_OK
...
loop while (size-- != 0)
   "I2Cx_IRQHandler" <- : I2Cx interrupt RXNE, CMD Byte 1 ... CMD Byte M 
   I2C <- "I2Cx_IRQHandler" : HAL_I2C_EV_IRQHandler
   note over I2C : I2C_Slave_ISR()
   alt if (size-- != 0)
      note over I2C : buffer++;\nbuffer[0] = RXDR;
   else else
      App <- I2C : HAL_I2C_SLAVE_RxCpltCallback
      App --> I2C
   end
   I2C --> "I2Cx_IRQHandler"
   "I2Cx_IRQHandler" -->
end
...
"I2Cx_IRQHandler" <- : I2Cx interrupt ADDR, DIR=Rd
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : I2C_Slave_ISR()
App <- I2C : HAL_I2C_SLAVE_AddrCallback(handle,\nDirection=Read, Addr Match Code)
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->
...
App -> I2C : HAL_I2C_SLAVE_SEQ_Transmit_IT(handle, addr, &buffer,\n size_in_byte = N, I2C_LAST_FRAME)
App <-- I2C : HAL_OK
...
loop while (size-- != 0)
   "I2Cx_IRQHandler" <- : I2Cx interrupt TXIS, Byte 1 ... Byte N 
   I2C <- "I2Cx_IRQHandler" : HAL_I2C_EV_IRQHandler
   note over I2C : I2C_Slave_ISR()
   alt if (size-- != 0)
      note over I2C : buffer++;\nTXDR = buffer[0];
   else else
      App <- I2C : HAL_I2C_SLAVE_TxCpltCallback
      App --> I2C
   end
   I2C --> "I2Cx_IRQHandler"
   "I2Cx_IRQHandler" -->
end
...
"I2Cx_IRQHandler" <- : I2Cx interrupt STOP
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
note over I2C : Clear Flag STOP
App <- I2C : HAL_I2C_SLAVE_ListenCpltCallback
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->

note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Process DMA

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
==Process :  Master Transmit DMA==

participant App
participant I2C
participant "I2Cx_IRQHandler"
participant "HAL DMA driver"
participant "DMAx_IRQHandler"

App -> I2C : HAL_I2C_MASTER_Transmit_DMA
I2C-> "HAL DMA driver" : HAL_DMA_Start_IT
"HAL DMA driver" --> I2C : HAL_OK
App <-- I2C : HAL_OK

"DMAx_IRQHandler" <- : DMAx complete interrupt
"DMAx_IRQHandler" -> "HAL DMA driver" : HAL_DMA_IRQHandler
"HAL DMA driver" -> I2C : XferCpltCallback
"HAL DMA driver" <-- I2C
"DMAx_IRQHandler" <-- "HAL DMA driver"
"DMAx_IRQHandler" -->

"I2Cx_IRQHandler" <- : I2Cx Stop complete interrupt
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
I2C-> App : HAL_I2C_MASTER_TxCpltCallback
I2C<-- App
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->

note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Process Abort IT

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
==Process abort : Master Transmit asynchrone (IT)\n==

App -> I2C : HAL_I2C_MASTER_Transmit_IT
App <-- I2C : HAL_OK
...
App -> I2C : HAL_I2C_MASTER_Abort_IT
App <-- I2C : HAL_OK
...
"I2Cx_IRQHandler" <- : I2Cx Stop complete interrupt
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
App <- I2C : HAL_I2C_AbortCpltCallback
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->


note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Process Abort DMA

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
==Process abort : Master Transmit asynchrone (DMA)\n==

App -> I2C : HAL_I2C_MASTER_Transmit_DMA
App <-- I2C : HAL_OK
...
App -> I2C : HAL_I2C_MASTER_Abort_IT

I2C -> "HAL DMA driver" : HAL_DMA_Abort_IT 
I2C <-- "HAL DMA driver" : HAL_OK

App <-- I2C : HAL_OK
...
"DMAx_IRQHandler" <- : DMAx interrupt
I2C <- "DMAx_IRQHandler" : I2C_DMAAbort
I2C --> "DMAx_IRQHandler"
"DMAx_IRQHandler" -->

...
"I2Cx_IRQHandler" <- : I2Cx Stop complete interrupt
"I2Cx_IRQHandler" -> I2C : HAL_I2C_EV_IRQHandler
App <- I2C : HAL_I2C_AbortCpltCallback
App --> I2C
"I2Cx_IRQHandler" <-- I2C
"I2Cx_IRQHandler" -->


note over App : Driver state is IDLE,\nUser can start any process or execute any configuration.
@enduml

Called functions:

Recoverable Blocking Error

@startuml
participant App as "User application"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
==Process recoverable blocking error : Master Transmit asynchrone (IT or DMA)\n ==

App -> I2C : HAL_I2C_MASTER_Transmit_IT/DMA
App <-- I2C : HAL_OK
...
I2C <- :  I2Cx or DMAx recoverable error interrupt
App <-[#Orange] I2C :\
<color #Orange> HAL_I2C_ErrorCallback(&hi2c) </color>

alt#grey #lightgrey If USE_HAL_I2C_GET_LAST_ERRORS == 1
App->I2C : HAL_I2C_GetLastErrorCodes()
App <-- I2C : \
(HAL_I2C_ERROR_XXX | HAL_I2C_ERROR_YYY)
end

App [#Orange]--> I2C
I2C -->

note over App : Driver state is IDLE,\nUser can start any process or execute\n any configuration.
@enduml

Called functions:

Acquire/Release

@startuml

participant "User 1"
participant "User 2"
participant "<font color=green><b>HAL I2C</b></font>" as I2C
participant "HAL OS wrapper"

"User 1"-[#green]>I2C : <color #green>HAL_I2C_AcquireBus</color>
I2C-[#green]>"HAL OS wrapper" :<color #green>HAL_OS_SemaphoreTake</color>
I2C <-[#green]- "HAL OS wrapper"
"User 1" <-[#green]- I2C : <color #green>HAL_OK</color>

note over I2C : Bus acquired by user 1. Any Process can be executed.\nFor instance : Master Transmit Polling

"User 2"-[#red]>I2C : <color #red>HAL_I2C_AcquireBus</color>
I2C-[#red]>"HAL OS wrapper" :<color #red>HAL_OS_SemaphoreTake</color>

"User 1"-[#green]>I2C : <color #green>HAL_I2C_ReleaseBus</color>
"User 1" <-[#green]- I2C : <color #green>HAL_OK</color>

I2C <-[#red]- "HAL OS wrapper"
"User 2" <-[#red]- I2C : <color #red>HAL_OK</color>

note over I2C : Bus acquired by user 2. Any Process can be executed.\nFor instance : Master Transmit Polling
@enduml

Called functions: