GPS Device
Loading...
Searching...
No Matches
I2C Public APIs

Functions

void i2c_init (I2C_CFG_ts *i2c_cfg)
 Initializes the I2C peripheral with the given configuration.
void i2c_deinit (I2C_REGDEF_ts const *i2c_instance)
 Deinitializes the I2C peripheral and disables its clock.
void i2c_master_send (I2C_REGDEF_ts *i2c_instance, uint8_t slave_addr, uint8_t *tx_buffer, uint32_t len)
 Blocking I2C master transmit.
void i2c_master_send_continue (I2C_REGDEF_ts *i2c_instance, uint8_t *tx_buffer, uint32_t len)
 Continues a transmission without a new START or address phase.
void i2c_master_receive (I2C_REGDEF_ts *i2c_instance, uint8_t slave_addr, uint8_t *rx_buffer, uint32_t len)
 Blocking I2C master receive.
void i2c_master_set_comm (I2C_REGDEF_ts *i2c_instance, EN_STATUS_te en_status)
 Enables or disables the I2C peripheral and controls bus ownership.
void i2c_get_name (I2C_REGDEF_ts const *i2c_instance, char *name)
 Returns the name string of an I2C peripheral instance.

Detailed Description

Function Documentation

◆ i2c_init()

void i2c_init ( I2C_CFG_ts * i2c_cfg)

Initializes the I2C peripheral with the given configuration.

See also
i2c_init

Definition at line 24 of file stm32f401re_i2c.c.

24 {
25 // Enable peripheral clock
26 i2c_set_pclk(i2c_cfg->instance, ENABLE);
27
28 // Configure clock stretching (NOSTRETCH bit in CR1)
29 i2c_cfg->instance->I2C_CR1 &= ~(0x1 << I2C_CR1_NOSTRETCH);
30 i2c_cfg->instance->I2C_CR1 |= (i2c_cfg->clock_strech << I2C_CR1_NOSTRETCH);
31
32 // Configure own 7-bit address in OAR1; bit 14 must be kept set per reference manual
33 i2c_cfg->instance->I2C_OAR1 &= ~(0x7F << I2C_OAR1_ADD7_1);
34 i2c_cfg->instance->I2C_OAR1 |= ((i2c_cfg->address & 0x7F) << I2C_OAR1_ADD7_1);
35 i2c_cfg->instance->I2C_OAR1 |= (0x1 << 14);
36
37 // Set CR2 FREQ field to the APB1 clock frequency in MHz
38 uint32_t i2c_clock_hz = rcc_get_apb1_clk();
39 i2c_cfg->instance->I2C_CR2 &= ~(0x3F << I2C_CR2_FREQ);
40 i2c_cfg->instance->I2C_CR2 |= (((i2c_clock_hz / 1000000) & 0x3F) << I2C_CR2_FREQ);
41
42 // Compute CCR and TRISE based on selected speed
43 uint16_t ccr_value = 0;
44 uint8_t t_rise = 0;
45 if(i2c_cfg->speed == I2C_SPEED_100kHz) {
46 // Standard mode (SM): 100 kHz, 50% duty cycle
47 // CCR = f_PCLK1 / (2 * f_SCL)
48 i2c_cfg->instance->I2C_CCR &= ~(0x1 << I2C_CCR_FS);
49
50 ccr_value = i2c_clock_hz / (2 * 100000);
51
52 // TRISE = (t_rise_max_ns / t_PCLK1_ns) + 1 = (1000 ns / (1/f_PCLK1)) + 1
53 t_rise = (i2c_clock_hz / 1000000) + 1;
54 }
55 else if(i2c_cfg->speed == I2C_SPEED_400kHz) {
56 // Fast mode (FM): 400 kHz, DUTY = 1 gives t_low/t_high = 16/9
57 // CCR = f_PCLK1 / (25 * f_SCL)
58 i2c_cfg->instance->I2C_CCR &= ~(0x1 << I2C_CCR_FS);
59 i2c_cfg->instance->I2C_CCR |= (0x1 << I2C_CCR_FS);
60
61 i2c_cfg->instance->I2C_CCR &= ~(0x1 << I2C_CCR_DUTY);
62 i2c_cfg->instance->I2C_CCR |= (0x1 << I2C_CCR_DUTY);
63
64 ccr_value = i2c_clock_hz / (25 * 400000);
65
66 // TRISE = (t_rise_max_ns * f_PCLK1 / 1e9) + 1 = (300 ns * f_PCLK1 / 1e9) + 1
67 t_rise = ((i2c_clock_hz * 300) / 1000000000) + 1;
68 }
69 i2c_cfg->instance->I2C_CCR &= ~(0xFFF);
70 i2c_cfg->instance->I2C_CCR |= (ccr_value << I2C_CCR_CCR);
71
72 i2c_cfg->instance->I2C_TRISE &= ~(0x3F);
73 i2c_cfg->instance->I2C_TRISE |= (t_rise);
74}
@ ENABLE
Definition common.h:100
static void i2c_set_pclk(I2C_REGDEF_ts const *i2c_instance, EN_STATUS_te en_status)
Enables or disables the peripheral clock for an I2C instance.
@ I2C_SPEED_100kHz
@ I2C_SPEED_400kHz
uint32_t rcc_get_apb1_clk(void)
Returns the current APB1 (low-speed) peripheral bus clock frequency in Hz.
@ I2C_CCR_DUTY
@ I2C_CCR_CCR
@ I2C_CCR_FS
@ I2C_CR2_FREQ
@ I2C_CR1_NOSTRETCH
@ I2C_OAR1_ADD7_1
I2C_REGDEF_ts * instance
I2C_CLOCK_STRECH_te clock_strech
I2C_SPEED_te speed
uint32_t volatile I2C_OAR1
uint32_t volatile I2C_CCR
uint32_t volatile I2C_CR2
uint32_t volatile I2C_TRISE
uint32_t volatile I2C_CR1
Here is the call graph for this function:
Here is the caller graph for this function:

◆ i2c_deinit()

void i2c_deinit ( I2C_REGDEF_ts const * i2c_instance)

Deinitializes the I2C peripheral and disables its clock.

See also
i2c_deinit

Definition at line 77 of file stm32f401re_i2c.c.

77 {
78 if(i2c_instance == I2C1) {
80 }
81 else if(i2c_instance == I2C2) {
83 }
84 else if(i2c_instance == I2C3) {
86 }
87
88 i2c_set_pclk(i2c_instance, DISABLE);
89}
@ DISABLE
Definition common.h:97
void rcc_reset_periph_apb1(RCC_APB1RSTR_te periph_position)
Resets an APB1 peripheral via RCC_APB1RSTR.
#define I2C3
#define I2C1
#define I2C2
@ RCC_APB1RSTR_I2C3RST
@ RCC_APB1RSTR_I2C1RST
@ RCC_APB1RSTR_I2C2RST
Here is the call graph for this function:

◆ i2c_master_send()

void i2c_master_send ( I2C_REGDEF_ts * i2c_instance,
uint8_t slave_addr,
uint8_t * tx_buffer,
uint32_t len )

Blocking I2C master transmit.

Blocking I2C master transmit. Sends a start condition, address, and data.

See also
i2c_master_send

Definition at line 92 of file stm32f401re_i2c.c.

92 {
93 uint16_t volatile dummy_read = 0;
94 (void)dummy_read;
95
96 // Generate START condition
97 i2c_instance->I2C_CR1 |= (0x1 << I2C_CR1_START);
98
99 // Wait for SB (start bit) flag; reading SR1 clears SB
100 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_SB) & 0x1));
101 dummy_read = i2c_instance->I2C_SR1;
102
103 // Send 7-bit slave address with write bit (LSB = 0)
104 i2c_instance->I2C_DR = (slave_addr << 1);
105
106 // Wait for ADDR flag; reading SR1 then SR2 clears ADDR
107 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_ADDR) & 0x1));
108 dummy_read = i2c_instance->I2C_SR1;
109 dummy_read = i2c_instance->I2C_SR2;
110
111 // Transmit data bytes
112 while(len != 0) {
113 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_TxE) & 0x1));
114 i2c_instance->I2C_DR = *tx_buffer;
115 tx_buffer++;
116 len--;
117 }
118
119 // Wait for TxE and BTF to confirm the last byte has been shifted out
120 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_TxE) & 0x1));
121 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_BTF) & 0x1));
122}
@ I2C_CR1_START
@ I2C_SR1_TxE
@ I2C_SR1_BTF
@ I2C_SR1_SB
@ I2C_SR1_ADDR
uint32_t volatile I2C_SR1
uint32_t volatile I2C_SR2
uint32_t volatile I2C_DR
Here is the caller graph for this function:

◆ i2c_master_send_continue()

void i2c_master_send_continue ( I2C_REGDEF_ts * i2c_instance,
uint8_t * tx_buffer,
uint32_t len )

Continues a transmission without a new START or address phase.

Continues a transmission started by i2c_master_send without a new START or address phase.

See also
i2c_master_send_continue

Definition at line 125 of file stm32f401re_i2c.c.

125 {
126 uint16_t volatile dummy_read = 0;
127 (void)dummy_read;
128
129 // Transmit additional data bytes into the open transaction
130 while(len != 0) {
131 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_TxE) & 0x1));
132 i2c_instance->I2C_DR = *tx_buffer;
133 tx_buffer++;
134 len--;
135 }
136
137 // Wait for TxE and BTF to confirm the last byte has been shifted out
138 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_TxE) & 0x1));
139 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_BTF) & 0x1));
140}
Here is the caller graph for this function:

◆ i2c_master_receive()

void i2c_master_receive ( I2C_REGDEF_ts * i2c_instance,
uint8_t slave_addr,
uint8_t * rx_buffer,
uint32_t len )

Blocking I2C master receive.

Blocking I2C master receive. Sends a start condition, address, and reads data.

See also
i2c_master_receive

Definition at line 143 of file stm32f401re_i2c.c.

143 {
144 uint16_t volatile dummy_read = 0;
145 (void)dummy_read;
146
147 // Generate START condition
148 i2c_instance->I2C_CR1 |= (0x1 << I2C_CR1_START);
149
150 // Wait for SB flag; reading SR1 clears SB
151 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_SB) & 0x1));
152 dummy_read = i2c_instance->I2C_SR1;
153
154 // Send 7-bit slave address with read bit (LSB = 1)
155 i2c_instance->I2C_DR = ((slave_addr << 1) | 0x1);
156
157 if(len == 1) {
158 // Single-byte reception: disable ACK before clearing ADDR so NACK
159 // is sent immediately after the byte is received
160 i2c_instance->I2C_CR1 &= ~(0x1 << I2C_CR1_ACK);
161
162 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_ADDR) & 0x1));
163 dummy_read = i2c_instance->I2C_SR1;
164 dummy_read = i2c_instance->I2C_SR2;
165
166 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_RxNE) & 0x1));
167 *rx_buffer = i2c_instance->I2C_DR;
168 }
169 else if(len > 1) {
170 // Multi-byte reception: ACK all bytes until the second-to-last
171 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_ADDR) & 0x1));
172 dummy_read = i2c_instance->I2C_SR1;
173 dummy_read = i2c_instance->I2C_SR2;
174
175 while(len != 0) {
176 if(len == 2) {
177 // Disable ACK before reading the penultimate byte so NACK
178 // is sent after the last byte
179 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_RxNE) & 0x1));
180 i2c_instance->I2C_CR1 &= ~(0x1 << I2C_CR1_ACK);
181
182 *rx_buffer = i2c_instance->I2C_DR;
183 rx_buffer++;
184 len--;
185 }
186 else {
187 while(!((i2c_instance->I2C_SR1 >> I2C_SR1_RxNE) & 0x1));
188 *rx_buffer = i2c_instance->I2C_DR;
189 rx_buffer++;
190 len--;
191 }
192 }
193 }
194
195 // Re-enable ACK for subsequent transactions
196 i2c_instance->I2C_CR1 |= (0x1 << I2C_CR1_ACK);
197}
@ I2C_CR1_ACK
@ I2C_SR1_RxNE

◆ i2c_master_set_comm()

void i2c_master_set_comm ( I2C_REGDEF_ts * i2c_instance,
EN_STATUS_te en_status )

Enables or disables the I2C peripheral and controls bus ownership.

See also
i2c_master_set_comm

Definition at line 200 of file stm32f401re_i2c.c.

200 {
201 if(en_status == ENABLE) {
202 // Enable peripheral and ACK generation
203 i2c_instance->I2C_CR1 |= (0x1 << I2C_CR1_PE);
204 i2c_instance->I2C_CR1 |= (0x1 << I2C_CR1_ACK);
205 }
206 else if(en_status == DISABLE) {
207 // Generate STOP condition, wait for bus to go idle, then disable PE
208 i2c_instance->I2C_CR1 |= (0x1 << I2C_CR1_STOP);
209 while((i2c_instance->I2C_SR2 >> I2C_SR2_BUSY) & 0x01);
210 i2c_instance->I2C_CR1 &= ~(0x1 << I2C_CR1_PE);
211 }
212}
@ I2C_CR1_STOP
@ I2C_CR1_PE
@ I2C_SR2_BUSY
Here is the caller graph for this function:

◆ i2c_get_name()

void i2c_get_name ( I2C_REGDEF_ts const * i2c_instance,
char * name )

Returns the name string of an I2C peripheral instance.

Returns the name string of an I2C peripheral instance (e.g. "I2C1").

See also
i2c_get_name

Definition at line 215 of file stm32f401re_i2c.c.

215 {
216 const char i2c[] = "I2C";
217 uint8_t i2c_len = get_str_len(i2c);
218 uint8_t pos_counter = 0;
219
220 while(pos_counter != i2c_len) {
221 name[pos_counter] = i2c[pos_counter];
222 pos_counter++;
223 }
224
225 if(i2c_instance == I2C1) name[pos_counter] = '1';
226 else if(i2c_instance == I2C2) name[pos_counter] = '2';
227 else if(i2c_instance == I2C3) name[pos_counter] = '3';
228 pos_counter++;
229
230 name[pos_counter] = '\0';
231}
uint32_t get_str_len(char const *str)
Returns the length of a string, excluding the null terminator.
Definition common.c:22
Here is the call graph for this function: