Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (20.5 KB)

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

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
#ifndef AMIROOS_PERIPHAL_H
20
#define AMIROOS_PERIPHAL_H
21

    
22
#include <amiro-lld.h>
23

    
24
/*============================================================================*/
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    1
39

    
40
/*============================================================================*/
41
/* DEPENDENCIES                                                               */
42
/*============================================================================*/
43

    
44
#include <aosconf.h>
45
#include <hal.h>
46

    
47

    
48
/*============================================================================*/
49
/* DEBUG                                                                      */
50
/*============================================================================*/
51

    
52
#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
53

    
54
#if defined(__cplusplus)
55
extern "C" {
56
#endif /* defined(__cplusplus) */
57
  void _apalDbgAssertMsg(const bool c, const char* fmt, ...);
58
  void apalDbgPrintf(const char* fmt, ...);
59
#if defined(__cplusplus)
60
}
61
#endif /* defined(__cplusplus) */
62

    
63
/**
64
 * @brief Assert function to check a given condition.
65
 *
66
 * @param[in] c     The condition to check.
67
 */
68
#define apalDbgAssert(c)                                                      \
69
  _apalDbgAssertMsg(c, "%s(%u): apalDbgAssert failed", __FILE__, __LINE__);
70

    
71
#else /* (AMIROOS_CFG_DBG != true) */
72

    
73
#define apalDbgAssert(constition)
74
#define apalDbgAssertMsg(condition, fmt, ...)
75
#define apalDbgPrintf(fmt, ...)
76

    
77
#endif /* (AMIROOS_CFG_DBG == true) */
78

    
79
/*============================================================================*/
80
/* GENERAL                                                                    */
81
/*============================================================================*/
82

    
83
/**
84
 * @brief Delay execution by a specific number of microseconds.
85
 *
86
 * @param[in]   us    Time to sleep until execution continues in microseconds.
87
 */
88
static inline void usleep(apalTime_t us)
89
{
90
  // check if the specified time can be represented by the system
91
  apalDbgAssert(us <= chTimeI2US(TIME_INFINITE));
92

    
93
  const sysinterval_t interval = chTimeUS2I(us);
94
  // TIME_IMMEDIATE makes no sense and would even cause system halt
95
  if (interval != TIME_IMMEDIATE) {
96
    chThdSleep(interval);
97
  }
98
  return;
99
}
100

    
101
/*============================================================================*/
102
/* GPIO                                                                       */
103
/*============================================================================*/
104

    
105
#if (HAL_USE_PAL == TRUE) || defined (__DOXYGEN__)
106

    
107
/**
108
 * @brief GPIO driver type.
109
 */
110
struct apalGpio_t {
111
  ioline_t line;
112
} 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
  apalDbgAssert(gpio != NULL);
125
  apalDbgAssert(val != NULL);
126

    
127
  *val = (palReadLine(gpio->line) == 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
  apalDbgAssert(gpio != NULL);
142

    
143
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
144
  syssts_t sysstatus = chSysGetStatusAndLockX();
145
  palWriteLine(gpio->line, (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
  apalDbgAssert(gpio != NULL);
160

    
161
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
162
  syssts_t sysstatus = chSysGetStatusAndLockX();
163
  palWriteLine(gpio->line, (palReadLine(gpio->line) == 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
  apalDbgAssert(cgpio != NULL);
179
  apalDbgAssert(cgpio->gpio != NULL);
180
  apalDbgAssert(val != NULL);
181

    
182
  *val = ((palReadLine(cgpio->gpio->line) == 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
  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

    
200
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
201
  syssts_t sysstatus = chSysGetStatusAndLockX();
202
  palWriteLine(cgpio->gpio->line, ((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
 * @brief   Converts an apalGpioEdge_t to an ChibiOS PAL edge.
209
 */
210
#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
     (edge == APAL_GPIO_EDGE_BOTH) ? PAL_EVENT_MODE_BOTH_EDGES :      \
214
      PAL_EVENT_MODE_DISABLED)
215

    
216
#endif /* (HAL_USE_PAL == TRUE) */
217

    
218
/*============================================================================*/
219
/* PWM                                                                        */
220
/*============================================================================*/
221

    
222
#if (HAL_USE_PWM == TRUE) || defined (__DOXYGEN__)
223

    
224
/**
225
 * @brief PWM driver type.
226
 */
227
typedef PWMDriver apalPWMDriver_t;
228

    
229
/**
230
 * @brief   Set the PWM with given parameters.
231
 *
232
 * @param[in] pwm       PWM driver to set.
233
 * @param[in] channel   Channel of the PWM driver to set.
234
 * @param[in] width     Width to set the channel to.
235
 *
236
 * @return  The status indicates whether the function call was successful.
237
 */
238
static inline apalExitStatus_t apalPWMSet(apalPWMDriver_t* pwm, const apalPWMchannel_t channel, const apalPWMwidth_t width)
239
{
240
  apalDbgAssert(pwm != NULL);
241

    
242
  pwmEnableChannel(pwm, (pwmchannel_t)channel, pwm->period * ((float)width / (float)APAL_PWM_WIDTH_MAX) + 0.5f);
243
  return APAL_STATUS_OK;
244
}
245

    
246
/**
247
 * @brief   Retrieve the current frequency of the PWM.
248
 *
249
 * @param[in]  pwm        PWM driver to read.
250
 * @param[out] frequency  The currently set frequency.
251
 *
252
 * @return  The status indicates whether the function call was successful.
253
 */
254
static inline apalExitStatus_t apalPWMGetFrequency(apalPWMDriver_t* pwm, apalPWMfrequency_t* const frequency)
255
{
256
  apalDbgAssert(pwm != NULL);
257
  apalDbgAssert(frequency != NULL);
258

    
259
  *frequency = pwm->config->frequency;
260
  return APAL_STATUS_OK;
261
}
262

    
263
/**
264
 * @brief   Retrieve the current period of the PWM.
265
 *
266
 * @param[in]   pwm     PWM driver to read.
267
 * @param[out]  period  The currently set period.
268
 *
269
 * @return  The status indicates whether the function call was successful.
270
 */
271
static inline apalExitStatus_t apalPWMGetPeriod(apalPWMDriver_t* pwm, apalPWMperiod_t* const period)
272
{
273
  apalDbgAssert(pwm != NULL);
274
  apalDbgAssert(period != NULL);
275

    
276
  *period = pwm->period;
277
  return APAL_STATUS_OK;
278
}
279

    
280
#endif /* (HAL_USE_PWM == TRUE) */
281

    
282
/*============================================================================*/
283
/* QEI                                                                        */
284
/*============================================================================*/
285

    
286
#if (HAL_USE_QEI == TRUE) || defined (__DOXYGEN__)
287

    
288
/**
289
 * @brief QEI driver type.
290
 */
291
typedef QEIDriver apalQEIDriver_t;
292

    
293
/**
294
 * @brief Gets the direction of the last transition.
295
 *
296
 * @param[in]   qei         The QEI driver to use.
297
 * @param[out]  direction   The direction of the last transition.
298
 *
299
 * @return The status indicates whether the function call was successful.
300
 */
301
static inline apalExitStatus_t apalQEIGetDirection(apalQEIDriver_t* qei, apalQEIDirection_t* const direction)
302
{
303
  apalDbgAssert(qei != NULL);
304
  apalDbgAssert(direction != NULL);
305

    
306
  *direction = (qei_lld_get_direction(qei)) ? APAL_QEI_DIRECTION_DOWN : APAL_QEI_DIRECTION_UP;
307

    
308
  return APAL_STATUS_OK;
309
}
310

    
311
/**
312
 * @brief Gets the current position of the ecnoder.
313
 *
314
 * @param[in]   qei       The QEI driver to use.
315
 * @param[out]  position  The current position of the encoder.
316
 *
317
 * @return The status indicates whether the function call was successful.
318
 */
319
static inline apalExitStatus_t apalQEIGetPosition(apalQEIDriver_t* qei, apalQEICount_t* const position)
320
{
321
  apalDbgAssert(qei != NULL);
322
  apalDbgAssert(position != NULL);
323

    
324
  *position = qei_lld_get_position(qei);
325

    
326
  return APAL_STATUS_OK;
327
}
328

    
329
/**
330
 * @brief Gets the value range of the encoder.
331
 *
332
 * @param[in]   qei     The QEI driver to use.
333
 * @param[out]  range   The value range of the encoder.
334
 *
335
 * @return The status indicates whether the function call was successful.
336
 */
337
static inline apalExitStatus_t apalQEIGetRange(apalQEIDriver_t* qei, apalQEICount_t* const range)
338
{
339
  apalDbgAssert(qei != NULL);
340
  apalDbgAssert(range != NULL);
341

    
342
  *range = qei_lld_get_range(qei);
343

    
344
  return APAL_STATUS_OK;
345
}
346

    
347
#endif /* (HAL_USE_QEI == TRUE) */
348

    
349
/*============================================================================*/
350
/* I2C                                                                        */
351
/*============================================================================*/
352

    
353
#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
354

    
355
/**
356
 * @brief I2C driver type.
357
 */
358
typedef I2CDriver apalI2CDriver_t;
359

    
360
/**
361
 * @brief Transmit data and receive a response.
362
 *
363
 * @param[in]   i2cd      The I2C driver to use.
364
 * @param[in]   addr      Address to write to.
365
 * @param[in]   txbuf     Buffer containing data to send.
366
 * @param[in]   txbytes   Number of bytes to send.
367
 * @param[out]  rxbuf     Buffer to store a response to.
368
 * @param[in]   rxbytes   Number of bytes to receive.
369
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
370
 *
371
 * @return The status indicates whether the function call was succesful or a timeout occurred.
372
 */
373
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)
374
{
375
  apalDbgAssert(i2cd != NULL);
376

    
377
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
378
  // check whether the I2C driver was locked externally
379
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
380
  if (!i2cd_locked_external) {
381
    i2cAcquireBus(i2cd);
382
  }
383
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
384

    
385
#pragma GCC diagnostic push
386
#pragma GCC diagnostic ignored "-Wtype-limits"
387
#if defined(STM32F1XX_I2C)
388
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
389
  msg_t status = MSG_OK;
390
  if (rxbytes == 1) {
391
    uint8_t buffer[2];
392
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
393
    rxbuf[0] = buffer[0];
394
  } else {
395
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
396
  }
397
#else /* defined(STM32F1XX_I2C) */
398
  const msg_t status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
399
#endif /* defined(STM32F1XX_I2C) */
400
#pragma GCC diagnostic pop
401

    
402
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
403
  if (!i2cd_locked_external) {
404
    i2cReleaseBus(i2cd);
405
  }
406
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
407

    
408
  switch (status)
409
  {
410
    case MSG_OK:
411
#if defined(STM32F1XX_I2C)
412
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
413
#else /* defined(STM32F1XX_I2C) */
414
      return APAL_STATUS_OK;
415
#endif /* defined(STM32F1XX_I2C) */
416
    case MSG_TIMEOUT:
417
      return APAL_STATUS_TIMEOUT;
418
    case MSG_RESET:
419
    default:
420
      return APAL_STATUS_ERROR;
421
  }
422
}
423

    
424
/**
425
 * @brief Read data from a specific address.
426
 *
427
 * @param[in]   i2cd      The I2C driver to use.
428
 * @param[in]   addr      Address to read.
429
 * @param[out]  rxbuf     Buffer to store the response to.
430
 * @param[in]   rxbytes   Number of bytes to receive.
431
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
432
 *
433
 * @return The status indicates whether the function call was succesful or a timeout occurred.
434
 */
435
static inline apalExitStatus_t apalI2CMasterReceive(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
436
{
437
  apalDbgAssert(i2cd != NULL);
438

    
439
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
440
  // check whether the I2C driver was locked externally
441
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
442
  if (!i2cd_locked_external) {
443
    i2cAcquireBus(i2cd);
444
  }
445
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
446

    
447
#pragma GCC diagnostic push
448
#pragma GCC diagnostic ignored "-Wtype-limits"
449
#if defined(STM32F1XX_I2C)
450
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
451
  msg_t status = MSG_OK;
452
  if (rxbytes == 1) {
453
    uint8_t buffer[2];
454
    status = i2cMasterReceiveTimeout(i2cd, addr, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
455
    rxbuf[0] = buffer[0];
456
  } else {
457
    status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
458
  }
459
#else /* defined(STM32F1XX_I2C) */
460
  const msg_t status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
461
#endif /* defined(STM32F1XX_I2C) */
462
#pragma GCC diagnostic pop
463

    
464
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
465
  if (!i2cd_locked_external) {
466
    i2cReleaseBus(i2cd);
467
  }
468
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
469

    
470
  switch (status)
471
  {
472
    case MSG_OK:
473
#if defined(STM32F1XX_I2C)
474
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
475
#else /* defined(STM32F1XX_I2C) */
476
      return APAL_STATUS_OK;
477
#endif /* defined(STM32F1XX_I2C) */
478
    case MSG_TIMEOUT:
479
      return APAL_STATUS_TIMEOUT;
480
    case MSG_RESET:
481
    default:
482
      return APAL_STATUS_ERROR;
483
  }
484
}
485

    
486
#endif /* (HAL_USE_I2C == TRUE) */
487

    
488
/*============================================================================*/
489
/* SPI                                                                        */
490
/*============================================================================*/
491

    
492
#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
493

    
494
/**
495
 * @brief SPI driver type.
496
 */
497
typedef SPIDriver apalSPIDriver_t;
498

    
499
/**
500
 * @brief Transmit and receive data from SPI
501
 *
502
 * @param[in]   spid      The SPI driver to use.
503
 * @param[in]   txData    Buffer containing data to send.
504
 * @param[out]  rxData    Buffer to store.
505
 * @param[in]   length    Number of bytes to send.
506
 *
507
 * @return The status indicates whether the function call was succesful.
508
 */
509
static inline apalExitStatus_t apalSPIExchange(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t length)
510
{
511
  apalDbgAssert(spid != NULL);
512

    
513
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
514
  // check whether the SPI driver was locked externally
515
  const bool spid_locked_external = spid->mutex.owner == currp;
516
  if (!spid_locked_external) {
517
    spiAcquireBus(spid);
518
  }
519
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
520

    
521
  spiSelect(spid);
522
  spiExchange(spid, length, txData, rxData);
523
  spiUnselect(spid);
524

    
525
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
526
  if (!spid_locked_external) {
527
    spiReleaseBus(spid);
528
  }
529
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
530

    
531
  return APAL_STATUS_OK;
532
}
533

    
534
/**
535
 * @brief Receive data from SPI
536
 *
537
 * @param[in]   spid      The SPI driver to use.
538
 * @param[out]  data      Buffer to store.
539
 * @param[in]   length    Number of bytes to send.
540
 *
541
 * @return The status indicates whether the function call was succesful.
542
 */
543
static inline apalExitStatus_t apalSPIReceive(apalSPIDriver_t* spid, uint8_t* const data, const size_t length)
544
{
545
  apalDbgAssert(spid != NULL);
546

    
547
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
548
  // check whether the SPI driver was locked externally
549
  const bool spid_locked_external = spid->mutex.owner == currp;
550
  if (!spid_locked_external) {
551
    spiAcquireBus(spid);
552
  }
553
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
554

    
555
  spiSelect(spid);
556
  spiReceive(spid, length, data);
557
  spiUnselect(spid);
558

    
559
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
560
  if (!spid_locked_external) {
561
    spiReleaseBus(spid);
562
  }
563
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
564

    
565
  return APAL_STATUS_OK;
566
}
567

    
568
/**
569
 * @brief Transmit data to SPI
570
 *
571
 * @param[in]   spid      The SPI driver to use.
572
 * @param[in]   data      Buffer containing data to send.
573
 * @param[in]   length    Number of bytes to send.
574
 *
575
 * @return The status indicates whether the function call was succesful.
576
 */
577
static inline apalExitStatus_t apalSPITransmit(apalSPIDriver_t* spid, const uint8_t* const data, const size_t length)
578
{
579
  apalDbgAssert(spid != NULL);
580

    
581
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
582
  // check whether the SPI driver was locked externally
583
  const bool spid_locked_external = spid->mutex.owner == currp;
584
  if (!spid_locked_external) {
585
    spiAcquireBus(spid);
586
  }
587
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
588

    
589
  spiSelect(spid);
590
  spiSend(spid, length, data);
591
  spiUnselect(spid);
592

    
593
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
594
  if (!spid_locked_external) {
595
    spiReleaseBus(spid);
596
  }
597
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
598

    
599
  return APAL_STATUS_OK;
600
}
601

    
602
/**
603
 * @brief Transmit data to SPI and receive data afterwards without releasing the bus in between.
604
 *
605
 * @param   spid        The SPI driver to use.
606
 * @param   txData      Transmit data buffer.
607
 * @param   rxData      Receive data buffer.
608
 * @param   txLength    Number of bytes to send.
609
 * @param   rxLength    Number of bytes to receive.
610
 *
611
 * @return The status indicates whether the function call was succesful.
612
 */
613
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)
614
{
615
  apalDbgAssert(spid != NULL);
616

    
617
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
618
  // check whether the SPI driver was locked externally
619
  const bool spid_locked_external = spid->mutex.owner == currp;
620
  if (!spid_locked_external) {
621
    spiAcquireBus(spid);
622
  }
623
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
624

    
625
  spiSelect(spid);
626
  spiSend(spid, txLength, txData);
627
  spiReceive(spid, rxLength, rxData);
628
  spiUnselect(spid);
629

    
630
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
631
  if (!spid_locked_external) {
632
    spiReleaseBus(spid);
633
  }
634
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
635

    
636
  return APAL_STATUS_OK;
637
}
638

    
639
#endif /* (HAL_USE_SPI == TRUE) */
640

    
641
#endif /* AMIROOS_PERIPHAL_H */