Statistics
| Branch: | Tag: | Revision:

amiro-os / periphery-lld / periphAL.h @ 232ccea6

History | View | Annotate | Download (21.712 KB)

1 e545e620 Thomas Schöpping
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3 84f0ce9e Thomas Schöpping
Copyright (C) 2016..2019  Thomas Schöpping et al.
4 e545e620 Thomas Schöpping

5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14

15
You should have received a copy of the GNU General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19 6ff06bbf Thomas Schöpping
#ifndef AMIROOS_PERIPHAL_H
20
#define AMIROOS_PERIPHAL_H
21 e545e620 Thomas Schöpping
22 3940ba8a Thomas Schöpping
#include <amiro-lld.h>
23
24 e545e620 Thomas Schöpping
/*============================================================================*/
25
/* VERSION                                                                    */
26
/*============================================================================*/
27
28
/**
29
 * @brief   The periphery abstraction layer interface major version.
30
 * @note    Changes of the major version imply incompatibilities.
31
 */
32
#define PERIPHAL_VERSION_MAJOR    1
33
34
/**
35
 * @brief   The periphery abstraction layer interface minor version.
36
 * @note    A higher minor version implies new functionalty, but all old interfaces are still available.
37
 */
38 3106e8cc Thomas Schöpping
#define PERIPHAL_VERSION_MINOR    1
39 e545e620 Thomas Schöpping
40
/*============================================================================*/
41
/* DEPENDENCIES                                                               */
42
/*============================================================================*/
43
44 1f94ac64 Thomas Schöpping
#include <aosconf.h>
45 e545e620 Thomas Schöpping
#include <hal.h>
46
47
/*============================================================================*/
48 1f94ac64 Thomas Schöpping
/* DEBUG                                                                      */
49
/*============================================================================*/
50
51
#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
52
53 7de0cc90 Thomas Schöpping
#if defined(__cplusplus)
54 1f94ac64 Thomas Schöpping
extern "C" {
55 7de0cc90 Thomas Schöpping
#endif /* defined(__cplusplus) */
56 1f94ac64 Thomas Schöpping
  void _apalDbgAssertMsg(const bool c, const char* fmt, ...);
57
  void apalDbgPrintf(const char* fmt, ...);
58 7de0cc90 Thomas Schöpping
#if defined(__cplusplus)
59 1f94ac64 Thomas Schöpping
}
60 7de0cc90 Thomas Schöpping
#endif /* defined(__cplusplus) */
61 1f94ac64 Thomas Schöpping
62
/**
63
 * @brief Assert function to check a given condition.
64
 *
65
 * @param[in] c     The condition to check.
66
 */
67 232ccea6 Thomas Schöpping
#define apalDbgAssert(c) _apalDbgAssertMsg(c, "%s(%u): apalDbgAssert failed", __FILE__, __LINE__)
68
69 1f94ac64 Thomas Schöpping
70 7de0cc90 Thomas Schöpping
#else /* (AMIROOS_CFG_DBG != true) */
71 1f94ac64 Thomas Schöpping
72
#define apalDbgAssert(constition)
73
#define apalDbgAssertMsg(condition, fmt, ...)
74
#define apalDbgPrintf(fmt, ...)
75
76 7de0cc90 Thomas Schöpping
#endif /* (AMIROOS_CFG_DBG == true) */
77 1f94ac64 Thomas Schöpping
78
/*============================================================================*/
79 e545e620 Thomas Schöpping
/* GENERAL                                                                    */
80
/*============================================================================*/
81
82
/**
83
 * @brief Delay execution by a specific number of microseconds.
84
 *
85
 * @param[in]   us    Time to sleep until execution continues in microseconds.
86
 */
