Statistics
| Branch: | Tag: | Revision:

amiro-os / periphery-lld / periphAL.h @ 3e1a9c79

History | View | Annotate | Download (17.007 KB)

1
/*
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
  aosDbgCheck(us <= LL_ST2US(TIME_INFINITE));
60

    
61
  const systime_t st = LL_US2ST(us);
62
  // TIME_IMMEDIATE makes no sense and would even cause system halt
63
  if (st != TIME_IMMEDIATE) {
64
    chThdSleep(st);
65
  }
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
  /*
80
   * Workaround, since GPIOv2 (STM32F4XX) uses a different type than GPIOv1 (STM32F1XX).
81
   */
82
  #if defined(STM32F4XX)
83
  stm32_gpio_t* port;
84
  #elif defined(STM32F1XX)
85
  GPIO_TypeDef* port;
86
  #else
87
  void* port;
88
  #endif
89

    
90
  uint8_t pad;
91
} PACKED_VAR;
92

    
93
/**
94
 * @brief Read the current value of a GPIO pin.
95
 *
96
 * @param[in]   gpio  GPIO to read.
97
 * @param[out]  val   Current value of the GPIO.
98
 *
99
 * @return The status indicates whether the function call was successful.
100
 */
101
static inline apalExitStatus_t apalGpioRead(apalGpio_t* gpio, apalGpioState_t* const val)
102
{
103
  aosDbgCheck(gpio != NULL);
104
  aosDbgCheck(val != NULL);
105

    
106
  *val = (palReadPad(gpio->port, gpio->pad) == PAL_HIGH) ? APAL_GPIO_HIGH : APAL_GPIO_LOW;
107
  return APAL_STATUS_OK;
108
}
109

    
110
/**
111
 * @brief Set the value of a GPIO pin.
112
 *
113
 * @param[in] gpio  GPIO to write.
114
 * @param[in] val   Value to set for the GPIO.
115
 *
116
 * @return The status indicates whether the function call was successful.
117
 */
118
static inline apalExitStatus_t apalGpioWrite(apalGpio_t* gpio, const apalGpioState_t val)
119
{
120
  aosDbgCheck(gpio != NULL);
121

    
122
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
123
  syssts_t sysstatus = chSysGetStatusAndLockX();
124
  palWritePad(gpio->port, gpio->pad, (val == APAL_GPIO_HIGH) ? PAL_HIGH : PAL_LOW);
125
  chSysRestoreStatusX(sysstatus);
126
  return APAL_STATUS_OK;
127
}
128

    
129
/**
130
 * @brief Toggle the output of a GPIO.
131
 *
132
 * @param[in] gpio  GPIO to toggle.
133
 *
134
 * @return The status indicates whether the function call was successful.
135
 */
136
static inline apalExitStatus_t apalGpioToggle(apalGpio_t* gpio)
137
{
138
  aosDbgCheck(gpio != NULL);
139

    
140
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
141
  syssts_t sysstatus = chSysGetStatusAndLockX();
142
  palWritePad(gpio->port, gpio->pad, (palReadPad(gpio->port, gpio->pad) == PAL_HIGH) ? PAL_LOW : PAL_HIGH);
143
  chSysRestoreStatusX(sysstatus);
144
  return APAL_STATUS_OK;
145
}
146

    
147
/**
148
 * @brief Get the current on/off state of a control GPIO.
149
 *
150
 * @param[in]   gpio  Control GPIO to read.
151
 * @param[out]  val   Current activation status of the control GPIO.
152
 *
153
 * @return The status indicates whether the function call was successful.
154
 */
155
static inline apalExitStatus_t apalControlGpioGet(const apalControlGpio_t* const cgpio, apalControlGpioState_t* const val)
156
{
157
  aosDbgCheck(cgpio != NULL);
158
  aosDbgCheck(cgpio->gpio != NULL);
159
  aosDbgCheck(val != NULL);
160

    
161
  *val = ((palReadPad(cgpio->gpio->port, cgpio->gpio->pad) == PAL_HIGH) ^ (cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH)) ? APAL_GPIO_OFF : APAL_GPIO_ON;
162
  return APAL_STATUS_OK;
163
}
164

    
165
/**
166
 * @brief Turn a control GPIO 'on' or 'off' respectively.
167
 *
168
 * @param[in] gpio  Control GPIO to set.
169
 * @param[in] val   Activation value to set for the control GPIO.
170
 *
171
 * @return The status indicates whether the function call was successful.
172
 */
