Statistics
| Branch: | Tag: | Revision:

amiro-os / periphery-lld / periphAL.h @ 6d5d8856

History | View | Annotate | Download (19.429 KB)

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