Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (22.9 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
/* DEBUG                                                                      */
49
/*============================================================================*/
50

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

    
53
#if defined(__cplusplus)
54
extern "C" {
55
#endif /* defined(__cplusplus) */
56
  void _apalDbgAssertMsg(const bool c, const char* fmt, ...);
57
  void apalDbgPrintf(const char* fmt, ...);
58
#if defined(__cplusplus)
59
}
60
#endif /* defined(__cplusplus) */
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) _apalDbgAssertMsg(c, "%s(%u): apalDbgAssert failed", __FILE__, __LINE__)
68

    
69

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

    
72
#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

    
82
#endif /* (AMIROOS_CFG_DBG == true) */
83

    
84
/*============================================================================*/
85
/* 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
static inline void apalSleep(apalTime_t us)
94
{
95
  // check if the specified time can be represented by the system
96
  apalDbgAssert(us <= chTimeI2US(TIME_INFINITE));
97

    
98
  const sysinterval_t interval = chTimeUS2I(us);
99
  // TIME_IMMEDIATE makes no sense and would even cause system halt
100
  if (interval != TIME_IMMEDIATE) {
101
    chThdSleep(interval);
102
  }
103
  return;
104
}
105

    
106
/*============================================================================*/
107
/* GPIO                                                                       */
108
/*============================================================================*/
109

    
110
#if (HAL_USE_PAL == TRUE) || defined (__DOXYGEN__)
111

    
112
/**
113
 * @brief GPIO driver type.
114
 */
115
struct apalGpio_t {
116
  ioline_t line;
117
} 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
  apalDbgAssert(gpio != NULL);
130
  apalDbgAssert(val != NULL);
131

    
132
  *val = (palReadLine(gpio->line) == PAL_HIGH) ? APAL_GPIO_HIGH : APAL_GPIO_LOW;
133
  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
  apalDbgAssert(gpio != NULL);
147

    
148
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
149
  syssts_t sysstatus = chSysGetStatusAndLockX();
150
  palWriteLine(gpio->line, (val == APAL_GPIO_HIGH) ? PAL_HIGH : PAL_LOW);
151
  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
  apalDbgAssert(gpio != NULL);
165

    
166
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
167
  syssts_t sysstatus = chSysGetStatusAndLockX();
168
  palWriteLine(gpio->line, (palReadLine(gpio->line) == PAL_HIGH) ? PAL_LOW : PAL_HIGH);
169
  chSysRestoreStatusX(sysstatus);
170
  return APAL_STATUS_OK;
171
}
172

    
173
/**
174
 * @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
 * @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
  apalDbgAssert(cgpio != NULL);
201
  apalDbgAssert(cgpio->gpio != NULL);
202
  apalDbgAssert(val != NULL);
203

    
204
  *val = ((palReadLine(cgpio->gpio->line) == PAL_HIGH) ^ (cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH)) ? APAL_GPIO_OFF : APAL_GPIO_ON;
205
  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
  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

    
222
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
223
  syssts_t sysstatus = chSysGetStatusAndLockX();
224
  palWriteLine(cgpio->gpio->line, ((cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH) ^ (val == APAL_GPIO_ON)) ? PAL_LOW : PAL_HIGH);
225
  chSysRestoreStatusX(sysstatus);
226
  return APAL_STATUS_OK;
227
}
228

    
229
/**
230
 * @brief   Converts an apalGpioEdge_t to an ChibiOS PAL edge.
231
 */
232
#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
     (edge == APAL_GPIO_EDGE_BOTH) ? PAL_EVENT_MODE_BOTH_EDGES :      \
236
      PAL_EVENT_MODE_DISABLED)
237

    
238
/**
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
#endif /* (HAL_USE_PAL == TRUE) */
262

    
263
/*============================================================================*/
264
/* PWM                                                                        */
265
/*============================================================================*/
266

    
267
#if (HAL_USE_PWM == TRUE) || defined (__DOXYGEN__)
268

    
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
  apalDbgAssert(pwm != NULL);
286

    
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
  apalDbgAssert(pwm != NULL);
302
  apalDbgAssert(frequency != NULL);
303

    
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
  apalDbgAssert(pwm != NULL);
319
  apalDbgAssert(period != NULL);
320

    
321
  *period = pwm->period;
322
  return APAL_STATUS_OK;
323
}
324

    
325
#endif /* (HAL_USE_PWM == TRUE) */
326

    
327
/*============================================================================*/
328
/* QEI                                                                        */
329
/*============================================================================*/
330

    
331
#if (HAL_USE_QEI == TRUE) || defined (__DOXYGEN__)
332

    
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
  apalDbgAssert(qei != NULL);
349
  apalDbgAssert(direction != NULL);
350

    
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
  apalDbgAssert(qei != NULL);
367
  apalDbgAssert(position != NULL);
368

    
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
  apalDbgAssert(qei != NULL);
385
  apalDbgAssert(range != NULL);
386

    
387
  *range = qei_lld_get_range(qei);
388

    
389
  return APAL_STATUS_OK;
390
}
391

    
392
#endif /* (HAL_USE_QEI == TRUE) */
393

    
394
/*============================================================================*/
395
/* I2C                                                                        */
396
/*============================================================================*/
397

    
398
#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
399

    
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
  apalDbgAssert(i2cd != NULL);
421

    
422
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
423
  // 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
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
429

    
430
#pragma GCC diagnostic push
431
#pragma GCC diagnostic ignored "-Wtype-limits"
432
#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
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
438
    rxbuf[0] = buffer[0];
439
  } else {
440
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
441
  }
442
#else /* defined(STM32F1XX_I2C) */
443
  const msg_t status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
444
#endif /* defined(STM32F1XX_I2C) */
445
#pragma GCC diagnostic pop
446

    
447
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
448
  if (!i2cd_locked_external) {
449
    i2cReleaseBus(i2cd);
450
  }
451
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
452

    
453
  switch (status)
454
  {
455
    case MSG_OK:
456
#if defined(STM32F1XX_I2C)
457
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
458
#else /* defined(STM32F1XX_I2C) */
459
      return APAL_STATUS_OK;
460
#endif /* defined(STM32F1XX_I2C) */
461
    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
  apalDbgAssert(i2cd != NULL);
483

    
484
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
485
  // 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
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
491

    
492
#pragma GCC diagnostic push
493
#pragma GCC diagnostic ignored "-Wtype-limits"
494
#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
    status = i2cMasterReceiveTimeout(i2cd, addr, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
500
    rxbuf[0] = buffer[0];
501
  } else {
502
    status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
503
  }
504
#else /* defined(STM32F1XX_I2C) */
505
  const msg_t status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
506
#endif /* defined(STM32F1XX_I2C) */
507
#pragma GCC diagnostic pop
508

    
509
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
510
  if (!i2cd_locked_external) {
511
    i2cReleaseBus(i2cd);
512
  }
513
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
514

    
515
  switch (status)
516
  {
517
    case MSG_OK:
518
#if defined(STM32F1XX_I2C)
519
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
520
#else /* defined(STM32F1XX_I2C) */
521
      return APAL_STATUS_OK;
522
#endif /* defined(STM32F1XX_I2C) */
523
    case MSG_TIMEOUT:
524
      return APAL_STATUS_TIMEOUT;
525
    case MSG_RESET:
526
    default:
527
      return APAL_STATUS_ERROR;
528
  }
529
}
530

    
531
#endif /* (HAL_USE_I2C == TRUE) */
532

    
533
/*============================================================================*/
534
/* SPI                                                                        */
535
/*============================================================================*/
536

    
537
#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
538

    
539
/**
540
 * @brief SPI driver type.
541
 */
542
typedef SPIDriver apalSPIDriver_t;
543

    
544
/**
545
 * @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
 * @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
  apalDbgAssert(spid != NULL);
595

    
596
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
597
  // 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
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
603

    
604
  spiSelect(spid);
605
  spiExchange(spid, length, txData, rxData);
606
  spiUnselect(spid);
607

    
608
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
609
  if (!spid_locked_external) {
610
    spiReleaseBus(spid);
611
  }
612
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
613

    
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
  apalDbgAssert(spid != NULL);
629

    
630
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
631
  // 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
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
637

    
638
  spiSelect(spid);
639
  spiReceive(spid, length, data);
640
  spiUnselect(spid);
641

    
642
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
643
  if (!spid_locked_external) {
644
    spiReleaseBus(spid);
645
  }
646
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
647

    
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
  apalDbgAssert(spid != NULL);
663

    
664
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
665
  // 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
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
671

    
672
  spiSelect(spid);
673
  spiSend(spid, length, data);
674
  spiUnselect(spid);
675

    
676
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
677
  if (!spid_locked_external) {
678
    spiReleaseBus(spid);
679
  }
680
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
681

    
682
  return APAL_STATUS_OK;
683
}
684

    
685
/**
686
 * @brief Transmit data to SPI and receive data afterwards without releasing the bus in between.
687
 *
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
  apalDbgAssert(spid != NULL);
699

    
700
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
701
  // 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
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
707

    
708
  spiSelect(spid);
709
  spiSend(spid, txLength, txData);
710
  spiReceive(spid, rxLength, rxData);
711
  spiUnselect(spid);
712

    
713
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
714
  if (!spid_locked_external) {
715
    spiReleaseBus(spid);
716
  }
717
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
718

    
719
  return APAL_STATUS_OK;
720
}
721

    
722
#endif /* (HAL_USE_SPI == TRUE) */
723

    
724
#endif /* AMIROOS_PERIPHAL_H */