Library 09- I2C for STM32F4
I2C or Inter-Integrated Circuit is a multimaster serial single ended bus. This protocol is commonly used with RTC modules, temperature sensors, EEPROMs, IO expanders and more.
I2C protocol uses 2 wires:
- SCL: Serial Clock, clock for serial synchronization
- SDA: Serial data, bidirection line for receving and transmitting
- Both wires need external pull up resistor, from about 4k7 to 47k, if you don’t use pull up resistors in MCU. In our case, you don’t need external pull ups, because library uses internal in STM32F4.
More about I2C is described here.
STM32F4 has up to 3 I2Cs, every of them has (as always) at least 2 pins pack for each I2C. Pins used for each I2C are described in table below:
PinS PACK 1 | PINS PACK 2 | PINS PACK 3 | |||||
---|---|---|---|---|---|---|---|
I2Cx | SCL | SDA | SCL | SDA | SCL | SDA | APB |
I2C1 | PB6 | PB7 | PB8 | PB9 | PB6 | PB9 | 1 |
I2C2 | PB10 | PB11 | PF1 | PF0 | PH4 | PH5 | 1 |
I2C3 | PA8 | PC9 | PH7 | PH8 | 1 |
Library
Features
- Master mode
- 7 bit slave address
- Up to 127 different slaves on 1 I2C bus
- Read/Write single byte
- Read/Write multiple bytes from slave
- Version 1.1 – August 09, 2014
- Checks if device is connected to I2C bus
- Version 1.2 – August 14, 2014
- If you connect more devices on one I2C with different max SCL speed, low speed will be always selected.
- Added some additional pins for I2C
- Version 1.3 – December 22, 2014
- Added option to read multi bytes from device without setting register from where
- Version 1.4 – March 08, 2015
- Added support for new GPIO settings
Dependencies
- CMSIS
- STM32F4xx
- STM32F4xx RCC
- STM32F4xx GPIO
- STM32F4xx I2C
- TM
- TM GPIO
- defines.h
- attributes.h
- TM GPIO
Initialization
When you use library, you have to initialize it first. You can do this with
1 2 |
//Initialize I2C1 on pins SCL: PB6 and SDA: PB7 with 50kHz serial clock TM_I2C_Init(I2C1, TM_I2C_PinsPack_1, 50000); |
or
1 2 |
//Initialize I2C1 on pins SCL: PB8 and SDA: PB9 with 50kHz serial clock TM_I2C_Init(I2C1, TM_I2C_PinsPack_2, 50000); |
Now, you are able to read/write data with slave.
Read
1 2 3 4 |
/** * Read single byte from slave with 0xD0 (1101 000 0) address and register location 0x00 */ uint8_t data = TM_I2C_Read(I2C1, 0xD0, 0x00); |
1 2 3 4 5 6 7 |
/** * Read 3 bytes of data from slave with 0xD0 address * First register to read from is at 0x00 location * Store received data to variable "data" */ uint8_t data[3]; TM_I2C_ReadMulti(I2C1, 0xD0, 0x00, &data[0], 3); |
Write
1 2 |
//Write "5" at location 0x00 to slave with address 0xD0 TM_I2C_Write(I2C1, 0xD0, 0x00, 5); |
1 2 3 4 5 6 |
/** * Write multi bytes to slave with address 0xD0 * Write to registers starting from 0x00, get data in variable "data" and write 3 bytes */ uint8_t data[] = {0, 1, 2}; TM_I2C_WriteMulti(I2C1, 0xD0, 0x00, &data[0], 3); |
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 |
/** * Pins used */ typedef enum { TM_I2C_PinsPack_1, TM_I2C_PinsPack_2, TM_I2C_PinsPack_3, TM_I2C_PinsPack_Custom } TM_I2C_PinsPack_t; /** * Initialize I2C * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * I2C1, I2C2, I2C3 * - TM_I2C_PinsPack_t pinspack: Pins used */ extern void TM_I2C_Init(I2C_TypeDef* I2Cx, TM_I2C_PinsPack_t pinspack, uint32_t clockSpeed); /** * Read single byte from slave * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used * - uint8_t reg: register to read from * * Data from slave returned */ extern uint8_t TM_I2C_Read(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg); /** * Read multi bytes from slave * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used * - uint8_t reg: register to read from * - uint8_t *data: pointer to data array to store data from slave * - uint8_t count: how many bytes will be read */ extern void TM_I2C_ReadMulti(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint8_t *data, uint16_t count); /** * Read byte from slave without specify register address * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used */ extern uint8_t TM_I2C_ReadNoRegister(I2C_TypeDef* I2Cx, uint8_t address); /** * Read multi bytes from slave without setting register from where to start read * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used * - uint8_t *data: pointer to data array to store data from slave * - uint8_t count: how many bytes will be read */ extern void TM_I2C_ReadMultiNoRegister(I2C_TypeDef* I2Cx, uint8_t address, uint8_t* data, uint16_t count); /** * Write single byte to slave * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used * - uint8_t reg: register to write to * - uint8_t data: data to be written */ extern void TM_I2C_Write(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint8_t data); /** * Write multi bytes from slave * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used * - uint8_t reg: register to write to * - uint8_t *data: pointer to data array to write it to slave * - uint8_t count: how many bytes will be written */ extern void TM_I2C_WriteMulti(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint8_t *data, uint16_t count); /** * Write byte to slave without specify register address * * Useful if you have I2C device to read like that: * - I2C START * - SEND DEVICE ADDRESS * - SEND DATA BYTE * - I2C STOP * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used * - uint8_t data: data byte which will be send to device */ extern void TM_I2C_WriteNoRegister(I2C_TypeDef* I2Cx, uint8_t address, uint8_t data); /** * Write multi bytes to slave without setting register from where to start write * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used * - uint8_t *data: pointer to data array to write data to slave * - uint8_t count: how many bytes you want to write */ extern void TM_I2C_WriteMultiNoRegister(I2C_TypeDef* I2Cx, uint8_t address, uint8_t* data, uint16_t count); /** * Checks if device is connected to I2C bus * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used * * Returns 1 if device is connected, or 0 if not */ extern uint8_t TM_I2C_IsDeviceConnected(I2C_TypeDef* I2Cx, uint8_t address); /** * I2C Start condition * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t address: slave address * - uint8_t direction: master to slave or slave to master * - uint8_t ack: ack enabled or disabled * * Private use */ extern int16_t TM_I2C_Start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction, uint8_t ack); /** * Stop condition * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * * Private use */ extern uint8_t TM_I2C_Stop(I2C_TypeDef* I2Cx); /** * Read byte without ack * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * * Return: data read * * Private use */ extern uint8_t TM_I2C_ReadNack(I2C_TypeDef* I2Cx); /** * Read byte with ack * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * * Return: data read * * Private use */ extern uint8_t TM_I2C_ReadAck(I2C_TypeDef* I2Cx); /** * Write to slave * * Parameters: * - I2C_TypeDef* I2Cx: I2C used * - uint8_t data: data to be sent * * Private use */ extern void TM_I2C_WriteData(I2C_TypeDef* I2Cx, uint8_t data); /** * 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. * * Parameters: * - I2C_TypeDef* I2Cx: * I2C for which initialization will be set * * With __weak parameter to prevent link errors if not defined by user * * No return */ extern __weak void TM_I2C_InitCustomPinsCallback(I2C_TypeDef* I2Cx); |
Example
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 |
/** * Keil project for I2C example * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://majerle.eu * @ide Keil uVision 5 */ #include "stm32f4xx.h" #include "defines.h" #include "tm_stm32f4_i2c.h" #include "tm_stm32f4_delay.h" //Slave address #define ADDRESS 0xD0 // 1101 000 0 int main(void) { uint8_t data[] = {0, 1, 2}; //Initialize system SystemInit(); //Initialize I2C, SCL: PB6 and SDA: PB7 with 100kHt serial clock TM_I2C_Init(I2C1, TM_I2C_PinsPack_1, 100000); //Write "5" at location 0x00 to slave with address ADDRESS TM_I2C_Write(I2C1, ADDRESS, 0x00, 5); /** * Write multi bytes to slave with address ADDRESS * Write to registers starting from 0x00, get data in variable "data" and write 3 bytes */ TM_I2C_WriteMulti(I2C1, ADDRESS, 0x00, data, 3); //Read single byte from slave with 0xD0 (1101 000 0) address and register location 0x00 data[0] = TM_I2C_Read(I2C1, ADDRESS, 0x00); /** * Read 3 bytes of data from slave with 0xD0 address * First register to read from is at 0x00 location * Store received data to "data" variable */ TM_I2C_ReadMulti(I2C1, 0xD0, 0x00, data, 3); while (1) { } } |
Project available on Github, download library below.
I2C library for all I2C peripherals
Recent comments