87 232ccea6 Thomas Schöpping
static inline void apalSleep(apalTime_t us)
88 e545e620 Thomas Schöpping
{
89
  // check if the specified time can be represented by the system
90 1f94ac64 Thomas Schöpping
  apalDbgAssert(us <= chTimeI2US(TIME_INFINITE));
91 e545e620 Thomas Schöpping
92 3940ba8a Thomas Schöpping
  const sysinterval_t interval = chTimeUS2I(us);
93 e545e620 Thomas Schöpping
  // TIME_IMMEDIATE makes no sense and would even cause system halt
94 3940ba8a Thomas Schöpping
  if (interval != TIME_IMMEDIATE) {
95
    chThdSleep(interval);
96 e545e620 Thomas Schöpping
  }
97
  return;
98
}
99
100
/*============================================================================*/
101
/* GPIO                                                                       */
102
/*============================================================================*/
103
104 7de0cc90 Thomas Schöpping
#if (HAL_USE_PAL == TRUE) || defined (__DOXYGEN__)
105 e545e620 Thomas Schöpping
106
/**
107
 * @brief GPIO driver type.
108
 */
109
struct apalGpio_t {
110 3106e8cc Thomas Schöpping
  ioline_t line;
111 e545e620 Thomas Schöpping
} PACKED_VAR;
112
113
/**
114
 * @brief Read the current value of a GPIO pin.
115
 *
116
 * @param[in]   gpio  GPIO to read.
117
 * @param[out]  val   Current value of the GPIO.
118
 *
119
 * @return The status indicates whether the function call was successful.
120
 */
121
static inline apalExitStatus_t apalGpioRead(apalGpio_t* gpio, apalGpioState_t* const val)
122
{
123 1f94ac64 Thomas Schöpping
  apalDbgAssert(gpio != NULL);
124
  apalDbgAssert(val != NULL);
125 e545e620 Thomas Schöpping
126 3106e8cc Thomas Schöpping
  *val = (palReadLine(gpio->line) == PAL_HIGH) ? APAL_GPIO_HIGH : APAL_GPIO_LOW;
127 e545e620 Thomas Schöpping
  return APAL_STATUS_OK;
128
}
129
130
/**
131
 * @brief Set the value of a GPIO pin.
132
 *
133
 * @param[in] gpio  GPIO to write.
134
 * @param[in] val   Value to set for the GPIO.
135
 *
136
 * @return The status indicates whether the function call was successful.
137
 */
138
static inline apalExitStatus_t apalGpioWrite(apalGpio_t* gpio, const apalGpioState_t val)
139
{
140 1f94ac64 Thomas Schöpping
  apalDbgAssert(gpio != NULL);
141 e545e620 Thomas Schöpping
142 3106e8cc Thomas Schöpping
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
143 e545e620 Thomas Schöpping
  syssts_t sysstatus = chSysGetStatusAndLockX();
144 3106e8cc Thomas Schöpping
  palWriteLine(gpio->line, (val == APAL_GPIO_HIGH) ? PAL_HIGH : PAL_LOW);
145 e545e620 Thomas Schöpping
  chSysRestoreStatusX(sysstatus);
146
  return APAL_STATUS_OK;
147
}
148
149
/**
150
 * @brief Toggle the output of a GPIO.
151
 *
152
 * @param[in] gpio  GPIO to toggle.
153
 *
154
 * @return The status indicates whether the function call was successful.
155
 */
156
static inline apalExitStatus_t apalGpioToggle(apalGpio_t* gpio)
157
{
158 1f94ac64 Thomas Schöpping
  apalDbgAssert(gpio != NULL);
159 e545e620 Thomas Schöpping
160 3106e8cc Thomas Schöpping
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
161 e545e620 Thomas Schöpping
  syssts_t sysstatus = chSysGetStatusAndLockX();
162 3106e8cc Thomas Schöpping
  palWriteLine(gpio->line, (palReadLine(gpio->line) == PAL_HIGH) ? PAL_LOW : PAL_HIGH);
163 e545e620 Thomas Schöpping
  chSysRestoreStatusX(sysstatus);
164
  return APAL_STATUS_OK;
165
}
166
167
/**
168 232ccea6 Thomas Schöpping
 * @brief Return the interrupt enable status of the GPIO.
169
 *
170
 * @param[in]   gpio      GPIO to check.
171
 * @param[out]  enabled   Flag, indicating whether interrupt is enabled for the GPIO.
172
 *
173
 * @return The status indicates whether the function call was successful.
174
 */