173
static inline apalExitStatus_t apalControlGpioSet(const apalControlGpio_t* const cgpio, const apalControlGpioState_t val)
174
{
175
  aosDbgCheck(cgpio != NULL);
176
  aosDbgCheck(cgpio->gpio != NULL);
177
  aosDbgCheck(cgpio->meta.direction == APAL_GPIO_DIRECTION_OUTPUT || cgpio->meta.direction == APAL_GPIO_DIRECTION_BIDIRECTIONAL);
178

    
179
  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
180
  syssts_t sysstatus = chSysGetStatusAndLockX();
181
  palWritePad(cgpio->gpio->port, cgpio->gpio->pad, ((cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH) ^ (val == APAL_GPIO_ON)) ? PAL_LOW : PAL_HIGH);
182
  chSysRestoreStatusX(sysstatus);
183
  return APAL_STATUS_OK;
184
}
185

    
186
#endif
187

    
188
#if HAL_USE_EXT || defined(__DOXYGEN__)
189

    
190
/**
191
 * @brief   Converts an apalGpioEdge_t to an ChibiOS EXT edge.
192
 */
193
#define APAL2CH_EDGE(edge)                                        \
194
  ((edge == APAL_GPIO_EDGE_RISING) ? EXT_CH_MODE_RISING_EDGE :    \
195
    (edge == APAL_GPIO_EDGE_FALLING) ? EXT_CH_MODE_FALLING_EDGE : \
196
     (edge == APAL_GPIO_EDGE_BOTH) ? EXT_CH_MODE_BOTH_EDGES : 0)
197

    
198
#endif
199

    
200
/*============================================================================*/
201
/* PWM                                                                        */
202
/*============================================================================*/
203

    
204
#if HAL_USE_PWM || defined (__DOXYGEN__)
205

    
206
/**
207
 * @brief PWM driver type.
208
 */
209
typedef PWMDriver apalPWMDriver_t;
210

    
211
/**
212
 * @brief   Set the PWM with given parameters.
213
 *
214
 * @param[in] pwm       PWM driver to set.
215
 * @param[in] channel   Channel of the PWM driver to set.
216
 * @param[in] width     Width to set the channel to.
217
 *
218
 * @return  The status indicates whether the function call was successful.
219
 */
220
static inline apalExitStatus_t apalPWMSet(apalPWMDriver_t* pwm, const apalPWMchannel_t channel, const apalPWMwidth_t width)
221
{
222
  aosDbgCheck(pwm != NULL);
223

    
224
  pwmEnableChannel(pwm, (pwmchannel_t)channel, pwm->period * ((float)width / (float)APAL_PWM_WIDTH_MAX) + 0.5f);
225
  return APAL_STATUS_OK;
226
}
227

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

    
241
  *frequency = pwm->config->frequency;
242
  return APAL_STATUS_OK;
243
}
244

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

    
258
  *period = pwm->period;
259
  return APAL_STATUS_OK;
260
}
261

    
262
#endif
263

    
264
/*============================================================================*/
265
/* QEI                                                                        */
266
/*============================================================================*/
267

    
268
#if HAL_USE_QEI || defined (__DOXYGEN__)
269

    
270
/**
271
 * @brief QEI driver type.
272
 */
273
typedef QEIDriver apalQEIDriver_t;
274

    
275
/**
276
 * @brief Gets the direction of the last transition.
277
 *
278
 * @param[in]   qei         The QEI driver to use.
279
 * @param[out]  direction   The direction of the last transition.
280
 *
281
 * @return The status indicates whether the function call was successful.
282
 */
283
static inline apalExitStatus_t apalQEIGetDirection(apalQEIDriver_t* qei, apalQEIDirection_t* const direction)
284
{
285
  aosDbgCheck(qei != NULL);
286
  aosDbgCheck(direction != NULL);
287

    
288
  *direction = (qei_lld_get_direction(qei)) ? APAL_QEI_DIRECTION_DOWN : APAL_QEI_DIRECTION_UP;
289

    
290
  return APAL_STATUS_OK;
291
}
292

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

    
306
  *position = qei_lld_get_position(qei);
307

    
308
  return APAL_STATUS_OK;
309
}
310

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

    
324
  *range = qei_lld_get_range(qei);
325

    
326
  return APAL_STATUS_OK;
327
}
328

    
329
#endif
330

    
331
/*============================================================================*/
332
/* I2C                                                                        */
333
/*============================================================================*/
334

    
335
#if HAL_USE_I2C || defined(__DOXYGEN__)
336

    
337
/**
338
 * @brief I2C driver type.
339
 */
340
typedef I2CDriver apalI2CDriver_t;
341

    
342
/**
343
 * @brief Transmit data and receive a response.
344
 *
345
 * @param[in]   i2cd      The I2C driver to use.
346
 * @param[in]   addr      Address to write to.
347
 * @param[in]   txbuf     Buffer containing data to send.
348
 * @param[in]   txbytes   Number of bytes to send.
349
 * @param[out]  rxbuf     Buffer to store a response to.
350
 * @param[in]   rxbytes   Number of bytes to receive.
351
 * @param[in]   timeout   Timeout for the function to return (in microseconds).
352
 *
353
 * @return The status indicates whether the function call was succesful or a timeout occurred.
354
 */
