Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (19.37 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    0
39

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

    
44
#include <hal.h>
45

    
46
/*============================================================================*/
47
/* GENERAL                                                                    */
48
/*============================================================================*/
49

    
50
/**
51
 * @brief Delay execution by a specific number of microseconds.
52
 *
53
 * @param[in]   us    Time to sleep until execution continues in microseconds.
54
 */
55
static inline void usleep(apalTime_t us)
56
{
57
  // check if the specified time can be represented by the system
58
  chDbgCheck(us <= chTimeI2US(TIME_INFINITE));
59

    
60
  const sysinterval_t interval = chTimeUS2I(us);
61
  // TIME_IMMEDIATE makes no sense and would even cause system halt
62
  if (interval != TIME_IMMEDIATE) {
63
    chThdSleep(interval);
64
  }
65
  return;
66
}
67

    
68
/*============================================================================*/
69
/* GPIO                                                                       */
70
/*============================================================================*/
71

    
72
#if HAL_USE_PAL || defined (__DOXYGEN__)
73

    
74
/**
75
 * @brief GPIO driver type.
76
 */
77
struct apalGpio_t {
78
  ioportid_t port;
79
  iopadid_t pad;
80
} PACKED_VAR;
81

    
82
/**
83
 * @brief Read the current value of a GPIO pin.
84
 *
85
 * @param[in]   gpio  GPIO to read.
86
 * @param[out]  val   Current value of the GPIO.
87
 *
88
 * @return The status indicates whether the function call was successful.
89
 */
90
static inline apalExitStatus_t apalGpioRead(apalGpio_t* gpio, apalGpioState_t* const val)
91
{
92
  chDbgCheck(gpio != NULL);
93
  chDbgCheck(val != NULL);
94

    
95
  *val = (palReadPad(gpio->port, gpio->pad) == PAL_HIGH) ? APAL_GPIO_HIGH : APAL_GPIO_LOW;
96
  return APAL_STATUS_OK;
97
}
98

    
99
/**
100
 * @brief Set the value of a GPIO pin.
101
 *
102
 * @param[in] gpio  GPIO to write.
103
 * @param[in] val   Value to set for the GPIO.
104
 *
105
 * @return The status indicates whether the function call was successful.
106
 */
107
static inline apalExitStatus_t apalGpioWrite(apalGpio_t* gpio, const apalGpioState_t val)
108
{
109
  chDbgCheck(gpio != NULL);
110

    
111
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
112
  syssts_t sysstatus = chSysGetStatusAndLockX();
113
  palWritePad(gpio->port, gpio->pad, (val == APAL_GPIO_HIGH) ? PAL_HIGH : PAL_LOW);
114
  chSysRestoreStatusX(sysstatus);
115
  return APAL_STATUS_OK;
116
}
117

    
118
/**
119
 * @brief Toggle the output of a GPIO.
120
 *
121
 * @param[in] gpio  GPIO to toggle.
122
 *
123
 * @return The status indicates whether the function call was successful.
124
 */
125
static inline apalExitStatus_t apalGpioToggle(apalGpio_t* gpio)
126
{
127
  chDbgCheck(gpio != NULL);
128

    
129
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
130
  syssts_t sysstatus = chSysGetStatusAndLockX();
131
  palWritePad(gpio->port, gpio->pad, (palReadPad(gpio->port, gpio->pad) == PAL_HIGH) ? PAL_LOW : PAL_HIGH);
132
  chSysRestoreStatusX(sysstatus);
133
  return APAL_STATUS_OK;
134
}
135

    
136
/**
137
 * @brief Get the current on/off state of a control GPIO.
138
 *
139
 * @param[in]   gpio  Control GPIO to read.
140
 * @param[out]  val   Current activation status of the control GPIO.
141
 *
142
 * @return The status indicates whether the function call was successful.
143
 */
144
static inline apalExitStatus_t apalControlGpioGet(const apalControlGpio_t* const cgpio, apalControlGpioState_t* const val)
145
{
146
  chDbgCheck(cgpio != NULL);
147
  chDbgCheck(cgpio->gpio != NULL);
148
  chDbgCheck(val != NULL);
149

    
150
  *val = ((palReadPad(cgpio->gpio->port, cgpio->gpio->pad) == PAL_HIGH) ^ (cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH)) ? APAL_GPIO_OFF : APAL_GPIO_ON;
151
  return APAL_STATUS_OK;
152
}
153

    
154
/**
155
 * @brief Turn a control GPIO 'on' or 'off' respectively.
156
 *
157
 * @param[in] gpio  Control GPIO to set.
158
 * @param[in] val   Activation value to set for the control GPIO.
159
 *
160
 * @return The status indicates whether the function call was successful.
161
 */
162
static inline apalExitStatus_t apalControlGpioSet(const apalControlGpio_t* const cgpio, const apalControlGpioState_t val)
163
{
164
  chDbgCheck(cgpio != NULL);
165
  chDbgCheck(cgpio->gpio != NULL);
166
  chDbgCheck(cgpio->meta.direction == APAL_GPIO_DIRECTION_OUTPUT || cgpio->meta.direction == APAL_GPIO_DIRECTION_BIDIRECTIONAL);
167

    
168
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
169
  syssts_t sysstatus = chSysGetStatusAndLockX();
170
  palWritePad(cgpio->gpio->port, cgpio->gpio->pad, ((cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH) ^ (val == APAL_GPIO_ON)) ? PAL_LOW : PAL_HIGH);
171
  chSysRestoreStatusX(sysstatus);
172
  return APAL_STATUS_OK;
173
}
174

    
175
/**
176
 * @brief   Converts an apalGpioEdge_t to an ChibiOS PAL edge.
177
 */
178
#define APAL2CH_EDGE(edge)                                            \
179
  ((edge == APAL_GPIO_EDGE_RISING) ? PAL_EVENT_MODE_RISING_EDGE :     \
180
    (edge == APAL_GPIO_EDGE_FALLING) ? PAL_EVENT_MODE_FALLING_EDGE :  \
181
     (edge == APAL_GPIO_EDGE_BOTH) ? PAL_EVENT_MODE_BOTH_EDGES : 0)
182

    
183
#endif
184

    
185
/*============================================================================*/
186
/* PWM                                                                        */
187
/*============================================================================*/
188

    
189
#if HAL_USE_PWM || defined (__DOXYGEN__)
190

    
191
/**
192
 * @brief PWM driver type.
193
 */
194
typedef PWMDriver apalPWMDriver_t;
195

    
196
/**
197
 * @brief   Set the PWM with given parameters.
198
 *
199
 * @param[in] pwm       PWM driver to set.
200
 * @param[in] channel   Channel of the PWM driver to set.
201
 * @param[in] width     Width to set the channel to.
202
 *
203
 * @return  The status indicates whether the function call was successful.
204
 */
205
static inline apalExitStatus_t apalPWMSet(apalPWMDriver_t* pwm, const apalPWMchannel_t channel, const apalPWMwidth_t width)
206
{
207
  chDbgCheck(pwm != NULL);
208

    
209
  pwmEnableChannel(pwm, (pwmchannel_t)channel, pwm->period * ((float)width / (float)APAL_PWM_WIDTH_MAX) + 0.5f);
210
  return APAL_STATUS_OK;
211
}
212

    
213
/**
214
 * @brief   Retrieve the current frequency of the PWM.
215
 *
216
 * @param[in]  pwm        PWM driver to read.
217
 * @param[out] frequency  The currently set frequency.
218
 *
219
 * @return  The status indicates whether the function call was successful.
220
 */
221
static inline apalExitStatus_t apalPWMGetFrequency(apalPWMDriver_t* pwm, apalPWMfrequency_t* const frequency)
222
{
223
  chDbgCheck(pwm != NULL);
224
  chDbgCheck(frequency != NULL);
225

    
226
  *frequency = pwm->config->frequency;
227
  return APAL_STATUS_OK;
228
}
229

    
230
/**
231
 * @brief   Retrieve the current period of the PWM.
232
 *
233
 * @param[in]   pwm     PWM driver to read.
234
 * @param[out]  period  The currently set period.
235
 *
236
 * @return  The status indicates whether the function call was successful.
237
 */
238
static inline apalExitStatus_t apalPWMGetPeriod(apalPWMDriver_t* pwm, apalPWMperiod_t* const period)
239
{
240
  chDbgCheck(pwm != NULL);
241
  chDbgCheck(period != NULL);
242

    
243
  *period = pwm->period;
244
  return APAL_STATUS_OK;
245
}
246

    
247
#endif
248

    
249
/*============================================================================*/
250
/* QEI                                                                        */
251
/*============================================================================*/
252

    
253
#if HAL_USE_QEI || defined (__DOXYGEN__)
254

    
255
/**
256
 * @brief QEI driver type.
257
 */
258
typedef QEIDriver apalQEIDriver_t;
259

    
260
/**
261
 * @brief Gets the direction of the last transition.
262
 *
263
 * @param[in]   qei         The QEI driver to use.
264
 * @param[out]  direction   The direction of the last transition.
265
 *
266
 * @return The status indicates whether the function call was successful.
267
 */
268
static inline apalExitStatus_t apalQEIGetDirection(apalQEIDriver_t* qei, apalQEIDirection_t* const direction)
269
{
270
  chDbgCheck(qei != NULL);
271
  chDbgCheck(direction != NULL);
272

    
273
  *direction = (qei_lld_get_direction(qei)) ? APAL_QEI_DIRECTION_DOWN : APAL_QEI_DIRECTION_UP;
274

    
275
  return APAL_STATUS_OK;
276
}
277

    
278
/**
279
 * @brief Gets the current position of the ecnoder.
280
 *
281
 * @param[in]   qei       The QEI driver to use.
282
 * @param[out]  position  The current position of the encoder.
283
 *
284
 * @return The status indicates whether the function call was successful.
285
 */
286
static inline apalExitStatus_t apalQEIGetPosition(apalQEIDriver_t* qei, apalQEICount_t* const position)
287
{
288
  chDbgCheck(qei != NULL);
289
  chDbgCheck(position != NULL);
290

    
291
  *position = qei_lld_get_position(qei);
292

    
293
  return APAL_STATUS_OK;
294
}
295

    
296
/**
297
 * @brief Gets the value range of the encoder.
298
 *
299
 * @param[in]   qei     The QEI driver to use.
300
 * @param[out]  range   The value range of the encoder.
301
 *
302
 * @return The status indicates whether the function call was successful.
303
 */
304
static inline apalExitStatus_t apalQEIGetRange(apalQEIDriver_t* qei, apalQEICount_t* const range)
305
{
306
  chDbgCheck(qei != NULL);
307
  chDbgCheck(range != NULL);
308

    
309
  *range = qei_lld_get_range(qei);
310

    
311
  return APAL_STATUS_OK;
312
}
313

    
314
#endif
315

    
316
/*============================================================================*/
317
/* I2C                                                                        */
318
/*============================================================================*/
319

    
320
#if HAL_USE_I2C || defined(__DOXYGEN__)
321

    
322
/**
323
 * @brief I2C driver type.
324
 */
325
typedef I2CDriver apalI2CDriver_t;
326

    
327
/**
328
 * @brief Transmit data and receive a response.
329
 *
330
 * @param[in]   i2cd      The I2C driver to use.
331
 * @param[in]   addr      Address to write to.
332
 * @param[in]   txbuf     Buffer containing data to send.
333
 * @param[in]   txbytes   Number of bytes to send.
334
 * @param[out]  rxbuf     Buffer to store a response to.
335
 * @param[in]   rxbytes   Number of bytes to receive.
336
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
337
 *
338
 * @return The status indicates whether the function call was succesful or a timeout occurred.
339
 */
340
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)
341
{
342
  chDbgCheck(i2cd != NULL);
343

    
344
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
345
  // check whether the I2C driver was locked externally
346
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
347
  if (!i2cd_locked_external) {
348
    i2cAcquireBus(i2cd);
349
  }
350
#endif
351

    
352
#pragma GCC diagnostic push
353
#pragma GCC diagnostic ignored "-Wtype-limits"
354
#if defined(STM32F1XX_I2C)
355
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
356
  msg_t status = MSG_OK;
357
  if (rxbytes == 1) {
358
    uint8_t buffer[2];
359
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
360
    rxbuf[0] = buffer[0];
361
  } else {
362
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
363
  }
364
#else
365
  const msg_t status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
366
#endif
367
#pragma GCC diagnostic pop
368

    
369
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
370
  if (!i2cd_locked_external) {
371
    i2cReleaseBus(i2cd);
372
  }
373
#endif
374

    
375
  switch (status)
376
  {
377
    case MSG_OK:
378
#if defined(STM32F1XX_I2C)
379
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
380
#else
381
      return APAL_STATUS_OK;
382
#endif
383
    case MSG_TIMEOUT:
384
      return APAL_STATUS_TIMEOUT;
385
    case MSG_RESET:
386
    default:
387
      return APAL_STATUS_ERROR;
388
  }
389
}
390

    
391
/**
392
 * @brief Read data from a specific address.
393
 *
394
 * @param[in]   i2cd      The I2C driver to use.
395
 * @param[in]   addr      Address to read.
396
 * @param[out]  rxbuf     Buffer to store the response to.
397
 * @param[in]   rxbytes   Number of bytes to receive.
398
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
399
 *
400
 * @return The status indicates whether the function call was succesful or a timeout occurred.
401
 */
