Statistics
| Branch: | Tag: | Revision:

amiro-os / periphery-lld / periphAL.h @ bc7aed20

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