Statistics
| Branch: | Tag: | Revision:

amiro-os / periphery-lld / periphAL.h @ 88ce18b7

History | View | Annotate | Download (19.646 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
#define PERIPHAL_VERSION_MINOR    0
39
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
#ifdef __cplusplus
54
extern "C" {
55
#endif
56
  void _apalDbgAssertMsg(const bool c, const char* fmt, ...);
57
  void apalDbgPrintf(const char* fmt, ...);
58
#ifdef __cplusplus
59
}
60
#endif
61
62
/**
63
 * @brief Assert function to check a given condition.
64
 *
65
 * @param[in] c     The condition to check.
66
 */
67
#define apalDbgAssert(c)                                                      \
68
  _apalDbgAssertMsg(c, "%s(%u): apalDbgAssert failed", __FILE__, __LINE__);
69
70
#else /* AMIROOS_CFG_DBG != true */
71
72
#define apalDbgAssert(constition)
73
#define apalDbgAssertMsg(condition, fmt, ...)
74
#define apalDbgPrintf(fmt, ...)
75
76
#endif /* AMIROOS_CFG_DBG */
77
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
static inline void usleep(apalTime_t us)
88
{
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
#if HAL_USE_PAL || defined (__DOXYGEN__)
105
106
/**
107
 * @brief GPIO driver type.
108
 */
109
struct apalGpio_t {
110 1e5f7648 Thomas Schöpping
  ioportid_t port;
111
  iopadid_t pad;
112 e545e620 Thomas Schöpping
} PACKED_VAR;
113
114
/**
115
 * @brief Read the current value of a GPIO pin.
116
 *
117
 * @param[in]   gpio  GPIO to read.
118
 * @param[out]  val   Current value of the GPIO.
119
 *
120
 * @return The status indicates whether the function call was successful.
121
 */
122
static inline apalExitStatus_t apalGpioRead(apalGpio_t* gpio, apalGpioState_t* const val)
123
{
124 1f94ac64 Thomas Schöpping
  apalDbgAssert(gpio != NULL);
125
  apalDbgAssert(val != NULL);
126 e545e620 Thomas Schöpping
127
  *val = (palReadPad(gpio->port, gpio->pad) == PAL_HIGH) ? APAL_GPIO_HIGH : APAL_GPIO_LOW;
128
  return APAL_STATUS_OK;
129
}
130
131
/**
132
 * @brief Set the value of a GPIO pin.
133
 *
134
 * @param[in] gpio  GPIO to write.
135
 * @param[in] val   Value to set for the GPIO.
136
 *
137
 * @return The status indicates whether the function call was successful.
138
 */
139
static inline apalExitStatus_t apalGpioWrite(apalGpio_t* gpio, const apalGpioState_t val)
140
{
141 1f94ac64 Thomas Schöpping
  apalDbgAssert(gpio != NULL);
142 e545e620 Thomas Schöpping
143
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
144
  syssts_t sysstatus = chSysGetStatusAndLockX();
145
  palWritePad(gpio->port, gpio->pad, (val == APAL_GPIO_HIGH) ? PAL_HIGH : PAL_LOW);
146
  chSysRestoreStatusX(sysstatus);
147
  return APAL_STATUS_OK;
148
}
149
150
/**
151
 * @brief Toggle the output of a GPIO.
152
 *
153
 * @param[in] gpio  GPIO to toggle.
154
 *
155
 * @return The status indicates whether the function call was successful.
156
 */
157
static inline apalExitStatus_t apalGpioToggle(apalGpio_t* gpio)
158
{
159 1f94ac64 Thomas Schöpping
  apalDbgAssert(gpio != NULL);
160 e545e620 Thomas Schöpping
161
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
162
  syssts_t sysstatus = chSysGetStatusAndLockX();
163
  palWritePad(gpio->port, gpio->pad, (palReadPad(gpio->port, gpio->pad) == PAL_HIGH) ? PAL_LOW : PAL_HIGH);
164
  chSysRestoreStatusX(sysstatus);
165
  return APAL_STATUS_OK;
166
}
167
168
/**
169
 * @brief Get the current on/off state of a control GPIO.
170
 *
171
 * @param[in]   gpio  Control GPIO to read.
172
 * @param[out]  val   Current activation status of the control GPIO.
173
 *
174
 * @return The status indicates whether the function call was successful.
175
 */
176
static inline apalExitStatus_t apalControlGpioGet(const apalControlGpio_t* const cgpio, apalControlGpioState_t* const val)
177
{
178 1f94ac64 Thomas Schöpping
  apalDbgAssert(cgpio != NULL);
179
  apalDbgAssert(cgpio->gpio != NULL);
180
  apalDbgAssert(val != NULL);
181 e545e620 Thomas Schöpping
182
  *val = ((palReadPad(cgpio->gpio->port, cgpio->gpio->pad) == PAL_HIGH) ^ (cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH)) ? APAL_GPIO_OFF : APAL_GPIO_ON;
183
  return APAL_STATUS_OK;
184
}
185
186
/**
187
 * @brief Turn a control GPIO 'on' or 'off' respectively.
188
 *
189
 * @param[in] gpio  Control GPIO to set.
190
 * @param[in] val   Activation value to set for the control GPIO.
191
 *
192
 * @return The status indicates whether the function call was successful.
193
 */
194
static inline apalExitStatus_t apalControlGpioSet(const apalControlGpio_t* const cgpio, const apalControlGpioState_t val)
195
{
196 1f94ac64 Thomas Schöpping
  apalDbgAssert(cgpio != NULL);
197
  apalDbgAssert(cgpio->gpio != NULL);
198
  apalDbgAssert(cgpio->meta.direction == APAL_GPIO_DIRECTION_OUTPUT || cgpio->meta.direction == APAL_GPIO_DIRECTION_BIDIRECTIONAL);
199 e545e620 Thomas Schöpping
200
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
201
  syssts_t sysstatus = chSysGetStatusAndLockX();
202
  palWritePad(cgpio->gpio->port, cgpio->gpio->pad, ((cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH) ^ (val == APAL_GPIO_ON)) ? PAL_LOW : PAL_HIGH);
203
  chSysRestoreStatusX(sysstatus);
204
  return APAL_STATUS_OK;
205
}
206
207
/**
208 1e5f7648 Thomas Schöpping
 * @brief   Converts an apalGpioEdge_t to an ChibiOS PAL edge.
209 e545e620 Thomas Schöpping
 */
210 1e5f7648 Thomas Schöpping
#define APAL2CH_EDGE(edge)                                            \
211
  ((edge == APAL_GPIO_EDGE_RISING) ? PAL_EVENT_MODE_RISING_EDGE :     \
212
    (edge == APAL_GPIO_EDGE_FALLING) ? PAL_EVENT_MODE_FALLING_EDGE :  \
213 0128be0f Marc Rothmann
     (edge == APAL_GPIO_EDGE_BOTH) ? PAL_EVENT_MODE_BOTH_EDGES : 0)
214 e545e620 Thomas Schöpping
215 1f94ac64 Thomas Schöpping
#endif /* HAL_USE_PAL */
216 e545e620 Thomas Schöpping
217
/*============================================================================*/
218
/* PWM                                                                        */
219
/*============================================================================*/
220
221
#if HAL_USE_PWM || defined (__DOXYGEN__)
222
223
/**
224
 * @brief PWM driver type.
225
 */
226
typedef PWMDriver apalPWMDriver_t;
227
228
/**
229
 * @brief   Set the PWM with given parameters.
230
 *
231
 * @param[in] pwm       PWM driver to set.
232
 * @param[in] channel   Channel of the PWM driver to set.
233
 * @param[in] width     Width to set the channel to.
234
 *
235
 * @return  The status indicates whether the function call was successful.
236
 */
237
static inline apalExitStatus_t apalPWMSet(apalPWMDriver_t* pwm, const apalPWMchannel_t channel, const apalPWMwidth_t width)
238
{
239 1f94ac64 Thomas Schöpping
  apalDbgAssert(pwm != NULL);
240 e545e620 Thomas Schöpping
241
  pwmEnableChannel(pwm, (pwmchannel_t)channel, pwm->period * ((float)width / (float)APAL_PWM_WIDTH_MAX) + 0.5f);
242
  return APAL_STATUS_OK;
243
}
244
245
/**
246
 * @brief   Retrieve the current frequency of the PWM.
247
 *
248
 * @param[in]  pwm        PWM driver to read.
249
 * @param[out] frequency  The currently set frequency.
250
 *
251
 * @return  The status indicates whether the function call was successful.
252
 */
253
static inline apalExitStatus_t apalPWMGetFrequency(apalPWMDriver_t* pwm, apalPWMfrequency_t* const frequency)
254
{
255 1f94ac64 Thomas Schöpping
  apalDbgAssert(pwm != NULL);
256
  apalDbgAssert(frequency != NULL);
257 e545e620 Thomas Schöpping
258
  *frequency = pwm->config->frequency;
259
  return APAL_STATUS_OK;
260
}
261
262
/**
263
 * @brief   Retrieve the current period of the PWM.
264
 *
265
 * @param[in]   pwm     PWM driver to read.
266
 * @param[out]  period  The currently set period.
267
 *
268
 * @return  The status indicates whether the function call was successful.
269
 */
270
static inline apalExitStatus_t apalPWMGetPeriod(apalPWMDriver_t* pwm, apalPWMperiod_t* const period)
271
{
272 1f94ac64 Thomas Schöpping
  apalDbgAssert(pwm != NULL);
273
  apalDbgAssert(period != NULL);
274 e545e620 Thomas Schöpping
275
  *period = pwm->period;
276
  return APAL_STATUS_OK;
277
}
278
279 1f94ac64 Thomas Schöpping
#endif /* HAL_USE_PWM */
280 e545e620 Thomas Schöpping
281
/*============================================================================*/
282
/* QEI                                                                        */
283
/*============================================================================*/
284
285
#if HAL_USE_QEI || defined (__DOXYGEN__)
286
287
/**
288
 * @brief QEI driver type.
289
 */
290
typedef QEIDriver apalQEIDriver_t;
291
292
/**
293
 * @brief Gets the direction of the last transition.
294
 *
295
 * @param[in]   qei         The QEI driver to use.
296
 * @param[out]  direction   The direction of the last transition.
297
 *
298
 * @return The status indicates whether the function call was successful.
299
 */
300
static inline apalExitStatus_t apalQEIGetDirection(apalQEIDriver_t* qei, apalQEIDirection_t* const direction)
301
{
302 1f94ac64 Thomas Schöpping
  apalDbgAssert(qei != NULL);
303
  apalDbgAssert(direction != NULL);
304 e545e620 Thomas Schöpping
305
  *direction = (qei_lld_get_direction(qei)) ? APAL_QEI_DIRECTION_DOWN : APAL_QEI_DIRECTION_UP;
306
307
  return APAL_STATUS_OK;
308
}
309
310
/**
311
 * @brief Gets the current position of the ecnoder.
312
 *
313
 * @param[in]   qei       The QEI driver to use.
314
 * @param[out]  position  The current position of the encoder.
315
 *
316
 * @return The status indicates whether the function call was successful.
317
 */
318
static inline apalExitStatus_t apalQEIGetPosition(apalQEIDriver_t* qei, apalQEICount_t* const position)
319
{
320 1f94ac64 Thomas Schöpping
  apalDbgAssert(qei != NULL);
321
  apalDbgAssert(position != NULL);
322 e545e620 Thomas Schöpping
323
  *position = qei_lld_get_position(qei);
324
325
  return APAL_STATUS_OK;
326
}
327
328
/**
329
 * @brief Gets the value range of the encoder.
330
 *
331
 * @param[in]   qei     The QEI driver to use.
332
 * @param[out]  range   The value range of the encoder.
333
 *
334
 * @return The status indicates whether the function call was successful.
335
 */
336
static inline apalExitStatus_t apalQEIGetRange(apalQEIDriver_t* qei, apalQEICount_t* const range)
337
{
338 1f94ac64 Thomas Schöpping
  apalDbgAssert(qei != NULL);
339
  apalDbgAssert(range != NULL);
340 e545e620 Thomas Schöpping
341
  *range = qei_lld_get_range(qei);
342
343
  return APAL_STATUS_OK;
344
}
345
346 1f94ac64 Thomas Schöpping
#endif /* HAL_USE_QEI */
347 e545e620 Thomas Schöpping
348
/*============================================================================*/
349
/* I2C                                                                        */
350
/*============================================================================*/
351
352
#if HAL_USE_I2C || defined(__DOXYGEN__)
353
354
/**
355
 * @brief I2C driver type.
356
 */
357
typedef I2CDriver apalI2CDriver_t;
358
359
/**
360
 * @brief Transmit data and receive a response.
361
 *
362
 * @param[in]   i2cd      The I2C driver to use.
363
 * @param[in]   addr      Address to write to.
364
 * @param[in]   txbuf     Buffer containing data to send.
365
 * @param[in]   txbytes   Number of bytes to send.
366
 * @param[out]  rxbuf     Buffer to store a response to.
367
 * @param[in]   rxbytes   Number of bytes to receive.
368
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
369
 *
370
 * @return The status indicates whether the function call was succesful or a timeout occurred.
371
 */
372
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)
373
{
374 1f94ac64 Thomas Schöpping
  apalDbgAssert(i2cd != NULL);
375 e545e620 Thomas Schöpping
376
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
377 5ab6a6a4 Thomas Schöpping
  // check whether the I2C driver was locked externally
378
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
379
  if (!i2cd_locked_external) {
380
    i2cAcquireBus(i2cd);
381
  }
382 e545e620 Thomas Schöpping
#endif
383
384 1e5f7648 Thomas Schöpping
#pragma GCC diagnostic push
385
#pragma GCC diagnostic ignored "-Wtype-limits"
386 e545e620 Thomas Schöpping
#if defined(STM32F1XX_I2C)
387
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
388
  msg_t status = MSG_OK;
389
  if (rxbytes == 1) {
390
    uint8_t buffer[2];
391 0128be0f Marc Rothmann
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
392 e545e620 Thomas Schöpping
    rxbuf[0] = buffer[0];
393
  } else {
394 0128be0f Marc Rothmann
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
395 e545e620 Thomas Schöpping
  }
396
#else
397 0128be0f Marc Rothmann
  const msg_t status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
398 e545e620 Thomas Schöpping
#endif
399 1e5f7648 Thomas Schöpping
#pragma GCC diagnostic pop
400 e545e620 Thomas Schöpping
401
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
402 5ab6a6a4 Thomas Schöpping
  if (!i2cd_locked_external) {
403
    i2cReleaseBus(i2cd);
404
  }
405 e545e620 Thomas Schöpping
#endif
406
407
  switch (status)
408
  {
409
    case MSG_OK:
410
#if defined(STM32F1XX_I2C)
411
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
412
#else
413
      return APAL_STATUS_OK;
414
#endif
415
    case MSG_TIMEOUT:
416
      return APAL_STATUS_TIMEOUT;
417
    case MSG_RESET:
418
    default:
419
      return APAL_STATUS_ERROR;
420
  }
421
}
422
423
/**
424
 * @brief Read data from a specific address.
425
 *
426
 * @param[in]   i2cd      The I2C driver to use.
427
 * @param[in]   addr      Address to read.
428
 * @param[out]  rxbuf     Buffer to store the response to.
429
 * @param[in]   rxbytes   Number of bytes to receive.
430
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
431
 *
432
 * @return The status indicates whether the function call was succesful or a timeout occurred.
433
 */
434
static inline apalExitStatus_t apalI2CMasterReceive(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
435
{
436 1f94ac64 Thomas Schöpping
  apalDbgAssert(i2cd != NULL);
437 e545e620 Thomas Schöpping
438
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
439 5ab6a6a4 Thomas Schöpping
  // check whether the I2C driver was locked externally
440
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
441
  if (!i2cd_locked_external) {
442
    i2cAcquireBus(i2cd);
443
  }
444 e545e620 Thomas Schöpping
#endif
445
446 1e5f7648 Thomas Schöpping
#pragma GCC diagnostic push
447
#pragma GCC diagnostic ignored "-Wtype-limits"
448 e545e620 Thomas Schöpping
#if defined(STM32F1XX_I2C)
449
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
450
  msg_t status = MSG_OK;
451
  if (rxbytes == 1) {
452
    uint8_t buffer[2];
453 0128be0f Marc Rothmann
    status = i2cMasterReceiveTimeout(i2cd, addr, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
454 e545e620 Thomas Schöpping
    rxbuf[0] = buffer[0];
455
  } else {
456 0128be0f Marc Rothmann
    status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
457 e545e620 Thomas Schöpping
  }
458
#else
459 0128be0f Marc Rothmann
  const msg_t status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
460 e545e620 Thomas Schöpping
#endif
461 1e5f7648 Thomas Schöpping
#pragma GCC diagnostic pop
462 e545e620 Thomas Schöpping
463
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
464 5ab6a6a4 Thomas Schöpping
  if (!i2cd_locked_external) {
465
    i2cReleaseBus(i2cd);
466
  }
467 e545e620 Thomas Schöpping
#endif
468
469
  switch (status)
470
  {
471
    case MSG_OK:
472
#if defined(STM32F1XX_I2C)
473
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
474
#else
475
      return APAL_STATUS_OK;
476
#endif
477
    case MSG_TIMEOUT:
478
      return APAL_STATUS_TIMEOUT;
479
    case MSG_RESET:
480
    default:
481
      return APAL_STATUS_ERROR;
482
  }
483
}
484
485 1f94ac64 Thomas Schöpping
#endif /* HAL_USE_I2C */
486 e545e620 Thomas Schöpping
487
/*============================================================================*/
488
/* SPI                                                                        */
489
/*============================================================================*/
490
491
#if HAL_USE_SPI || defined(__DOXYGEN__)
492
493
/**
494
 * @brief SPI driver type.
495
 */
496
typedef SPIDriver apalSPIDriver_t;
497
498
/**
499
 * @brief Transmit and receive data from SPI
500
 *
501
 * @param[in]   spid      The SPI driver to use.
502
 * @param[in]   txData    Buffer containing data to send.
503
 * @param[out]  rxData    Buffer to store.
504
 * @param[in]   length    Number of bytes to send.
505
 *
506
 * @return The status indicates whether the function call was succesful.
507
 */
508
static inline apalExitStatus_t apalSPIExchange(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t length)
509
{
510 1f94ac64 Thomas Schöpping
  apalDbgAssert(spid != NULL);
511 e545e620 Thomas Schöpping
512
#if (SPI_USE_MUTUAL_EXCLUSION)
513 5ab6a6a4 Thomas Schöpping
  // check whether the SPI driver was locked externally
514
  const bool spid_locked_external = spid->mutex.owner == currp;
515
  if (!spid_locked_external) {
516
    spiAcquireBus(spid);
517
  }
518 e545e620 Thomas Schöpping
#endif
519 5ab6a6a4 Thomas Schöpping
520 e545e620 Thomas Schöpping
  spiSelect(spid);
521
  spiExchange(spid, length, txData, rxData);
522
  spiUnselect(spid);
523 5ab6a6a4 Thomas Schöpping
524 e545e620 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION)
525 5ab6a6a4 Thomas Schöpping
  if (!spid_locked_external) {
526
    spiReleaseBus(spid);
527
  }
528 e545e620 Thomas Schöpping
#endif
529
530
  return APAL_STATUS_OK;
531
}
532
533
/**
534
 * @brief Receive data from SPI
535
 *
536
 * @param[in]   spid      The SPI driver to use.
537
 * @param[out]  data      Buffer to store.
538
 * @param[in]   length    Number of bytes to send.
539
 *
540
 * @return The status indicates whether the function call was succesful.
541
 */
542
static inline apalExitStatus_t apalSPIReceive(apalSPIDriver_t* spid, uint8_t* const data, const size_t length)
543
{
544 1f94ac64 Thomas Schöpping
  apalDbgAssert(spid != NULL);
545 e545e620 Thomas Schöpping
546
#if (SPI_USE_MUTUAL_EXCLUSION)
547 5ab6a6a4 Thomas Schöpping
  // check whether the SPI driver was locked externally
548
  const bool spid_locked_external = spid->mutex.owner == currp;
549
  if (!spid_locked_external) {
550
    spiAcquireBus(spid);
551
  }
552 e545e620 Thomas Schöpping
#endif
553 5ab6a6a4 Thomas Schöpping
554 e545e620 Thomas Schöpping
  spiSelect(spid);
555
  spiReceive(spid, length, data);
556
  spiUnselect(spid);
557 5ab6a6a4 Thomas Schöpping
558 e545e620 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION)
559 5ab6a6a4 Thomas Schöpping
  if (!spid_locked_external) {
560
    spiReleaseBus(spid);
561
  }
562 e545e620 Thomas Schöpping
#endif
563
564
  return APAL_STATUS_OK;
565
}
566
567
/**
568
 * @brief Transmit data to SPI
569
 *
570
 * @param[in]   spid      The SPI driver to use.
571
 * @param[in]   data      Buffer containing data to send.
572
 * @param[in]   length    Number of bytes to send.
573
 *
574
 * @return The status indicates whether the function call was succesful.
575
 */
576
static inline apalExitStatus_t apalSPITransmit(apalSPIDriver_t* spid, const uint8_t* const data, const size_t length)
577
{
578 1f94ac64 Thomas Schöpping
  apalDbgAssert(spid != NULL);
579 e545e620 Thomas Schöpping
580
#if (SPI_USE_MUTUAL_EXCLUSION)
581 5ab6a6a4 Thomas Schöpping
  // check whether the SPI driver was locked externally
582
  const bool spid_locked_external = spid->mutex.owner == currp;
583
  if (!spid_locked_external) {
584
    spiAcquireBus(spid);
585
  }
586 e545e620 Thomas Schöpping
#endif
587 5ab6a6a4 Thomas Schöpping
588 e545e620 Thomas Schöpping
  spiSelect(spid);
589
  spiSend(spid, length, data);
590
  spiUnselect(spid);
591 5ab6a6a4 Thomas Schöpping
592 e545e620 Thomas Schöpping
#if (SPI_USE_MUTUAL_EXCLUSION)
593 5ab6a6a4 Thomas Schöpping
  if (!spid_locked_external) {
594
    spiReleaseBus(spid);
595
  }
596 e545e620 Thomas Schöpping
#endif
597
598
  return APAL_STATUS_OK;
599
}
600
601 e251c4e6 Robin Ewers
/**
602
 * @brief Transmit data to SPI and receive data afterwards without releasing the bus in between
603
 *
604
 * @param   spid        The SPI driver to use.
605
 * @param   txData      Transmit data buffer.
606
 * @param   rxData      Receive data buffer.
607
 * @param   txLength    Number of bytes to send.
608
 * @param   rxLength    Number of bytes to receive.
609
 *
610
 * @return The status indicates whether the function call was succesful.
611
 */
612
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)
613
{
614 1f94ac64 Thomas Schöpping
  apalDbgAssert(spid != NULL);
615 e251c4e6 Robin Ewers
616
#if (SPI_USE_MUTUAL_EXCLUSION)
617 5ab6a6a4 Thomas Schöpping
  // check whether the SPI driver was locked externally
618
  const bool spid_locked_external = spid->mutex.owner == currp;
619
  if (!spid_locked_external) {
620
    spiAcquireBus(spid);
621
  }
622 e251c4e6 Robin Ewers
#endif
623 5ab6a6a4 Thomas Schöpping
624 e251c4e6 Robin Ewers
  spiSelect(spid);
625
  spiSend(spid, txLength, txData);
626
  spiReceive(spid, rxLength, rxData);
627
  spiUnselect(spid);
628 5ab6a6a4 Thomas Schöpping
629 e251c4e6 Robin Ewers
#if (SPI_USE_MUTUAL_EXCLUSION)
630 5ab6a6a4 Thomas Schöpping
  if (!spid_locked_external) {
631
    spiReleaseBus(spid);
632
  }
633 e545e620 Thomas Schöpping
#endif
634
635
  return APAL_STATUS_OK;
636
}
637
638 1f94ac64 Thomas Schöpping
#endif /* HAL_USE_SPI */
639 1703dfdf Thomas Schöpping
640 6ff06bbf Thomas Schöpping
#endif /* AMIROOS_PERIPHAL_H */