402
static inline apalExitStatus_t apalI2CMasterReceive(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
403
{
404
  chDbgCheck(i2cd != NULL);
405

    
406
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
407
  // check whether the I2C driver was locked externally
408
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
409
  if (!i2cd_locked_external) {
410
    i2cAcquireBus(i2cd);
411
  }
412
#endif
413

    
414
#pragma GCC diagnostic push
415
#pragma GCC diagnostic ignored "-Wtype-limits"
416
#if defined(STM32F1XX_I2C)
417
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
418
  msg_t status = MSG_OK;
419
  if (rxbytes == 1) {
420
    uint8_t buffer[2];
421
    status = i2cMasterReceiveTimeout(i2cd, addr, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
422
    rxbuf[0] = buffer[0];
423
  } else {
424
    status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
425
  }
426
#else
427
  const msg_t status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
428
#endif
429
#pragma GCC diagnostic pop
430

    
431
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
432
  if (!i2cd_locked_external) {
433
    i2cReleaseBus(i2cd);
434
  }
435
#endif
436

    
437
  switch (status)
438
  {
439
    case MSG_OK:
440
#if defined(STM32F1XX_I2C)
441
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
442
#else
443
      return APAL_STATUS_OK;
444
#endif
445
    case MSG_TIMEOUT:
446
      return APAL_STATUS_TIMEOUT;
447
    case MSG_RESET:
448
    default:
449
      return APAL_STATUS_ERROR;
450
  }
451
}
452

    
453
#endif
454

    
455
/*============================================================================*/
456
/* SPI                                                                        */
457
/*============================================================================*/
458

    
459
#if HAL_USE_SPI || defined(__DOXYGEN__)
460

    
461
/**
462
 * @brief SPI driver type.
463
 */
464
typedef SPIDriver apalSPIDriver_t;
465

    
466
/**
467
 * @brief Transmit and receive data from SPI
468
 *
469
 * @param[in]   spid      The SPI driver to use.
470
 * @param[in]   txData    Buffer containing data to send.
471
 * @param[out]  rxData    Buffer to store.
472
 * @param[in]   length    Number of bytes to send.
473
 *
474
 * @return The status indicates whether the function call was succesful.
475
 */
476
static inline apalExitStatus_t apalSPIExchange(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t length)
477
{
478
  chDbgCheck(spid != NULL);
479

    
480
#if (SPI_USE_MUTUAL_EXCLUSION)
481
  // check whether the SPI driver was locked externally
482
  const bool spid_locked_external = spid->mutex.owner == currp;
483
  if (!spid_locked_external) {
484
    spiAcquireBus(spid);
485
  }
486
#endif
487

    
488
  spiSelect(spid);
489
  spiExchange(spid, length, txData, rxData);
490
  spiUnselect(spid);
491

    
492
#if (SPI_USE_MUTUAL_EXCLUSION)
493
  if (!spid_locked_external) {
494
    spiReleaseBus(spid);
495
  }
496
#endif
497

    
498
  return APAL_STATUS_OK;
499
}
500

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

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

    
522
  spiSelect(spid);
523
  spiReceive(spid, length, data);
524
  spiUnselect(spid);
525

    
526
#if (SPI_USE_MUTUAL_EXCLUSION)
527
  if (!spid_locked_external) {
528
    spiReleaseBus(spid);
529
  }
530
#endif
531

    
532
  return APAL_STATUS_OK;
533
}
534

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

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

    
556
  spiSelect(spid);
557
  spiSend(spid, length, data);
558
  spiUnselect(spid);
559

    
560
#if (SPI_USE_MUTUAL_EXCLUSION)
561
  if (!spid_locked_external) {
562
    spiReleaseBus(spid);
563
  }
564
#endif
565

    
566
  return APAL_STATUS_OK;
567
}
568

    
569
/**
570
 * @brief Transmit data to SPI and receive data afterwards without releasing the bus in between
571
 *
572
 * @param   spid        The SPI driver to use.
573
 * @param   txData      Transmit data buffer.
574
 * @param   rxData      Receive data buffer.
575
 * @param   txLength    Number of bytes to send.
576
 * @param   rxLength    Number of bytes to receive.
577
 *
578
 * @return The status indicates whether the function call was succesful.
579
 */
