In past month STM published new set of tools and software examples that implement HAL (wikipedia: Hardware abstraction layer) on the many of theirs µC. They are calling this set of tools STM32CubeF4. This post is a little public note to myself and all others who are banging or will be banging their heads at wall because they aren’t able to make I2C communication to work.
I2C addressing (not the 10bit, i am talking about 7bit) has only 7 bits because one bit of 8 bit addressing space is reserved for flag denoting if operation will be reading or writing. That one bit is LSB (Least significant bit). If you are into details, you can more here.
Till now i worked with libraries that input a 7bit address and they automatically shift it for one bit to left. After that libs set LSB to the right value depending on the operation.
STM32CubeF4’s way
(At the time writting this: HAL version is 1.1.0 )
Long story short: You have to shift the 7 bit address yourself. You can see two functions from my I2C library that are more or less self explanatory – note the shifted addresses (uint16_t)I2C_ADDRESS<<1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
void I2C::WriteBuffer(uint8_t I2C_ADDRESS, uint8_t *aTxBuffer, uint8_t TXBUFFERSIZE) { /* -> Start the transmission process */ /* While the I2C in reception process, user can transmit data through "aTxBuffer" buffer */ while(HAL_I2C_Master_Transmit(&I2cHandle, (uint16_t)I2C_ADDRESS<<1, (uint8_t*)aTxBuffer, (uint16_t)TXBUFFERSIZE, (uint32_t)1000)!= HAL_OK) { /* * Error_Handler() function is called when Timeout error occurs. * When Acknowledge failure occurs (Slave don't acknowledge it's address) * Master restarts communication */ if (HAL_I2C_GetError(&I2cHandle) != HAL_I2C_ERROR_AF) { DEBUG(3, "In I2C::WriteBuffer -> error"); Error_Handler(3); } } /* -> 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_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY) { } } |
And ReadBuffer :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
void I2C::ReadBuffer(uint8_t I2C_ADDRESS, uint8_t RegAddr, uint8_t *aRxBuffer, uint8_t RXBUFFERSIZE) { /* -> Lets ask for register's address */ WriteBuffer(I2C_ADDRESS, &RegAddr, 1); /* -> Put I2C peripheral in reception process */ while(HAL_I2C_Master_Receive(&I2cHandle, (uint16_t)I2C_ADDRESS<<1, aRxBuffer, (uint16_t)RXBUFFERSIZE, (uint32_t)1000) != HAL_OK) { /* Error_Handler() function is called when Timeout error occurs. * When Acknowledge failure occurs (Slave don't acknowledge it's address) * Master restarts communication */ if (HAL_I2C_GetError(&I2cHandle) != HAL_I2C_ERROR_AF) { DEBUG(3, "In I2C::WriteBuffer -> error"); Error_Handler(4); } } /* -> 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_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY) { } } |
I hope i saved you an hour or two :-).