ChibiOS/HAL  6.1.0
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  */
59 void i2cInit(void) {
60 
61  i2c_lld_init();
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  */
71 void i2cObjectInit(I2CDriver *i2cp) {
72 
73  i2cp->state = I2C_STOP;
74  i2cp->config = NULL;
75 
76 #if I2C_USE_MUTUAL_EXCLUSION == TRUE
77  osalMutexObjectInit(&i2cp->mutex);
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  *
91  * @api
92  */
93 void i2cStart(I2CDriver *i2cp, const I2CConfig *config) {
94 
95  osalDbgCheck((i2cp != NULL) && (config != NULL));
96  osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
97  (i2cp->state == I2C_LOCKED), "invalid state");
98 
99  osalSysLock();
100  i2cp->config = config;
101  i2c_lld_start(i2cp);
102  i2cp->state = I2C_READY;
103  osalSysUnlock();
104 }
105 
106 /**
107  * @brief Deactivates the I2C peripheral.
108  *
109  * @param[in] i2cp pointer to the @p I2CDriver object
110  *
111  * @api
112  */
113 void i2cStop(I2CDriver *i2cp) {
114 
115  osalDbgCheck(i2cp != NULL);
116 
117  osalSysLock();
118 
119  osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
120  (i2cp->state == I2C_LOCKED), "invalid state");
121 
122  i2c_lld_stop(i2cp);
123  i2cp->config = NULL;
124  i2cp->state = I2C_STOP;
125 
126  osalSysUnlock();
127 }
128 
129 /**
130  * @brief Returns the errors mask associated to the previous operation.
131  *
132  * @param[in] i2cp pointer to the @p I2CDriver object
133  * @return The errors mask.
134  *
135  * @api
136  */
138 
139  osalDbgCheck(i2cp != NULL);
140 
141  return i2c_lld_get_errors(i2cp);
142 }
143 
144 /**
145  * @brief Sends data via the I2C bus.
146  * @details Function designed to realize "read-through-write" transfer
147  * paradigm. If you want transmit data without any further read,
148  * than set @b rxbytes field to 0.
149  *
150  * @param[in] i2cp pointer to the @p I2CDriver object
151  * @param[in] addr slave device address (7 bits) without R/W bit
152  * @param[in] txbuf pointer to transmit buffer
153  * @param[in] txbytes number of bytes to be transmitted
154  * @param[out] rxbuf pointer to receive buffer
155  * @param[in] rxbytes number of bytes to be received, set it to 0 if
156  * you want transmit only
157  * @param[in] timeout the number of ticks before the operation timeouts,
158  * the following special values are allowed:
159  * - @a TIME_INFINITE no timeout.
160  * .
161  *
162  * @return The operation status.
163  * @retval MSG_OK if the function succeeded.
164  * @retval MSG_RESET if one or more I2C errors occurred, the errors can
165  * be retrieved using @p i2cGetErrors().
166  * @retval MSG_TIMEOUT if a timeout occurred before operation end.
167  *
168  * @api
169  */
171  i2caddr_t addr,
172  const uint8_t *txbuf,
173  size_t txbytes,
174  uint8_t *rxbuf,
175  size_t rxbytes,
176  sysinterval_t timeout) {
177  msg_t rdymsg;
178 
179  osalDbgCheck((i2cp != NULL) &&
180  (txbytes > 0U) && (txbuf != NULL) &&
181  ((rxbytes == 0U) || ((rxbytes > 0U) && (rxbuf != NULL))) &&
182  (timeout != TIME_IMMEDIATE));
183 
184  osalDbgAssert(i2cp->state == I2C_READY, "not ready");
185 
186  osalSysLock();
187  i2cp->errors = I2C_NO_ERROR;
188  i2cp->state = I2C_ACTIVE_TX;
189  rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes,
190  rxbuf, rxbytes, timeout);
191  if (rdymsg == MSG_TIMEOUT) {
192  i2cp->state = I2C_LOCKED;
193  }
194  else {
195  i2cp->state = I2C_READY;
196  }
197  osalSysUnlock();
198  return rdymsg;
199 }
200 
201 /**
202  * @brief Receives data from the I2C bus.
203  *
204  * @param[in] i2cp pointer to the @p I2CDriver object
205  * @param[in] addr slave device address (7 bits) without R/W bit
206  * @param[out] rxbuf pointer to receive buffer
207  * @param[in] rxbytes number of bytes to be received
208  * @param[in] timeout the number of ticks before the operation timeouts,
209  * the following special values are allowed:
210  * - @a TIME_INFINITE no timeout.
211  * .
212  *
213  * @return The operation status.
214  * @retval MSG_OK if the function succeeded.
215  * @retval MSG_RESET if one or more I2C errors occurred, the errors can
216  * be retrieved using @p i2cGetErrors().
217  * @retval MSG_TIMEOUT if a timeout occurred before operation end.
218  *
219  * @api
220  */
222  i2caddr_t addr,
223  uint8_t *rxbuf,
224  size_t rxbytes,
225  sysinterval_t timeout) {
226 
227  msg_t rdymsg;
228 
229  osalDbgCheck((i2cp != NULL) && (addr != 0U) &&
230  (rxbytes > 0U) && (rxbuf != NULL) &&
231  (timeout != TIME_IMMEDIATE));
232 
233  osalDbgAssert(i2cp->state == I2C_READY, "not ready");
234 
235  osalSysLock();
236  i2cp->errors = I2C_NO_ERROR;
237  i2cp->state = I2C_ACTIVE_RX;
238  rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout);
239  if (rdymsg == MSG_TIMEOUT) {
240  i2cp->state = I2C_LOCKED;
241  }
242  else {
243  i2cp->state = I2C_READY;
244  }
245  osalSysUnlock();
246  return rdymsg;
247 }
248 
249 #if (I2C_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
250 /**
251  * @brief Gains exclusive access to the I2C bus.
252  * @details This function tries to gain ownership to the I2C bus, if the bus
253  * is already being used then the invoking thread is queued.
254  * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
255  * must be enabled.
256  *
257  * @param[in] i2cp pointer to the @p I2CDriver object
258  *
259  * @api
260  */
262 
263  osalDbgCheck(i2cp != NULL);
264 
265  osalMutexLock(&i2cp->mutex);
266 }
267 
268 /**
269  * @brief Releases exclusive access to the I2C bus.
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  osalMutexUnlock(&i2cp->mutex);
282 }
283 #endif /* I2C_USE_MUTUAL_EXCLUSION == TRUE */
284 
285 #endif /* HAL_USE_I2C == TRUE */
286 
287 /** @} */
static void osalMutexObjectInit(mutex_t *mp)
Initializes s mutex_t object.
Definition: osal.h:681
void i2cInit(void)
I2C Driver initialization.
Definition: hal_i2c.c:59
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:170
void i2c_lld_stop(I2CDriver *i2cp)
Deactivates the I2C peripheral.
Definition: hal_i2c_lld.c:99
void i2cStart(I2CDriver *i2cp, const I2CConfig *config)
Configures and activates the I2C peripheral.
Definition: hal_i2c.c:93
Type of I2C driver configuration structure.
Definition: hal_i2c_lld.h:75
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.
Definition: hal_i2c_lld.c:169
HAL subsystem header.
#define i2c_lld_get_errors(i2cp)
Get errors from I2C driver.
Definition: hal_i2c_lld.h:121
void i2cAcquireBus(I2CDriver *i2cp)
Gains exclusive access to the I2C bus.
Definition: hal_i2c.c:261
void i2cReleaseBus(I2CDriver *i2cp)
Releases exclusive access to the I2C bus.
Definition: hal_i2c.c:277
void osalMutexLock(mutex_t *mp)
Locks the specified mutex.
Definition: osal.c:384
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition: osal.h:540
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:221
i2cflags_t i2cGetErrors(I2CDriver *i2cp)
Returns the errors mask associated to the previous operation.
Definition: hal_i2c.c:137
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.
Definition: hal_i2c_lld.c:133
int32_t msg_t
Type of a message.
Definition: osal.h:160
void i2cStop(I2CDriver *i2cp)
Deactivates the I2C peripheral.
Definition: hal_i2c.c:113
uint32_t i2cflags_t
Type of I2C Driver condition flags.
Definition: hal_i2c_lld.h:68
Structure representing an I2C driver.
Definition: hal_i2c_lld.h:88
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:278
void i2c_lld_start(I2CDriver *i2cp)
Configures and activates the I2C peripheral.
Definition: hal_i2c_lld.c:79
uint32_t sysinterval_t
Type of system time interval.
Definition: osal.h:170
void i2c_lld_init(void)
Low level I2C driver initialization.
Definition: hal_i2c_lld.c:65
uint16_t i2caddr_t
Type representing an I2C address.
Definition: hal_i2c_lld.h:63
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition: osal.h:530
i2cflags_t errors
Error flags.
Definition: hal_i2c_lld.h:100
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:258
const I2CConfig * config
Current configuration data.
Definition: hal_i2c_lld.h:96
void osalMutexUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition: osal.c:404
i2cstate_t state
Driver state.
Definition: hal_i2c_lld.h:92
#define I2C_NO_ERROR
No error.
Definition: hal_i2c.h:43