175
static inline apalExitStatus_t apalGpioIsInterruptEnabled(apalGpio_t* gpio, bool* const enabled)
176
{
177
  apalDbgAssert(gpio != NULL);
178
  apalDbgAssert(enabled != NULL);
179
180
  *enabled = palIsLineEventEnabledX(gpio->line);
181
  return APAL_STATUS_OK;
182
}
183
184
/**
185 e545e620 Thomas Schöpping
 * @brief Get the current on/off state of a control GPIO.
186
 *
187
 * @param[in]   gpio  Control GPIO to read.
188
 * @param[out]  val   Current activation status of the control GPIO.
189
 *
190
 * @return The status indicates whether the function call was successful.
191
 */
192
static inline apalExitStatus_t apalControlGpioGet(const apalControlGpio_t* const cgpio, apalControlGpioState_t* const val)
193
{
194 1f94ac64 Thomas Schöpping
  apalDbgAssert(cgpio != NULL);
195
  apalDbgAssert(cgpio->gpio != NULL);
196
  apalDbgAssert(val != NULL);
197 e545e620 Thomas Schöpping
198 3106e8cc Thomas Schöpping
  *val = ((palReadLine(cgpio->gpio->line) == PAL_HIGH) ^ (cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH)) ? APAL_GPIO_OFF : APAL_GPIO_ON;
199 e545e620 Thomas Schöpping
  return APAL_STATUS_OK;
200
}
201
202
/**
203
 * @brief Turn a control GPIO 'on' or 'off' respectively.
204
 *
205
 * @param[in] gpio  Control GPIO to set.
206
 * @param[in] val   Activation value to set for the control GPIO.
207
 *
208
 * @return The status indicates whether the function call was successful.
209
 */
210
static inline apalExitStatus_t apalControlGpioSet(const apalControlGpio_t* const cgpio, const apalControlGpioState_t val)
211
{
212 1f94ac64 Thomas Schöpping
  apalDbgAssert(cgpio != NULL);
213
  apalDbgAssert(cgpio->gpio != NULL);
214
  apalDbgAssert(cgpio->meta.direction == APAL_GPIO_DIRECTION_OUTPUT || cgpio->meta.direction == APAL_GPIO_DIRECTION_BIDIRECTIONAL);
215 e545e620 Thomas Schöpping
216 3106e8cc Thomas Schöpping
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
217 e545e620 Thomas Schöpping
  syssts_t sysstatus = chSysGetStatusAndLockX();
218 3106e8cc Thomas Schöpping
  palWriteLine(cgpio->gpio->line, ((cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH) ^ (val == APAL_GPIO_ON)) ? PAL_LOW : PAL_HIGH);
219 e545e620 Thomas Schöpping
  chSysRestoreStatusX(sysstatus);
220
  return APAL_STATUS_OK;
221
}
222
223
/**
224 1e5f7648 Thomas Schöpping
 * @brief   Converts an apalGpioEdge_t to an ChibiOS PAL edge.
225 e545e620 Thomas Schöpping
 */
226 1e5f7648 Thomas Schöpping
#define APAL2CH_EDGE(edge)                                            \
227
  ((edge == APAL_GPIO_EDGE_RISING) ? PAL_EVENT_MODE_RISING_EDGE :     \
228
    (edge == APAL_GPIO_EDGE_FALLING) ? PAL_EVENT_MODE_FALLING_EDGE :  \
229 542939ea Thomas Schöpping
     (edge == APAL_GPIO_EDGE_BOTH) ? PAL_EVENT_MODE_BOTH_EDGES :      \
230
      PAL_EVENT_MODE_DISABLED)
231 e545e620 Thomas Schöpping
232 232ccea6 Thomas Schöpping
/**
233
 * @brief Enable or disable the interrupt event functionality.
234
 *
235
 * @param[in] cgpio   Control GPIO to set.
236
 * @param[in] enable  Flag, indicating whether the interrupt shall be activated (true) or deactivated (false).
237
 *
238
 * @return The status indicates whether the function call was successful.
239
 */
