cancel
Showing results for 
Search instead for 
Did you mean: 

I2C implementation based on freeRTOS OS

Micha Valach
Associate III

Hello,

I'm using STM32WB55 in conjunction with freeRTOS OS

I found a very good I2C BARE-METAL working example located at:

..\STM32Cube\Repository\STM32Cube_FW_WB_V1.12.1\Projects\P-NUCLEO-WB55.Nucleo\Examples\I2C\I2C_TwoBoards_AdvComIT

I'm looking for a similar I2C Example, however based on and using

freeRTOS implementation

Thanks In Advance,

Micha

1 ACCEPTED SOLUTION

Accepted Solutions
Micha Valach
Associate III

Hi KnafB,

Thanks you very much for your GREAT advise :smiling_face_with_smiling_eyes: !!!

The original I2C example is based on HAL functions: HAL_I2C_Master_Transmit_IT() and HAL_I2C_Master_Receive_IT

I added freeRTOS with CMSIS_V2 (from CubeMX) + one I2C task, copy the I2C functionality from Main loop to the I2C task, DONE - ALL work like a charm !!!

Many Thanks

Best Regards,

Micha

View solution in original post

6 REPLIES 6
KnarfB
Principal III

The FreeRTOS middleware is just the RTOS kernel, i.e. scheduler + synchronisation objects, no peripherals API. So you just use HAL as in the above example from a FreeRTOS task. HAL is not aware of RTOS, so the timing might be different (when the task is not running).

hth

KnarfB

Micha Valach
Associate III

Hi KnarfB,

Thanks for your reply

Will create an I2C Task then try to perform HAL_I2C_*** procedure

Best Regards,

Micha

Right. Keep in mind that the blocking HAL functions like HAL_I2C_Master_Transmit (with timeout) are not RTOS friendly because they don't "tell" the RTOS that they are busy waiting (=MCU using) for a condition. If you need more efficiency, you might want to use the non-blocking _IT or _DMA HAL functions and implement the interrupt&completion callbacks such that they e.g. return data in a FreeRTOS queue. This efficiency comes with more code complexity, so do it only when really needed.

hth

KnarfB

Micha Valach
Associate III

Hi KnafB,

Thanks you very much for your GREAT advise :smiling_face_with_smiling_eyes: !!!

The original I2C example is based on HAL functions: HAL_I2C_Master_Transmit_IT() and HAL_I2C_Master_Receive_IT

I added freeRTOS with CMSIS_V2 (from CubeMX) + one I2C task, copy the I2C functionality from Main loop to the I2C task, DONE - ALL work like a charm !!!

Many Thanks

Best Regards,

Micha

But still it's not clear what you did. If possible please post that part you edited.

Hi MDas3,
In general I, on I2C Master side which is based on freeRTOS and also based on ST example named: I2C_TwoBoards_AdvComIT, I created two I2C functions (I2C_master_write_to_slave() and I2C_master_read_from_slave()) then able to call them whenever I2C communication is needed for either Send or Receive within any freeRTOS task
If you are using CubeMX to auto generate tour code please double check that on both Master and Slave sides, this line is defined correctly: :�? #define I2C_ADDRESS 0x1F�? (seems like CubeMX bug)
Besides it is advised to use Logic Analyzer with I2C protocol capabilities (I’m using the excellent Saleae Logic Analyzer)
Kind Regards,
Micha
void I2C_master_write_to_slave()
{
hTxNumData = TXBUFFERSIZE;
hRxNumData = 2; /*RXBUFFERSIZE;*/
/* Update bTransferRequest to send buffer write request for Slave */
bTransferRequest = MASTER_REQ_WRITE;
/*##-2- Master sends write request for slave #############################*/
do
{
if(HAL_I2C_Master_Transmit_IT(&hi2c3, (uint16_t)(I2C_ADDRESS), (uint8_t*)&bTransferRequest, 1)!= HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY)
{
}
}
while(HAL_I2C_GetError(&hi2c3) == HAL_I2C_ERROR_AF);
/*##-3- Master sends number of data to be written ########################*/
do
{
if(HAL_I2C_Master_Transmit_IT(&hi2c3, (uint16_t)(I2C_ADDRESS),(uint8_t*)&hTxNumData, 2)!= HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY)
{
}
/* When Acknowledge failure occurs (Slave don't acknowledge it's address)
Master restarts communication */
}
while(HAL_I2C_GetError(&hi2c3) == HAL_I2C_ERROR_AF);
//****************************************************************************
memcpy((uint8_t *)aTxBuffer, (uint8_t *)&LEDs_arr[0].green, sizeof(LEDs_arr)); // copy pre-definind LEDs_arr to aTxBuffer[]
//****************************************************************************
/*##-4- Master sends aTxBuffer to slave ##################################*/
do
{
if(HAL_I2C_Master_Transmit_IT(&hi2c3, (uint16_t)(I2C_ADDRESS), (uint8_t*)aTxBuffer, TXBUFFERSIZE)!= HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY)
{
}
}
while(HAL_I2C_GetError(&hi2c3) == HAL_I2C_ERROR_AF);
osDelay(3);
}
void I2C_master_read_from_slave()
{
/* Update bTransferRequest to send buffer read request for Slave */
// After received INT from slave on EXTI12 (PC12) (as TouchPad detection) then read and send Touch-Pad data from Slave to I2C Master
bTransferRequest = MASTER_REQ_READ;
/*##-5- Master sends read request for slave ##############################*/
do
{
if(HAL_I2C_Master_Transmit_IT(&hi2c3, (uint16_t)(I2C_ADDRESS), (uint8_t*)&bTransferRequest, 1)!= HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY)
{
}
}
while(HAL_I2C_GetError(&hi2c3) == HAL_I2C_ERROR_AF);
/*##-6- Master sends number of data to be read ###########################*/
do
{
if(HAL_I2C_Master_Transmit_IT(&hi2c3, (uint16_t)(I2C_ADDRESS), (uint8_t*)&hRxNumData, 2)!= HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY)
{
}
}
while(HAL_I2C_GetError(&hi2c3) == HAL_I2C_ERROR_AF);
/*##-7- Master receives aRxBuffer from slave #############################*/
do
{
if(HAL_I2C_Master_Receive_IT(&hi2c3, (uint16_t)(I2C_ADDRESS),(uint8_t*)aRxBuffer, 2/*RXBUFFERSIZE*/)!= HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY)
{
}
}
while(HAL_I2C_GetError(&hi2c3) == HAL_I2C_ERROR_AF);
osDelay(3);
// check which TouchPad Key was received from Touch&LEDs pcb via I2C protocol ?
if ((aRxBuffer[0] == 0xA5) /*&& (aRxBuffer[1] == 0x5A)*/ )
{
set_bars_color(…..);
}
}