ChibiOS 21.11.4
hal_i2c.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16/*
17 Concepts and parts of this file have been contributed by Uladzimir Pylinsky
18 aka barthess.
19 */
20
21/**
22 * @file hal_i2c.c
23 * @brief I2C Driver code.
24 *
25 * @addtogroup I2C
26 * @{
27 */
28#include "hal.h"
29
30#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
31
32/*===========================================================================*/
33/* Driver local definitions. */
34/*===========================================================================*/
35
36/*===========================================================================*/
37/* Driver exported variables. */
38/*===========================================================================*/
39
40/*===========================================================================*/
41/* Driver local variables and types. */
42/*===========================================================================*/
43
44/*===========================================================================*/
45/* Driver local functions. */
46/*===========================================================================*/
47
48/*===========================================================================*/
49/* Driver exported functions. */
50/*===========================================================================*/
51
52/**
53 * @brief I2C Driver initialization.
54 * @note This function is implicitly invoked by @p halInit(), there is
55 * no need to explicitly initialize the driver.
56 *
57 * @init
58 */
59void i2cInit(void) {
60
62}
63
64/**
65 * @brief Initializes the standard part of a @p I2CDriver structure.
66 *
67 * @param[out] i2cp pointer to the @p I2CDriver object
68 *
69 * @init
70 */
72
73 i2cp->state = I2C_STOP;
74 i2cp->config = NULL;
75
76#if I2C_USE_MUTUAL_EXCLUSION == TRUE
78#endif
79
80#if defined(I2C_DRIVER_EXT_INIT_HOOK)
81 I2C_DRIVER_EXT_INIT_HOOK(i2cp);
82#endif
83}
84
85/**
86 * @brief Configures and activates the I2C peripheral.
87 *
88 * @param[in] i2cp pointer to the @p I2CDriver object
89 * @param[in] config pointer to the @p I2CConfig object
90 * @return The operation status.
91 *
92 * @api
93 */
94msg_t i2cStart(I2CDriver *i2cp, const I2CConfig *config) {
95 msg_t msg;
96
97 osalDbgCheck((i2cp != NULL) && (config != NULL));
98
100 osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
101 (i2cp->state == I2C_LOCKED), "invalid state");
102
103 i2cp->config = config;
104
105#if defined(I2C_LLD_ENHANCED_API)
106 msg = i2c_lld_start(i2cp);
107 if (msg == HAL_RET_SUCCESS) {
108 i2cp->state = I2C_READY;
109 }
110 else {
111 i2cp->state = I2C_STOP;
112 }
113#else
114 i2c_lld_start(i2cp);
115 i2cp->state = I2C_READY;
116 msg = HAL_RET_SUCCESS;
117#endif
118
120
121 return msg;
122}
123
124/**
125 * @brief Deactivates the I2C peripheral.
126 *
127 * @param[in] i2cp pointer to the @p I2CDriver object
128 *
129 * @api
130 */
131void i2cStop(I2CDriver *i2cp) {
132
133 osalDbgCheck(i2cp != NULL);
134
135 osalSysLock();
136
137 osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
138 (i2cp->state == I2C_LOCKED), "invalid state");
139
140 i2c_lld_stop(i2cp);
141 i2cp->config = NULL;
142 i2cp->state = I2C_STOP;
143
145}
146
147/**
148 * @brief Returns the errors mask associated to the previous operation.
149 *
150 * @param[in] i2cp pointer to the @p I2CDriver object
151 * @return The errors mask.
152 *
153 * @api
154 */
156
157 osalDbgCheck(i2cp != NULL);
158
159 return i2c_lld_get_errors(i2cp);
160}
161
162/**
163 * @brief Sends data via the I2C bus.
164 * @details Function designed to realize "read-through-write" transfer
165 * paradigm. If you want transmit data without any further read,
166 * than set @b rxbytes field to 0.
167 *
168 * @param[in] i2cp pointer to the @p I2CDriver object
169 * @param[in] addr slave device address (7 bits) without R/W bit
170 * @param[in] txbuf pointer to transmit buffer
171 * @param[in] txbytes number of bytes to be transmitted
172 * @param[out] rxbuf pointer to receive buffer
173 * @param[in] rxbytes number of bytes to be received, set it to 0 if
174 * you want transmit only
175 * @param[in] timeout the number of ticks before the operation timeouts,
176 * the following special values are allowed:
177 * - @a TIME_INFINITE no timeout.
178 *
179 * @return The operation status.
180 * @retval MSG_OK if the function succeeded.
181 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
182 * be retrieved using @p i2cGetErrors().
183 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
184 *
185 * @api
186 */
188 i2caddr_t addr,
189 const uint8_t *txbuf,
190 size_t txbytes,
191 uint8_t *rxbuf,
192 size_t rxbytes,
193 sysinterval_t timeout) {
194 msg_t rdymsg;
195
196 osalDbgCheck((i2cp != NULL) &&
197 (txbytes > 0U) && (txbuf != NULL) &&
198 ((rxbytes == 0U) || ((rxbytes > 0U) && (rxbuf != NULL))) &&
199 (timeout != TIME_IMMEDIATE));
200
201 osalDbgAssert(i2cp->state == I2C_READY, "not ready");
202
203 osalSysLock();
204 i2cp->errors = I2C_NO_ERROR;
205 i2cp->state = I2C_ACTIVE_TX;
206 rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes,
207 rxbuf, rxbytes, timeout);
208 if (rdymsg == MSG_TIMEOUT) {
209 i2cp->state = I2C_LOCKED;
210 }
211 else {
212 i2cp->state = I2C_READY;
213 }
215 return rdymsg;
216}
217
218/**
219 * @brief Receives data from the I2C bus.
220 *
221 * @param[in] i2cp pointer to the @p I2CDriver object
222 * @param[in] addr slave device address (7 bits) without R/W bit
223 * @param[out] rxbuf pointer to receive buffer
224 * @param[in] rxbytes number of bytes to be received
225 * @param[in] timeout the number of ticks before the operation timeouts,
226 * the following special values are allowed:
227 * - @a TIME_INFINITE no timeout.
228 *
229 * @return The operation status.
230 * @retval MSG_OK if the function succeeded.
231 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
232 * be retrieved using @p i2cGetErrors().
233 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
234 *
235 * @api
236 */
238 i2caddr_t addr,
239 uint8_t *rxbuf,
240 size_t rxbytes,
241 sysinterval_t timeout) {
242
243 msg_t rdymsg;
244
245 osalDbgCheck((i2cp != NULL) && (addr != 0U) &&
246 (rxbytes > 0U) && (rxbuf != NULL) &&
247 (timeout != TIME_IMMEDIATE));
248
249 osalDbgAssert(i2cp->state == I2C_READY, "not ready");
250
251 osalSysLock();
252 i2cp->errors = I2C_NO_ERROR;
253 i2cp->state = I2C_ACTIVE_RX;
254 rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout);
255 if (rdymsg == MSG_TIMEOUT) {
256 i2cp->state = I2C_LOCKED;
257 }
258 else {
259 i2cp->state = I2C_READY;
260 }
262 return rdymsg;
263}
264
265#if (I2C_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
266/**
267 * @brief Gains exclusive access to the I2C bus.
268 * @details This function tries to gain ownership to the I2C bus, if the bus
269 * is already being used then the invoking thread is queued.
270 * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
271 * must be enabled.
272 *
273 * @param[in] i2cp pointer to the @p I2CDriver object
274 *
275 * @api
276 */
278
279 osalDbgCheck(i2cp != NULL);
280
281 osalMutexLock(&i2cp->mutex);
282}
283
284/**
285 * @brief Releases exclusive access to the I2C bus.
286 * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
287 * must be enabled.
288 *
289 * @param[in] i2cp pointer to the @p I2CDriver object
290 *
291 * @api
292 */
294
295 osalDbgCheck(i2cp != NULL);
296
297 osalMutexUnlock(&i2cp->mutex);
298}
299#endif /* I2C_USE_MUTUAL_EXCLUSION == TRUE */
300
301#if (I2C_ENABLE_SLAVE_MODE == TRUE) || defined(__DOXYGEN__)
302/**
303 * @brief Listen I2C bus for address match.
304 * @details Use 7 bit address (10 bit,dual and general call address dosn't implement yet) .
305 *
306 * @param[in] i2cp pointer to the @p I2CDriver object
307 * @param[in] addr slave device address
308 * @return The operation status.
309 * @retval MSG_OK if the function succeeded.
310 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
311 * be retrieved using @p i2cGetErrors().
312 *
313 * @notapi
314 */
316
317 osalDbgCheck((i2cp != NULL) && (addr != 0x00));
318
319 chSysLock();
320
321 msg_t result = i2c_lld_match_address(i2cp, addr);
322
323 chSysUnlock();
324
325 return result;
326}
327
328/**
329 * @brief Receive data via the I2C bus as slave and call handler.
330 *
331 * @param[in] i2cp pointer to the @p I2CDriver object
332 * @param[out] rxbuf pointer to the receive buffer
333 * @param[in] rxbytes size of receive buffer
334 * @param[in] timeout the number of ticks before the operation timeouts,
335 * the following special values are allowed:
336 * - @a TIME_INFINITE no timeout.
337 * @return The operation status.
338 * @retval MSG_OK if the function succeeded.
339 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
340 * be retrieved using @p i2cGetErrors().
341 * @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
342 * timeout the driver must be stopped and restarted
343 * because the bus is in an uncertain state</b>.
344 *
345 * @api
346 */
348 uint8_t *rxbuf,
349 size_t rxbytes,
350 sysinterval_t timeout) {
351 msg_t rdymsg;
352
353 osalDbgCheck((i2cp != NULL) &&
354 (rxbytes > 0U) &&
355 (rxbuf != NULL) &&
356 (timeout != TIME_IMMEDIATE));
357
358 osalDbgAssert(i2cp->state == I2C_READY, "not ready");
359
360 osalSysLock();
361
362 i2cp->errors = I2C_NO_ERROR;
363 i2cp->state = I2C_ACTIVE_RX;
364
365 rdymsg = i2c_lld_slave_receive_timeout(i2cp, rxbuf, rxbytes, timeout);
366 if (rdymsg == MSG_TIMEOUT) {
367 i2cp->state = I2C_LOCKED;
368 }
369 else {
370 i2cp->state = I2C_READY;
371 }
372
374
375 return rdymsg;
376}
377
378/**
379 * @brief Transmits data via the I2C bus as slave.
380 * @details Call this function when Master request data (in request handler)
381 *
382 * @param[in] i2cp pointer to the @p I2CDriver object
383 * @param[in] txbuf pointer to the transmit buffer
384 * @param[in] txbytes number of bytes to be transmitted
385 * @param[in] timeout the number of ticks before the operation timeouts,
386 * the following special values are allowed:
387 * - @a TIME_INFINITE no timeout.
388 * @return The operation status.
389 * @retval MSG_OK if the function succeeded.
390 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
391 * be retrieved using @p i2cGetErrors().
392 * @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
393 * timeout the driver must be stopped and restarted
394 * because the bus is in an uncertain state</b>.
395 *
396 * @api
397 */
399 const uint8_t *txbuf,
400 size_t txbytes,
401 sysinterval_t timeout){
402 msg_t rdymsg;
403
404 osalDbgCheck((i2cp != NULL) &&
405 (txbytes > 0U) &&
406 (txbuf != NULL) &&
407 (timeout != TIME_IMMEDIATE));
408
409 osalDbgAssert(i2cp->state == I2C_READY, "not ready");
410
411 osalSysLock();
412
413 i2cp->errors = I2C_NO_ERROR;
414 i2cp->state = I2C_ACTIVE_TX;
415 rdymsg = i2c_lld_slave_transmit_timeout(i2cp, txbuf, txbytes, timeout);
416 if (rdymsg == MSG_TIMEOUT) {
417 i2cp->state = I2C_LOCKED;
418 }
419 else {
420 i2cp->state = I2C_READY;
421 }
422
424
425 return rdymsg;
426}
427#endif /* I2C_ENABLE_SLAVE_MODE == TRUE */
428
429#endif /* HAL_USE_I2C == TRUE */
430
431/** @} */
#define HAL_RET_SUCCESS
Definition hal.h:93
msg_t i2cSlaveTransmitTimeout(I2CDriver *i2cp, const uint8_t *txbuf, size_t txbytes, sysinterval_t timeout)
Transmits data via the I2C bus as slave.
Definition hal_i2c.c:398
#define i2c_lld_get_errors(i2cp)
Get errors from I2C driver.
msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, i2caddr_t addr, uint8_t *rxbuf, size_t rxbytes, sysinterval_t timeout)
Receives data from the I2C bus.
Definition hal_i2c.c:237
void i2cInit(void)
I2C Driver initialization.
Definition hal_i2c.c:59
void i2c_lld_stop(I2CDriver *i2cp)
Deactivates the I2C peripheral.
Definition hal_i2c_lld.c:99
void i2cObjectInit(I2CDriver *i2cp)
Initializes the standard part of a I2CDriver structure.
Definition hal_i2c.c:71
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, uint8_t *rxbuf, size_t rxbytes, sysinterval_t timeout)
Receives data via the I2C bus as master.
#define I2C_NO_ERROR
No error.
Definition hal_i2c.h:43
uint32_t i2cflags_t
Type of I2C Driver condition flags.
Definition hal_i2c_lld.h:68
msg_t i2cStart(I2CDriver *i2cp, const I2CConfig *config)
Configures and activates the I2C peripheral.
Definition hal_i2c.c:94
struct hal_i2c_config I2CConfig
Type of a structure representing an I2C configuration.
Definition hal_i2c_lld.h:83
i2cflags_t i2cGetErrors(I2CDriver *i2cp)
Returns the errors mask associated to the previous operation.
Definition hal_i2c.c:155
msg_t i2cSlaveReceiveTimeout(I2CDriver *i2cp, uint8_t *rxbuf, size_t rxbytes, sysinterval_t timeout)
Receive data via the I2C bus as slave and call handler.
Definition hal_i2c.c:347
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp, i2caddr_t addr, const uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes, sysinterval_t timeout)
Sends data via the I2C bus.
Definition hal_i2c.c:187
void i2c_lld_start(I2CDriver *i2cp)
Configures and activates the I2C peripheral.
Definition hal_i2c_lld.c:79
void i2cReleaseBus(I2CDriver *i2cp)
Releases exclusive access to the I2C bus.
Definition hal_i2c.c:293
uint16_t i2caddr_t
Type representing an I2C address.
Definition hal_i2c_lld.h:63
void i2cStop(I2CDriver *i2cp)
Deactivates the I2C peripheral.
Definition hal_i2c.c:131
void i2c_lld_init(void)
Low level I2C driver initialization.
Definition hal_i2c_lld.c:65
msg_t i2cSlaveMatchAddress(I2CDriver *i2cp, i2caddr_t addr)
Listen I2C bus for address match.
Definition hal_i2c.c:315
void i2cAcquireBus(I2CDriver *i2cp)
Gains exclusive access to the I2C bus.
Definition hal_i2c.c:277
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, const uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes, sysinterval_t timeout)
Transmits data via the I2C bus as master.
struct hal_i2c_driver I2CDriver
Type of a structure representing an I2C driver.
Definition hal_i2c_lld.h:88
@ I2C_ACTIVE_TX
Transmitting.
Definition hal_i2c.h:88
@ I2C_STOP
Stopped.
Definition hal_i2c.h:86
@ I2C_READY
Ready.
Definition hal_i2c.h:87
@ I2C_LOCKED
Bus locked.
Definition hal_i2c.h:90
@ I2C_ACTIVE_RX
Receiving.
Definition hal_i2c.h:89
#define chSysUnlock()
Leaves the kernel lock state.
#define chSysLock()
Enters the kernel lock state.
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition osal.h:601
static void osalMutexObjectInit(mutex_t *mp)
Initializes a mutex_t object.
Definition osal.h:753
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition osal.h:611
void osalMutexLock(mutex_t *mp)
Locks the specified mutex.
Definition osal.c:380
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
void osalMutexUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition osal.c:400
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
int32_t msg_t
Definition chearly.h:88
#define MSG_TIMEOUT
Wakeup caused by a timeout condition.
Definition chschd.h:40
#define TIME_IMMEDIATE
Zero interval specification for some functions with a timeout specification.
Definition chtime.h:47
uint64_t sysinterval_t
Type of time interval.
Definition chtime.h:119
HAL subsystem header.
const I2CConfig * config
Current configuration data.
i2cflags_t errors
Error flags.
i2cstate_t state
Driver state.
Definition hal_i2c_lld.h:97