240
static inline apalExitStatus_t apalControlGpioSetInterrupt(const apalControlGpio_t* const cgpio, const bool enable)
241
{
242
  apalDbgAssert(cgpio != NULL);
243
  apalDbgAssert(cgpio->gpio != NULL);
244
245
  if (enable) {
246
    apalDbgAssert(pal_lld_get_line_event(cgpio->gpio->line) != NULL);
247
    palEnableLineEvent(cgpio->gpio->line, APAL2CH_EDGE(cgpio->meta.edge));
248
  } else {
249
    palDisableLineEvent(cgpio->gpio->line);
250
  }
251
252
  return APAL_STATUS_OK;
253
}
254
255 7de0cc90 Thomas Schöpping
#endif /* (HAL_USE_PAL == TRUE) */
256 e545e620 Thomas Schöpping
257
/*============================================================================*/
258
/* PWM                                                                        */
259
/*============================================================================*/
260
261 7de0cc90 Thomas Schöpping
#if (HAL_USE_PWM == TRUE) || defined (__DOXYGEN__)
262 e545e620 Thomas Schöpping
263
/**
264
 * @brief PWM driver type.
265
 */
266
typedef PWMDriver apalPWMDriver_t;
267
268
/**
269
 * @brief   Set the PWM with given parameters.
270
 *
271
 * @param[in] pwm       PWM driver to set.
272
 * @param[in] channel   Channel of the PWM driver to set.
273
 * @param[in] width     Width to set the channel to.
274
 *
275
 * @return  The status indicates whether the function call was successful.
276
 */
277
static inline apalExitStatus_t apalPWMSet(apalPWMDriver_t* pwm, const apalPWMchannel_t channel, const apalPWMwidth_t width)
278
{
279 1f94ac64 Thomas Schöpping
  apalDbgAssert(pwm != NULL);
280 e545e620 Thomas Schöpping
281
  pwmEnableChannel(pwm, (pwmchannel_t)channel, pwm->period * ((float)width / (float)APAL_PWM_WIDTH_MAX) + 0.5f);
282
  return APAL_STATUS_OK;
283
}
284
285
/**
286
 * @brief   Retrieve the current frequency of the PWM.
287
 *
288
 * @param[in]  pwm        PWM driver to read.
289
 * @param[out] frequency  The currently set frequency.
290
 *
291
 * @return  The status indicates whether the function call was successful.
292
 */
293
static inline apalExitStatus_t apalPWMGetFrequency(apalPWMDriver_t* pwm, apalPWMfrequency_t* const frequency)
294
{
295 1f94ac64 Thomas Schöpping
  apalDbgAssert(pwm != NULL);
296
  apalDbgAssert(frequency != NULL);
297 e545e620 Thomas Schöpping
298
  *frequency = pwm->config->frequency;
299
  return APAL_STATUS_OK;
300
}
301
302
/**
303
 * @brief   Retrieve the current period of the PWM.
304
 *
305
 * @param[in]   pwm     PWM driver to read.
306
 * @param[out]  period  The currently set period.
307
 *
308
 * @return  The status indicates whether the function call was successful.
309
 */
310
static inline apalExitStatus_t apalPWMGetPeriod(apalPWMDriver_t* pwm, apalPWMperiod_t* const period)
311
{
312 1f94ac64 Thomas Schöpping
  apalDbgAssert(pwm != NULL);
313
  apalDbgAssert(period != NULL);
314 e545e620 Thomas Schöpping
315
  *period = pwm->period;
316
  return APAL_STATUS_OK;
317
}
318
319 7de0cc90 Thomas Schöpping
#endif /* (HAL_USE_PWM == TRUE) */
320 e545e620 Thomas Schöpping
321
/*============================================================================*/
322
/* QEI                                                                        */
323
/*============================================================================*/
324
325 7de0cc90 Thomas Schöpping
#if (HAL_USE_QEI == TRUE) || defined (__DOXYGEN__)
326 e545e620 Thomas Schöpping
327
/**
328
 * @brief QEI driver type.
329
 */