355
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)
356
{
357
  aosDbgCheck(i2cd != NULL);
358

    
359
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
360
  i2cAcquireBus(i2cd);
361
#endif
362

    
363
#if defined(STM32F1XX_I2C)
364
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
365
  msg_t status = MSG_OK;
366
  if (rxbytes == 1) {
367
    uint8_t buffer[2];
368
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
369
    rxbuf[0] = buffer[0];
370
  } else {
371
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
372
  }
373
#else
374
  const msg_t status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
375
#endif
376

    
377
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
378
  i2cReleaseBus(i2cd);
379
#endif
380

    
381
  switch (status)
382
  {
383
    case MSG_OK:
384
#if defined(STM32F1XX_I2C)
385
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
386
#else
387
      return APAL_STATUS_OK;
388
#endif
389
    case MSG_TIMEOUT:
390
      return APAL_STATUS_TIMEOUT;
391
    case MSG_RESET:
392
    default:
393
      return APAL_STATUS_ERROR;
394
  }
395
}
396

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

    
412
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
413
  i2cAcquireBus(i2cd);
414
#endif
415

    
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 : LL_US2ST(timeout)) );
422
    rxbuf[0] = buffer[0];
423
  } else {
424
    status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
425
  }
426
#else
427
  const msg_t status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
428
#endif
429

    
430
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
431
  i2cReleaseBus(i2cd);
432
#endif
433

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

    
450
#endif
451

    
452
/*============================================================================*/
453
/* SPI                                                                        */
454
/*============================================================================*/
455

    
456
#if HAL_USE_SPI || defined(__DOXYGEN__)
457

    
458
/**
459
 * @brief SPI driver type.
460
 */
461
typedef SPIDriver apalSPIDriver_t;
462

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

    
477
#if (SPI_USE_MUTUAL_EXCLUSION)
478
  spiAcquireBus(spid);
479
#endif
480
  spiSelect(spid);
481
  spiExchange(spid, length, txData, rxData);
482
  spiUnselect(spid);
483
#if (SPI_USE_MUTUAL_EXCLUSION)
484
  spiReleaseBus(spid);
485
#endif
486

    
487
  return APAL_STATUS_OK;
488
}
489

    
490
/**
491
 * @brief Receive data from SPI
492
 *
493
 * @param[in]   spid      The SPI driver to use.
494
 * @param[out]  data      Buffer to store.
495
 * @param[in]   length    Number of bytes to send.
496
 *
497
 * @return The status indicates whether the function call was succesful.
498
 */
499
static inline apalExitStatus_t apalSPIReceive(apalSPIDriver_t* spid, uint8_t* const data, const size_t length)
500
{
501
  aosDbgCheck(spid != NULL);
502

    
503
#if (SPI_USE_MUTUAL_EXCLUSION)
504
  spiAcquireBus(spid);
505
#endif
506
  spiSelect(spid);
507
  spiReceive(spid, length, data);
508
  spiUnselect(spid);
509
#if (SPI_USE_MUTUAL_EXCLUSION)
510
  spiReleaseBus(spid);
511
#endif
512

    
513
  return APAL_STATUS_OK;
514
}
515

    
516
/**
517
 * @brief Transmit data to SPI
518
 *
519
 * @param[in]   spid      The SPI driver to use.
520
 * @param[in]   data      Buffer containing data to send.
521
 * @param[in]   length    Number of bytes to send.
522
 *
523
 * @return The status indicates whether the function call was succesful.
524
 */
525
static inline apalExitStatus_t apalSPITransmit(apalSPIDriver_t* spid, const uint8_t* const data, const size_t length)
526
{
527
  aosDbgCheck(spid != NULL);
528

    
529
#if (SPI_USE_MUTUAL_EXCLUSION)
530
  spiAcquireBus(spid);
531
#endif
532
  spiSelect(spid);
533
  spiSend(spid, length, data);
534
  spiUnselect(spid);
535
#if (SPI_USE_MUTUAL_EXCLUSION)
536
  spiReleaseBus(spid);
537
#endif
538

    
539
  return APAL_STATUS_OK;
540
}
541

    
542
#endif
543

    
544
/*============================================================================*/
545
/* DEBUG                                                                      */
546
/*============================================================================*/
547

    
548
/**
549
 * @brief Assert function to check a given condition.
550
 *
551
 * @param[in] c   The condition to check.
552
 */
553
#define apalDbgAssert(c)   aosDbgAssert(c)
554

    
555
#endif /* _AMIROOS_PERIPHAL_H_ */