Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Stm32I2C.cxx
Go to the documentation of this file.
1
36#include "Stm32I2C.hxx"
37
38#if defined(STM32F072xB) || defined(STM32F091xC)
39#include "stm32f0xx_ll_rcc.h"
40#include "stm32f0xx_ll_i2c.h"
41
42// This timing is assuming 48 MHz main clock, the I2C module being clocked from
43// the main clock, and gives 400 kHz clock (fast mode).
44#define I2C_TIMING (__LL_I2C_CONVERT_TIMINGS(5, 0x3, 0x3, 0x3, 0x9))
45
46#elif defined(STM32F103xB)
47#include "stm32f1xx_ll_rcc.h"
48#elif defined(STM32F303xC) || defined(STM32F303xE)
49#include "stm32f3xx_ll_rcc.h"
50
51// This timing is assuming 72 MHz main clock, the I2C module being clocked from
52// the main clock, and gives 400 kHz clock (fast mode).
53#define I2C_TIMING (__LL_I2C_CONVERT_TIMINGS(8, 0x3, 0x3, 0x3, 0x9))
54
55#elif defined(STM32L431xx) || defined(STM32L432xx)
56#include "stm32l4xx_ll_rcc.h"
57#include "stm32l4xx_ll_i2c.h"
58
59// This timing is assuming 80 MHz main clock, the I2C module being clocked from
60// the main clock, and gives 400 kHz clock (fast mode).
61#define I2C_TIMING (__LL_I2C_CONVERT_TIMINGS(9, 0x3, 0x3, 0x3, 0x9))
62
63#elif defined(STM32F767xx)
64#include "stm32f7xx_ll_rcc.h"
65#include "stm32f7xx_ll_i2c.h"
66
67// This timing is assuming 216 MHz main clock, the I2C module being clocked
68// from the main clock, and gives 400 kHz clock (fast mode).
69#define I2C_TIMING (__LL_I2C_CONVERT_TIMINGS(8, 9, 9, 9, 27))
70
71#elif defined(STM32G0B1xx)
72#include "stm32g0xx_ll_rcc.h"
73#include "stm32g0xx_ll_i2c.h"
74
75// This timing is assuming 64 MHz main clock, the I2C module being clocked
76// from the main clock, and gives 400 kHz clock (fast mode).
77#define I2C_TIMING (__LL_I2C_CONVERT_TIMINGS(7, 0x3, 0x3, 0x3, 0x9))
78
79#else
80#error Dont know what STM32 chip you have.
81#endif
82
83// Enables the clock and resets the I2C peripheral.
84static void i2c_reset(I2C_TypeDef *port)
85{
86 switch ((unsigned)port)
87 {
88 default:
89 DIE("Unknown I2C port requested.");
90#ifdef I2C1
91 case I2C1_BASE:
92 LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_SYSCLK);
93 __HAL_RCC_I2C1_CLK_ENABLE();
94 __HAL_RCC_I2C1_FORCE_RESET();
95 __HAL_RCC_I2C1_RELEASE_RESET();
96 break;
97#endif
98#ifdef I2C2
99 case I2C2_BASE:
100 #ifdef LL_RCC_I2C2_CLKSOURCE_SYSCLK
101 LL_RCC_SetI2CClockSource(LL_RCC_I2C2_CLKSOURCE_SYSCLK);
102 #endif
103 __HAL_RCC_I2C2_CLK_ENABLE();
104 __HAL_RCC_I2C2_FORCE_RESET();
105 __HAL_RCC_I2C2_RELEASE_RESET();
106 break;
107#endif
108#ifdef I2C3
109 case I2C3_BASE:
110 #ifdef LL_RCC_I2C3_CLKSOURCE_SYSCLK
111 LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_SYSCLK);
112 #endif
113 __HAL_RCC_I2C3_CLK_ENABLE();
114 __HAL_RCC_I2C3_FORCE_RESET();
115 __HAL_RCC_I2C3_RELEASE_RESET();
116 break;
117#endif
118#ifdef I2C4
119 case I2C4_BASE:
120 __HAL_RCC_I2C4_CONFIG(RCC_I2C4CLKSOURCE_SYSCLK);
121 __HAL_RCC_I2C4_CLK_ENABLE();
122 __HAL_RCC_I2C4_FORCE_RESET();
123 __HAL_RCC_I2C4_RELEASE_RESET();
124 break;
125#endif
126#ifdef I2C5
127 case I2C5_BASE:
128 __HAL_RCC_I2C5_CONFIG(RCC_I2C5CLKSOURCE_SYSCLK);
129 __HAL_RCC_I2C5_CLK_ENABLE();
130 __HAL_RCC_I2C5_FORCE_RESET();
131 __HAL_RCC_I2C5_RELEASE_RESET();
132 break;
133#endif
134#ifdef I2C6
135 case I2C6_BASE:
136 __HAL_RCC_I2C6_CONFIG(RCC_I2C6CLKSOURCE_SYSCLK);
137 __HAL_RCC_I2C6_CLK_ENABLE();
138 __HAL_RCC_I2C6_FORCE_RESET();
139 __HAL_RCC_I2C6_RELEASE_RESET();
140 break;
141#endif
142#ifdef I2C7
143 case I2C7_BASE:
144 __HAL_RCC_I2C7_CONFIG(RCC_I2C7CLKSOURCE_SYSCLK);
145 __HAL_RCC_I2C7_CLK_ENABLE();
146 __HAL_RCC_I2C7_FORCE_RESET();
147 __HAL_RCC_I2C7_RELEASE_RESET();
148 break;
149#endif
150#ifdef I2C8
151 case I2C8_BASE:
152 __HAL_RCC_I2C8_CONFIG(RCC_I2C8CLKSOURCE_SYSCLK);
153 __HAL_RCC_I2C8_CLK_ENABLE();
154 __HAL_RCC_I2C8_FORCE_RESET();
155 __HAL_RCC_I2C8_RELEASE_RESET();
156 break;
157#endif
158 }
159}
160
167Stm32I2C::Stm32I2C(const char *name, I2C_TypeDef *port, uint32_t ev_interrupt,
168 uint32_t er_interrupt)
169 : I2C(name)
170{
171 i2c_reset(port);
172 memset(&i2cHandle_, 0, sizeof(i2cHandle_));
173
174 i2cHandle_.Instance = port;
175
176 i2cHandle_.Init.Timing = I2C_TIMING;
177 i2cHandle_.Init.OwnAddress1 = 0;
178 i2cHandle_.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
179 i2cHandle_.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
180 i2cHandle_.Init.OwnAddress2 = 0xFF;
181 i2cHandle_.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
182 i2cHandle_.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
183
184 HASSERT(HAL_I2C_Init(&i2cHandle_) == HAL_OK);
185
186 /* Enable the Analog I2C Filter */
187 HAL_I2CEx_ConfigAnalogFilter(&i2cHandle_, I2C_ANALOGFILTER_ENABLE);
188
189 // We save the object pointer in order to get back to *this in the callback
190 // routines. This field of the Init structure is not used after the Init
191 // call above.
192 i2cHandle_.Init.Timing = (uint32_t) this;
193
194#ifdef configKERNEL_INTERRUPT_PRIORITY // cortex-m3 or more
195 SetInterruptPriority((IRQn_Type)ev_interrupt, configKERNEL_INTERRUPT_PRIORITY);
196 SetInterruptPriority((IRQn_Type)er_interrupt, configKERNEL_INTERRUPT_PRIORITY);
197#endif
198 HAL_NVIC_EnableIRQ((IRQn_Type)ev_interrupt);
199 HAL_NVIC_EnableIRQ((IRQn_Type)er_interrupt);
200}
201
202int Stm32I2C::transfer(struct i2c_msg *msg, bool stop)
203{
204 int bytes = msg->len;
205 // The slave address is set with an 8-bit value where bit 0 (R/nW) is
206 // ignored. We shift the address left for this reason.
207
208 // We kill the previous state information because we don't want the driver
209 // to optimize away the restart condition.
210 i2cHandle_.PreviousState = 0;
211 error_ = 0;
212
213 if (msg->flags & I2C_M_RD)
214 {
215 /* this is a read transfer */
216 uint32_t xfer_options;
217 if (stop)
218 {
219 xfer_options = I2C_FIRST_AND_LAST_FRAME;
220 }
221 else
222 {
223 xfer_options = I2C_FIRST_FRAME;
224 }
225
226 if (HAL_I2C_Master_Seq_Receive_IT(&i2cHandle_,
227 (uint16_t)msg->addr << 1, (uint8_t *)msg->buf, bytes,
228 xfer_options) != HAL_OK)
229 {
230 return -EIO;
231 }
232 }
233 else
234 {
235 /* this is a write transfer */
236 uint32_t xfer_options;
237 if (stop)
238 {
239 xfer_options = I2C_FIRST_AND_LAST_FRAME;
240 }
241 else
242 {
243 xfer_options = I2C_FIRST_FRAME;
244 }
245 if (HAL_I2C_Master_Seq_Transmit_IT(&i2cHandle_,
246 (uint16_t)msg->addr << 1, (uint8_t *)msg->buf, bytes,
247 xfer_options) != HAL_OK)
248 {
249 return -EIO;
250 }
251 }
252
253 sem.wait();
254
255 return error_ < 0 ? error_ : bytes;
256}
257
258Stm32I2C *dev_from_handle(I2C_HandleTypeDef *hi2c)
259{
260 return (Stm32I2C *)hi2c->Init.Timing;
261}
262
264{
265 int woken = 0;
266 sem.post_from_isr(&woken);
267 os_isr_exit_yield_test(woken);
268}
269
271{
272 auto error = i2cHandle_.ErrorCode;
273
274 if (error & HAL_I2C_ERROR_ARLO)
275 {
276 error_ = -EAGAIN;
277 }
278 else if (error & HAL_I2C_ERROR_AF)
279 {
280 error_ = -ENOENT;
281 }
282 else if (error & HAL_I2C_ERROR_TIMEOUT)
283 {
284 error_ = -ETIMEDOUT;
285 }
286 else
287 {
288 error_ = -EIO;
289 }
290
292}
293
294// =============== Callbacks from driver ===============
295
296extern "C" {
297
298void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
299{
300 dev_from_handle(hi2c)->complete_from_isr();
301}
302
303void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
304{
305 dev_from_handle(hi2c)->complete_from_isr();
306}
307
308void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
309{
310 dev_from_handle(hi2c)->error_from_isr();
311}
312}
Private data for an I2C device.
Definition I2C.hxx:51
void wait()
Wait on (decrement) a semaphore.
Definition OS.hxx:279
Specialization of I2C driver for STM32 devices.
Definition Stm32I2C.hxx:46
I2C_HandleTypeDef i2cHandle_
Stm32 HAL device structure.
Definition Stm32I2C.hxx:92
void error_from_isr()
Internal. This function is called from the error ISR callback.
Definition Stm32I2C.cxx:270
OSSem sem
Semaphore to wakeup task level from ISR.
Definition Stm32I2C.hxx:96
Stm32I2C()
Default constructor.
int error_
Pending transfer error field.
Definition Stm32I2C.hxx:94
void complete_from_isr()
Internal. This function is called from the complete ISR callback.
Definition Stm32I2C.cxx:263
int transfer(struct i2c_msg *msg, bool stop) override
Method to transmit/receive the data.
Definition Stm32I2C.cxx:202
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define DIE(MSG)
Unconditionally terminates the current process with a message.
Definition macros.h:143