580
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)
581
{
582
  chDbgCheck(spid != NULL);
583

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

    
592
  spiSelect(spid);
593
  spiSend(spid, txLength, txData);
594
  spiReceive(spid, rxLength, rxData);
595
  spiUnselect(spid);
596

    
597
#if (SPI_USE_MUTUAL_EXCLUSION)
598
  if (!spid_locked_external) {
599
    spiReleaseBus(spid);
600
  }
601
#endif
602

    
603
  return APAL_STATUS_OK;
604
}
605

    
606
#endif
607

    
608
/*============================================================================*/
609
/* DEBUG                                                                      */
610
/*============================================================================*/
611

    
612
/**
613
 * @brief Assert function to check a given condition.
614
 *
615
 * @param[in] c   The condition to check.
616
 */
617
#define apalDbgAssert(c)              chDbgAssert(c, "")
618

    
619

    
620
/**
621
 * @brief Printf function for messages printed only in debug builds.
622
 *
623
 * @param[in] fmt   Formatted string to print.
624
 */
625
#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
626
#define apalDbgPrintf(fmt, ...)       chprintf((BaseSequentialStream*)&aos.iostream, fmt, ##__VA_ARGS__)
627
#else
628
#define apalDbgPrintf(fmt, ...) {                         \
629
  (void)(fmt);                                            \
630
}
631
#endif
632

    
633
#endif /* AMIROOS_PERIPHAL_H */