330
typedef QEIDriver apalQEIDriver_t;
331
332
/**
333
 * @brief Gets the direction of the last transition.
334
 *
335
 * @param[in]   qei         The QEI driver to use.
336
 * @param[out]  direction   The direction of the last transition.
337
 *
338
 * @return The status indicates whether the function call was successful.
339
 */
340
static inline apalExitStatus_t apalQEIGetDirection(apalQEIDriver_t* qei, apalQEIDirection_t* const direction)
341
{
342 1f94ac64 Thomas Schöpping
  apalDbgAssert(qei != NULL);
343
  apalDbgAssert(direction != NULL);
344 e545e620 Thomas Schöpping
345
  *direction = (qei_lld_get_direction(qei)) ? APAL_QEI_DIRECTION_DOWN : APAL_QEI_DIRECTION_UP;
346
347
  return APAL_STATUS_OK;
348
}
349
350
/**
351
 * @brief Gets the current position of the ecnoder.
352
 *
353
 * @param[in]   qei       The QEI driver to use.
354
 * @param[out]  position  The current position of the encoder.
355
 *
356
 * @return The status indicates whether the function call was successful.
357
 */
358
static inline apalExitStatus_t apalQEIGetPosition(apalQEIDriver_t* qei, apalQEICount_t* const position)
359
{
360 1f94ac64 Thomas Schöpping
  apalDbgAssert(qei != NULL);
361
  apalDbgAssert(position != NULL);
362 e545e620 Thomas Schöpping
363
  *position = qei_lld_get_position(qei);
364
365
  return APAL_STATUS_OK;
366
}
367
368
/**
369
 * @brief Gets the value range of the encoder.
370
 *
371
 * @param[in]   qei     The QEI driver to use.
372
 * @param[out]  range   The value range of the encoder.
373
 *
374
 * @return The status indicates whether the function call was successful.
375
 */
376
static inline apalExitStatus_t apalQEIGetRange(apalQEIDriver_t* qei, apalQEICount_t* const range)
377
{
378 1f94ac64 Thomas Schöpping
  apalDbgAssert(qei != NULL);
379
  apalDbgAssert(range != NULL);
380 e545e620 Thomas Schöpping
381
  *range = qei_lld_get_range(qei);
382
383
  return APAL_STATUS_OK;
384
}
385
386 7de0cc90 Thomas Schöpping
#endif /* (HAL_USE_QEI == TRUE) */
387 e545e620 Thomas Schöpping
388
/*============================================================================*/
389
/* I2C                                                                        */
390
/*============================================================================*/
391
392 7de0cc90 Thomas Schöpping
#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
393 e545e620 Thomas Schöpping
394
/**
395
 * @brief I2C driver type.
396
 */
397
typedef I2CDriver apalI2CDriver_t;
398
399
/**
400
 * @brief Transmit data and receive a response.
401
 *
402
 * @param[in]   i2cd      The I2C driver to use.
403
 * @param[in]   addr      Address to write to.
404
 * @param[in]   txbuf     Buffer containing data to send.
405
 * @param[in]   txbytes   Number of bytes to send.
406
 * @param[out]  rxbuf     Buffer to store a response to.
407
 * @param[in]   rxbytes   Number of bytes to receive.
408
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
409
 *
410
 * @return The status indicates whether the function call was succesful or a timeout occurred.
411
 */
412
static inline apalExitStatus_t apalI2CMasterTransmit(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, const uint8_t* const txbuf, const size_t txbytes, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
413
{
414 1f94ac64 Thomas Schöpping
  apalDbgAssert(i2cd != NULL);
415 e545e620 Thomas Schöpping
416
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
417 5ab6a6a4 Thomas Schöpping
  // check whether the I2C driver was locked externally
418
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
419
  if (!i2cd_locked_external) {
420
    i2cAcquireBus(i2cd);
421
  }
422 7de0cc90 Thomas Schöpping
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
423 e545e620 Thomas Schöpping
424 1e5f7648 Thomas Schöpping
#pragma GCC diagnostic push
425
#pragma GCC diagnostic ignored "-Wtype-limits"
426 e545e620 Thomas Schöpping
#if defined(STM32F1XX_I2C)
427
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
428
  msg_t status = MSG_OK;
429
  if (rxbytes == 1) {
430
    uint8_t buffer[2];
431 0128be0f Marc Rothmann
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
432 e545e620 Thomas Schöpping
    rxbuf[0] = buffer[0];
433
  } else {
434 0128be0f Marc Rothmann
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
435 e545e620 Thomas Schöpping
  }
436 7de0cc90 Thomas Schöpping
#else /* defined(STM32F1XX_I2C) */
437 0128be0f Marc Rothmann
  const msg_t status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
438 7de0cc90 Thomas Schöpping
#endif /* defined(STM32F1XX_I2C) */
439 1e5f7648 Thomas Schöpping
#pragma GCC diagnostic pop
440 e545e620 Thomas Schöpping
441
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
442 5ab6a6a4 Thomas Schöpping
  if (!i2cd_locked_external) {
443
    i2cReleaseBus(i2cd);
444
  }
445 7de0cc90 Thomas Schöpping
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
446 e545e620 Thomas Schöpping
447
  switch (status)
448
  {
449
    case MSG_OK:
450
#if defined(STM32F1XX_I2C)
451
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
452 7de0cc90 Thomas Schöpping
#else /* defined(STM32F1XX_I2C) */
453 e545e620 Thomas Schöpping
      return APAL_STATUS_OK;
454 7de0cc90 Thomas Schöpping
#endif /* defined(STM32F1XX_I2C) */
455 e545e620 Thomas Schöpping
    case MSG_TIMEOUT:
456
      return APAL_STATUS_TIMEOUT;
457
    case MSG_RESET:
458
    default:
459
      return APAL_STATUS_ERROR;
460
  }
461
}
462
463
/**
464
 * @brief Read data from a specific address.
465
 *
466
 * @param[in]   i2cd      The I2C driver to use.
467
 * @param[in]   addr      Address to read.
468
 * @param[out]  rxbuf     Buffer to store the response to.
469
 * @param[in]   rxbytes   Number of bytes to receive.
470
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
471
 *
472
 * @return The status indicates whether the function call was succesful or a timeout occurred.
473
 */
474
static inline apalExitStatus_t apalI2CMasterReceive(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
475
{
476 1f94ac64 Thomas Schöpping
  apalDbgAssert(i2cd != NULL);
477 e545e620 Thomas Schöpping
478
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
479 5ab6a6a4 Thomas Schöpping
  // check whether the I2C driver was locked externally
480
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
481
  if (!i2cd_locked_external) {
482
    i2cAcquireBus(i2cd);
483
  }
484 7de0cc90 Thomas Schöpping
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
485 e545e620 Thomas Schöpping
486 1e5f7648 Thomas Schöpping
#pragma GCC diagnostic push
487
#pragma GCC diagnostic ignored "-Wtype-limits"
488 e545e620 Thomas Schöpping
#if defined(STM32F1XX_I2C)
489
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
490
  msg_t status = MSG_OK;
491
  if (rxbytes == 1) {
492
    uint8_t buffer[2];
493 0128be0f Marc Rothmann
    status = i2cMasterReceiveTimeout(i2cd, addr, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
494 e545e620 Thomas Schöpping
    rxbuf[0] = buffer[0];
495
  } else {
496 0128be0f Marc Rothmann
    status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
497 e545e620 Thomas Schöpping
  }
498 7de0cc90 Thomas Schöpping
#else /* defined(STM32F1XX_I2C) */
499 0128be0f Marc Rothmann
  const msg_t status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
500 7de0cc90 Thomas Schöpping
#endif /* defined(STM32F1XX_I2C) */
501 1e5f7648 Thomas Schöpping
#pragma GCC diagnostic pop
502 e545e620 Thomas Schöpping
503
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
504 5ab6a6a4 Thomas Schöpping
  if (!i2cd_locked_external) {
505
    i2cReleaseBus(i2cd);
506
  }
507 7de0cc90 Thomas Schöpping
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
508 e545e620 Thomas Schöpping
509
  switch (status)
510
  {
511
    case MSG_OK:
512
#if defined(STM32F1XX_I2C)
513
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
514 7de0cc90 Thomas Schöpping
#else /* defined(STM32F1XX_I2C) */
515 e545e620 Thomas Schöpping
      return APAL_STATUS_OK;
516 7de0cc90 Thomas Schöpping
#endif /* defined(STM32F1XX_I2C) */
517 e545e620 Thomas Schöpping
    case MSG_TIMEOUT:
518
      return APAL_STATUS_TIMEOUT;
519
    case MSG_RESET:
520
    default:
521
      return APAL_STATUS_ERROR;
522
  }
523
}
524
525 7de0cc90 Thomas Schöpping
#endif /* (HAL_USE_I2C == TRUE) */
526 e545e620 Thomas Schöpping
527
/*============================================================================*/
528
/* SPI                                                                        */
529
/*============================================================================*/
530
531 7de0cc90 Thomas Schöpping
#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
532 e545e620 Thomas Schöpping
533
/**
534
 * @brief SPI driver type.
535
 */
536
typedef SPIDriver apalSPIDriver_t;
537
538
/**
539
 * @brief Transmit and receive data from SPI
540
 *
541
 * @param[in]   spid      The SPI driver to use.
542
 * @param[in]   txData    Buffer containing data to send.
543
 * @param[out]  rxData    Buffer to store.
544
 * @param[in]   length    Number of bytes to send.
545
 *
546
 * @return The status indicates whether the function call was succesful.
547
 */
548
static inline apalExitStatus_t apalSPIExchange(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t length)
549
{
550 1f94ac64 Thomas Schöpping
  apalDbgAssert(spid != NULL);
551 e545e620 Thomas Schöpping
552 7de0cc90 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
553 5ab6a6a4 Thomas Schöpping
  // check whether the SPI driver was locked externally
554
  const bool spid_locked_external = spid->mutex.owner == currp;
555
  if (!spid_locked_external) {
556
    spiAcquireBus(spid);
557
  }
558 7de0cc90 Thomas Schöpping
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
559 5ab6a6a4 Thomas Schöpping
560 e545e620 Thomas Schöpping
  spiSelect(spid);
561
  spiExchange(spid, length, txData, rxData);
562
  spiUnselect(spid);
563 5ab6a6a4 Thomas Schöpping
564 7de0cc90 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
565 5ab6a6a4 Thomas Schöpping
  if (!spid_locked_external) {
566
    spiReleaseBus(spid);
567
  }
568 7de0cc90 Thomas Schöpping
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
569 e545e620 Thomas Schöpping
570
  return APAL_STATUS_OK;
571
}
572
573
/**
574
 * @brief Receive data from SPI
575
 *
576
 * @param[in]   spid      The SPI driver to use.
577
 * @param[out]  data      Buffer to store.
578
 * @param[in]   length    Number of bytes to send.
579
 *
580
 * @return The status indicates whether the function call was succesful.
581
 */
582
static inline apalExitStatus_t apalSPIReceive(apalSPIDriver_t* spid, uint8_t* const data, const size_t length)
583
{
584 1f94ac64 Thomas Schöpping
  apalDbgAssert(spid != NULL);
585 e545e620 Thomas Schöpping
586 7de0cc90 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
587 5ab6a6a4 Thomas Schöpping
  // check whether the SPI driver was locked externally
588
  const bool spid_locked_external = spid->mutex.owner == currp;
589
  if (!spid_locked_external) {
590
    spiAcquireBus(spid);
591
  }
592 7de0cc90 Thomas Schöpping
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
593 5ab6a6a4 Thomas Schöpping
594 e545e620 Thomas Schöpping
  spiSelect(spid);
595
  spiReceive(spid, length, data);
596
  spiUnselect(spid);
597 5ab6a6a4 Thomas Schöpping
598 7de0cc90 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
599 5ab6a6a4 Thomas Schöpping
  if (!spid_locked_external) {
600
    spiReleaseBus(spid);
601
  }
602 7de0cc90 Thomas Schöpping
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
603 e545e620 Thomas Schöpping
604
  return APAL_STATUS_OK;
605
}
606
607
/**
608
 * @brief Transmit data to SPI
609
 *
610
 * @param[in]   spid      The SPI driver to use.
611
 * @param[in]   data      Buffer containing data to send.
612
 * @param[in]   length    Number of bytes to send.
613
 *
614
 * @return The status indicates whether the function call was succesful.
615
 */
616
static inline apalExitStatus_t apalSPITransmit(apalSPIDriver_t* spid, const uint8_t* const data, const size_t length)
617
{
618 1f94ac64 Thomas Schöpping
  apalDbgAssert(spid != NULL);
619 e545e620 Thomas Schöpping
620 7de0cc90 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
621 5ab6a6a4 Thomas Schöpping
  // check whether the SPI driver was locked externally
622
  const bool spid_locked_external = spid->mutex.owner == currp;
623
  if (!spid_locked_external) {
624
    spiAcquireBus(spid);
625
  }
626 7de0cc90 Thomas Schöpping
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
627 5ab6a6a4 Thomas Schöpping
628 e545e620 Thomas Schöpping
  spiSelect(spid);
629
  spiSend(spid, length, data);
630
  spiUnselect(spid);
631 5ab6a6a4 Thomas Schöpping
632 7de0cc90 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
633 5ab6a6a4 Thomas Schöpping
  if (!spid_locked_external) {
634
    spiReleaseBus(spid);
635
  }
636 7de0cc90 Thomas Schöpping
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
637 e545e620 Thomas Schöpping
638
  return APAL_STATUS_OK;
639
}
640
641 e251c4e6 Robin Ewers
/**
642 3106e8cc Thomas Schöpping
 * @brief Transmit data to SPI and receive data afterwards without releasing the bus in between.
643 e251c4e6 Robin Ewers
 *
644
 * @param   spid        The SPI driver to use.
645
 * @param   txData      Transmit data buffer.
646
 * @param   rxData      Receive data buffer.
647
 * @param   txLength    Number of bytes to send.
648
 * @param   rxLength    Number of bytes to receive.
649
 *
650
 * @return The status indicates whether the function call was succesful.
651
 */
652
static inline apalExitStatus_t apalSPITransmitAndReceive(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t txLength, const size_t rxLength)
653
{
654 1f94ac64 Thomas Schöpping
  apalDbgAssert(spid != NULL);
655 e251c4e6 Robin Ewers
656 7de0cc90 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
657 5ab6a6a4 Thomas Schöpping
  // check whether the SPI driver was locked externally
658
  const bool spid_locked_external = spid->mutex.owner == currp;
659
  if (!spid_locked_external) {
660
    spiAcquireBus(spid);
661
  }
662 7de0cc90 Thomas Schöpping
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
663 5ab6a6a4 Thomas Schöpping
664 e251c4e6 Robin Ewers
  spiSelect(spid);
665
  spiSend(spid, txLength, txData);
666
  spiReceive(spid, rxLength, rxData);
667
  spiUnselect(spid);
668 5ab6a6a4 Thomas Schöpping
669 7de0cc90 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
670 5ab6a6a4 Thomas Schöpping
  if (!spid_locked_external) {
671
    spiReleaseBus(spid);
672
  }
673 7de0cc90 Thomas Schöpping
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
674 e545e620 Thomas Schöpping
675
  return APAL_STATUS_OK;
676
}
677
678 7de0cc90 Thomas Schöpping
#endif /* (HAL_USE_SPI == TRUE) */
679 1703dfdf Thomas Schöpping
680 6ff06bbf Thomas Schöpping
#endif /* AMIROOS_PERIPHAL_H */