HAL Library 16- I2C for STM32Fxxx devices
Here it is. After some email for I2C library for HAL, I’ve made it. I ported my old for F4 to HAL based libraries for F0/F4/F7 series.
I added method to read single byte, multi bytes, write single byte, write multi bytes, write/read single byte from/to register which has 16-bit address size.
Library
Features
- Supports up to 4 I2C peripherals
- Supports different pinouts selectable on initialization
- Supports custom pin combinations
- Supports multiple read/write modes
- Based on HAL drivers for maximal portability between series
Dependencies
- HAL
- TM
- STM32F4xxx HAL
- defines.h
- TM GPIO
Library pinouts
PINS PACK 1 | PINS PACK 2 | PINS PACK 3 | PINS PACK 4 | |||||
---|---|---|---|---|---|---|---|---|
I2Cx | SCL | SDA | SCL | SDA | SCL | SDA | SCL | SDA |
I2C1 | PB6 | PB7 | PB8 | PB9 | PB6 | PB9 | ||
I2C2 | PB10 | PB11 | PF1 | PF0 | PH4 | PH5 | ||
I2C3 | PA8 | PC9 | PH7 | PH8 | ||||
I2C4 | PD12 | PD13 | PF1 | PF0 | PF14 | PF15 | PH11 | PH12 |
Functions and enumerations
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
/** * @defgroup TM_I2C_Typedefs * @brief Library Typedefs * @{ */ /** * @brief I2C pinspack enumeration */ typedef enum { TM_I2C_PinsPack_1 = 0x00, /*!< Use Pinspack1 from Pinout table for I2Cx */ TM_I2C_PinsPack_2, /*!< Use Pinspack2 from Pinout table for I2Cx */ TM_I2C_PinsPack_3, /*!< Use Pinspack3 from Pinout table for I2Cx */ TM_I2C_PinsPack_4, /*!< Use Pinspack4 from Pinout table for I2Cx */ TM_I2C_PinsPack_Custom /*!< Use custom pins for I2Cx */ } TM_I2C_PinsPack_t; /** * @brief I2C result enumeration */ typedef enum { TM_I2C_Result_Ok = 0x00, /*!< Everything OK */ TM_I2C_Result_Error /*!< An error has occurred */ } TM_I2C_Result_t; /** * @} */ /** * @defgroup TM_I2C_Functions * @brief Library Functions * @{ */ /** * @brief Initializes I2C peripheral * @param *I2Cx: Pointer to I2Cx peripheral you will use for iintialization * @param pinspack: Pinspack used for GPIO initialization. This parameter can be a value of @ref TM_I2C_PinsPack_t enumeration * @param clockSpeed: Clock speed in units of Hz for I2C communication * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_Init(I2C_TypeDef* I2Cx, TM_I2C_PinsPack_t pinspack, uint32_t clockSpeed); /** * @brief Reads single byte from device * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param register_address: Register address from where read will be done * @param *data: Pointer to variable where data will be stored from read operation * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_Read(I2C_TypeDef* I2Cx, uint8_t device_address, uint8_t register_address, uint8_t* data); /** * @brief Reads multiple bytes from device * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param register_address: Register address from where read operation will start * @param *data: Pointer to variable where data will be stored from read operation * @param count: Number of elements to read from device * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_ReadMulti(I2C_TypeDef* I2Cx, uint8_t device_address, uint8_t register_address, uint8_t* data, uint16_t count); /** * @brief Reads I2C data without specifying register address * @note This can be used if your sensors just sends data, without any registers * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param *data: Pointer to variable where data will be stored from read operation * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_ReadNoRegister(I2C_TypeDef* I2Cx, uint8_t device_address, uint8_t* data); /** * @brief Reads multiple bytes from device without specifying register address * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param *data: Pointer to variable where data will be stored from read operation * @param count: Number of elements to read from device * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_ReadMultiNoRegister(I2C_TypeDef* I2Cx, uint8_t device_address, uint8_t* data, uint16_t count); /** * @brief Reads single byte from device with 16-bit register address * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param register_address: Register address from where read will be done * @param *data: Pointer to variable where data will be stored from read operation * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_Read16(I2C_TypeDef* I2Cx, uint8_t device_address, uint16_t register_address, uint8_t* data); /** * @brief Writes single byte to device * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param register_address: Register address where you want to write data * @param data: Data to be written to device * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_Write(I2C_TypeDef* I2Cx, uint8_t device_address, uint8_t register_address, uint8_t data); /** * @brief Writes multiple data to device * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param register_address: Register address where data will be written * @param *data: Data to be written to device. * @param count: Number of elements to write starting at register register_address * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_WriteMulti(I2C_TypeDef* I2Cx, uint8_t device_address, uint16_t register_address, uint8_t *data, uint16_t count); /** * @brief Writes single byte to device without specifying register address, can be used for command write * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param data: Data to be written to device * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_WriteNoRegister(I2C_TypeDef* I2Cx, uint8_t device_address, uint8_t data); /** * @brief Writes multiple data to device without register address * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param *data: Pointer to data array t obe written to device. Array length is the same as number of elements you want to write * @param count: Number of elements to write * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_WriteMultiNoRegister(I2C_TypeDef* I2Cx, uint8_t device_address, uint8_t* data, uint16_t count); /** * @brief Writes single byte in a 16-bit length register address * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param register_address: Register address where data will be written * @param data: Data byte to write * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_Write16(I2C_TypeDef* I2Cx, uint8_t device_address, uint16_t register_address, uint8_t data); /** * @brief Checks if device is connected to I2C port and ready to use * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_IsDeviceConnected(I2C_TypeDef* I2Cx, uint8_t address); /** * @brief Callback for custom pins initialization. * * When you call TM_I2C_Init() function, and if you pass TM_I2C_PinsPack_Custom to function, * then this function will be called where you can initialize custom pins for I2C peripheral. * @param *I2Cx: I2C for which initialization will be set * @param AlternateFunction: Alternate function which should be used for GPIO initialization * @retval None * @note With __weak parameter to prevent link errors if not defined by user */ void TM_I2C_InitCustomPinsCallback(I2C_TypeDef* I2Cx, uint16_t AlternateFunction); /** * @brief Gets pointer to I2C handle structure for specific I2C * @param *I2Cx: Pointer to I2Cx used for handle * @retval Pointer to I2C Handle structure */ I2C_HandleTypeDef* TM_I2C_GetHandle(I2C_TypeDef* I2Cx); /** * @brief Writes and receives amount of data via I2C using repeated start condition * @param *I2Cx: Pointer to I2Cx peripheral to be used in communication * @param device_address: 7-bit, left aligned device address used for communication * @param write_register_address: Register address to start writing to * @param *write_data: Pointer to data array where data for write are stored * @param write_count: Number of elements to write * @param read_register_address: Register address where reading will start * @param *read_data: Pointer to array where data will be saved * @param read_count: Number of elements to read * @retval Member of @ref TM_I2C_Result_t enumeration */ TM_I2C_Result_t TM_I2C_WriteReadRepeatedStart( I2C_TypeDef* I2Cx, uint8_t device_address, uint8_t write_register_address, uint8_t* write_data, uint16_t write_count, uint8_t read_register_address, uint8_t* read_data, uint16_t read_count ); /** * @} */ |
Example 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
/** * Keil project example for I2C - Single write and read bytes * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @conf PLL parameters are set in "Options for Target" -> "C/C++" -> "Defines" * @packs STM32F4xx/STM32F7xx Keil packs are requred with HAL driver support * @stdperiph STM32F4xx/STM32F7xx HAL drivers required */ /* Include core modules */ #include "stm32fxxx_hal.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32_disco.h" #include "tm_stm32_delay.h" #include "tm_stm32_i2c.h" /* MPU-6050 device address */ #define MPU6050_ADDRESS 0xD0 /* Byte value read from external device */ uint8_t read; int main(void) { /* Init system clock for maximum system speed */ TM_RCC_InitSystem(); /* Init HAL layer */ HAL_Init(); /* Init leds */ TM_DISCO_LedInit(); /* Init delay */ TM_DELAY_Init(); /* Init I2C, SCL = PB8, SDA = PB9, available on Arduino headers and on all discovery boards */ /* For STM32F4xx and STM32F7xx lines */ TM_I2C_Init(I2C1, TM_I2C_PinsPack_2, 100000); /* Read one byte, device address = MPU6050_ADDRESS, register address = 0x1A */ TM_I2C_Read(I2C1, MPU6050_ADDRESS, 0x1A, &read); /* Write single byte via I2C, device address = MPU6050_ADDRESS, register address = 0x0A, data = 0x12 */ TM_I2C_Write(I2C1, MPU6050_ADDRESS, 0x1A, 0x12); /* Read one byte, device address = MPU6050_ADDRESS, register address = 0x1A */ TM_I2C_Read(I2C1, MPU6050_ADDRESS, 0x1A, &read); /* Check value */ if (read == 0x12) { TM_DISCO_LedOn(LED_GREEN); } else { /* Toggle LED, indicate wrong */ while (1) { /* Toggle LED */ TM_DISCO_LedToggle(LED_ALL); /* Delay 100ms */ Delayms(100); } } while (1) { } } |
Example 2
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/** * Keil project example for I2C - Custom pins for I2C * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @conf PLL parameters are set in "Options for Target" -> "C/C++" -> "Defines" * @packs STM32F4xx/STM32F7xx Keil packs are requred with HAL driver support * @stdperiph STM32F4xx/STM32F7xx HAL drivers required */ /* Include core modules */ #include "stm32fxxx_hal.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32_disco.h" #include "tm_stm32_delay.h" #include "tm_stm32_i2c.h" /* MPU-6050 device address */ #define MPU6050_ADDRESS 0xD0 /* Byte value read from external device */ uint8_t read; int main(void) { /* Init system clock for maximum system speed */ TM_RCC_InitSystem(); /* Init HAL layer */ HAL_Init(); /* Init leds */ TM_DISCO_LedInit(); /* Init delay */ TM_DELAY_Init(); /* Init I2C, use custom pins, callback function will be caleed */ /* For STM32F4xx and STM32F7xx lines */ TM_I2C_Init(I2C1, TM_I2C_PinsPack_Custom, 100000); while (1) { } } /* Called if TM_I2C_PinsPack_Custom is selected when initializing I2C */ void TM_I2C_InitCustomPinsCallback(I2C_TypeDef* I2Cx, uint16_t AlternateFunction) { /* Check for proper I2C */ if (I2Cx == I2C1) { /* Init pins PB8 and PB9 for I2C1 */ TM_GPIO_InitAlternate(GPIOB, GPIO_PIN_8 | GPIO_PIN_9, TM_GPIO_OType_PP, TM_GPIO_PuPd_UP, TM_GPIO_Speed_Low, AlternateFunction); } } |
Example 3
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/** * Keil project example for I2C - Multiple write and read bytes from SLAVE * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @conf PLL parameters are set in "Options for Target" -> "C/C++" -> "Defines" * @packs STM32F4xx/STM32F7xx Keil packs are requred with HAL driver support * @stdperiph STM32F4xx/STM32F7xx HAL drivers required */ /* Include core modules */ #include "stm32fxxx_hal.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32_disco.h" #include "tm_stm32_delay.h" #include "tm_stm32_i2c.h" /* MPU-6050 device address */ #define MPU6050_ADDRESS 0xD0 /* Byte value read from external device */ uint8_t data_array[6]; int main(void) { /* Init system clock for maximum system speed */ TM_RCC_InitSystem(); /* Init HAL layer */ HAL_Init(); /* Init leds */ TM_DISCO_LedInit(); /* Init delay */ TM_DELAY_Init(); /* Init I2C, SCL = PB8, SDA = PB9, available on Arduino headers and on all discovery boards */ /* For STM32F4xx and STM32F7xx lines */ TM_I2C_Init(I2C1, TM_I2C_PinsPack_2, 100000); /* Read 5 bytes, device address = MPU6050_ADDRESS, start from register address = 0x1A */ TM_I2C_ReadMulti(I2C1, MPU6050_ADDRESS, 0x1A, data_array, 5); /* Format data array to write to device */ data_array[0] = 0x00; /* Data 0 */ data_array[1] = 0x00; /* Data 1 */ data_array[2] = 0x00; /* Data 2 */ data_array[3] = 0x00; /* Data 3 */ data_array[4] = 0x00; /* Data 4 */ /* Write 5 bytes via I2C, device address = MPU6050_ADDRESS, register address is 0x1A */ /* We want to write 5 bytes */ TM_I2C_WriteMulti(I2C1, MPU6050_ADDRESS, 0x1A, data_array, 5); while (1) { } } |
Project are available on Github, download all libraries below.
STM32 libraries based on STM32Fxxx HAL drivers.
Recent comments