Statistics
| Branch: | Tag: | Revision:

amiro-os / periphery-lld / aos_periphAL.c @ dd56d656

History | View | Annotate | Download (14.676 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
#include <periphAL.h>
20

    
21
/*============================================================================*/
22
/* DEBUG                                                                      */
23
/*============================================================================*/
24

    
25
#if (AMIROOS_CFG_DBG == true)
26

    
27
#include <amiroos.h>
28
#include <chprintf.h>
29

    
30
void apalDbgAssertMsg(const bool c, const char* fmt, ...)
31
{
32
  if (!c) {
33
    va_list ap;
34

    
35
    va_start(ap, fmt);
36
    chvprintf((BaseSequentialStream*)&aos.iostream, fmt, ap);
37
    va_end(ap);
38
    chThdExit(MSG_RESET);
39
  }
40

    
41
  return;
42
}
43

    
44
int apalDbgPrintf(const char* fmt, ...)
45
{
46
  va_list ap;
47

    
48
  va_start(ap, fmt);
49
  const int chars = chvprintf((BaseSequentialStream*)&aos.iostream, fmt, ap);
50
  va_end(ap);
51

    
52
  return chars;
53
}
54

    
55
#endif /* (AMIROOS_CFG_DBG == true) */
56

    
57
/*============================================================================*/
58
/* TIMING                                                                     */
59
/*============================================================================*/
60

    
61
#if (AMIROOS_CFG_DBG == true)
62

    
63
void apalSleep(apalTime_t us)
64
{
65
  // check if the specified time can be represented by the system
66
  apalDbgAssert(us <= chTimeI2US(TIME_INFINITE));
67

    
68
  const sysinterval_t interval = chTimeUS2I(us);
69
  // TIME_IMMEDIATE makes no sense and would even cause system halt
70
  if (interval != TIME_IMMEDIATE) {
71
    chThdSleep(interval);
72
  }
73

    
74
  return;
75
}
76

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

    
79
/*============================================================================*/
80
/* GPIO                                                                       */
81
/*============================================================================*/
82

    
83
#if (HAL_USE_PAL == TRUE)
84

    
85
apalExitStatus_t apalGpioRead(apalGpio_t* gpio, apalGpioState_t* const val)
86
{
87
  apalDbgAssert(gpio != NULL);
88
  apalDbgAssert(val != NULL);
89

    
90
  *val = (palReadLine(gpio->line) == PAL_HIGH) ? APAL_GPIO_HIGH : APAL_GPIO_LOW;
91

    
92
  return APAL_STATUS_OK;
93
}
94

    
95
apalExitStatus_t apalGpioWrite(apalGpio_t* gpio, const apalGpioState_t val)
96
{
97
  apalDbgAssert(gpio != NULL);
98

    
99
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
100
  syssts_t sysstatus = chSysGetStatusAndLockX();
101
  palWriteLine(gpio->line, (val == APAL_GPIO_HIGH) ? PAL_HIGH : PAL_LOW);
102
  chSysRestoreStatusX(sysstatus);
103

    
104
  return APAL_STATUS_OK;
105
}
106

    
107
apalExitStatus_t apalGpioToggle(apalGpio_t* gpio)
108
{
109
  apalDbgAssert(gpio != NULL);
110

    
111
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
112
  syssts_t sysstatus = chSysGetStatusAndLockX();
113
  palWriteLine(gpio->line, (palReadLine(gpio->line) == PAL_HIGH) ? PAL_LOW : PAL_HIGH);
114
  chSysRestoreStatusX(sysstatus);
115

    
116
  return APAL_STATUS_OK;
117
}
118

    
119
apalExitStatus_t apalGpioIsInterruptEnabled(apalGpio_t* gpio, bool* const enabled)
120
{
121
  apalDbgAssert(gpio != NULL);
122
  apalDbgAssert(enabled != NULL);
123

    
124
  *enabled = palIsLineEventEnabledX(gpio->line);
125

    
126
  return APAL_STATUS_OK;
127
}
128

    
129
apalExitStatus_t apalControlGpioGet(const apalControlGpio_t* const cgpio, apalControlGpioState_t* const val)
130
{
131
  apalDbgAssert(cgpio != NULL);
132
  apalDbgAssert(cgpio->gpio != NULL);
133
  apalDbgAssert(val != NULL);
134

    
135
  *val = ((palReadLine(cgpio->gpio->line) == PAL_HIGH) ^ (cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH)) ? APAL_GPIO_OFF : APAL_GPIO_ON;
136

    
137
  return APAL_STATUS_OK;
138
}
139

    
140
apalExitStatus_t apalControlGpioSet(const apalControlGpio_t* const cgpio, const apalControlGpioState_t val)
141
{
142
  apalDbgAssert(cgpio != NULL);
143
  apalDbgAssert(cgpio->gpio != NULL);
144
  apalDbgAssert(cgpio->meta.direction == APAL_GPIO_DIRECTION_OUTPUT || cgpio->meta.direction == APAL_GPIO_DIRECTION_BIDIRECTIONAL);
145

    
146
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
147
  syssts_t sysstatus = chSysGetStatusAndLockX();
148
  palWriteLine(cgpio->gpio->line, ((cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH) ^ (val == APAL_GPIO_ON)) ? PAL_LOW : PAL_HIGH);
149
  chSysRestoreStatusX(sysstatus);
150

    
151
  return APAL_STATUS_OK;
152
}
153

    
154
apalExitStatus_t apalControlGpioSetInterrupt(const apalControlGpio_t* const cgpio, const bool enable)
155
{
156
  apalDbgAssert(cgpio != NULL);
157
  apalDbgAssert(cgpio->gpio != NULL);
158

    
159
  if (enable) {
160
    apalDbgAssert(pal_lld_get_line_event(cgpio->gpio->line) != NULL);
161
    palEnableLineEvent(cgpio->gpio->line, APAL2CH_EDGE(cgpio->meta.edge));
162
  } else {
163
    palDisableLineEvent(cgpio->gpio->line);
164
  }
165

    
166
  return APAL_STATUS_OK;
167
}
168

    
169
#endif /* (HAL_USE_PAL == TRUE) */
170

    
171
/*============================================================================*/
172
/* PWM                                                                        */
173
/*============================================================================*/
174

    
175
#if (HAL_USE_PWM == TRUE)
176

    
177
apalExitStatus_t apalPWMSet(apalPWMDriver_t* pwm, const apalPWMchannel_t channel, const apalPWMwidth_t width)
178
{
179
  apalDbgAssert(pwm != NULL);
180

    
181
  pwmEnableChannel(pwm, (pwmchannel_t)channel, pwm->period * ((float)width / (float)APAL_PWM_WIDTH_MAX) + 0.5f);
182

    
183
  return APAL_STATUS_OK;
184
}
185

    
186
apalExitStatus_t apalPWMGetFrequency(apalPWMDriver_t* pwm, apalPWMfrequency_t* const frequency)
187
{
188
  apalDbgAssert(pwm != NULL);
189
  apalDbgAssert(frequency != NULL);
190

    
191
  *frequency = pwm->config->frequency;
192

    
193
  return APAL_STATUS_OK;
194
}
195

    
196
apalExitStatus_t apalPWMGetPeriod(apalPWMDriver_t* pwm, apalPWMperiod_t* const period)
197
{
198
  apalDbgAssert(pwm != NULL);
199
  apalDbgAssert(period != NULL);
200

    
201
  *period = pwm->period;
202

    
203
  return APAL_STATUS_OK;
204
}
205

    
206
#endif /* (HAL_USE_PWM == TRUE) */
207

    
208
/*============================================================================*/
209
/* QEI                                                                        */
210
/*============================================================================*/
211

    
212
#if (HAL_USE_QEI == TRUE)
213

    
214
apalExitStatus_t apalQEIGetDirection(apalQEIDriver_t* qei, apalQEIDirection_t* const direction)
215
{
216
  apalDbgAssert(qei != NULL);
217
  apalDbgAssert(direction != NULL);
218

    
219
  *direction = (qei_lld_get_direction(qei)) ? APAL_QEI_DIRECTION_DOWN : APAL_QEI_DIRECTION_UP;
220

    
221
  return APAL_STATUS_OK;
222
}
223

    
224
apalExitStatus_t apalQEIGetPosition(apalQEIDriver_t* qei, apalQEICount_t* const position)
225
{
226
  apalDbgAssert(qei != NULL);
227
  apalDbgAssert(position != NULL);
228

    
229
  *position = qei_lld_get_position(qei);
230

    
231
  return APAL_STATUS_OK;
232
}
233

    
234
apalExitStatus_t apalQEIGetRange(apalQEIDriver_t* qei, apalQEICount_t* const range)
235
{
236
  apalDbgAssert(qei != NULL);
237
  apalDbgAssert(range != NULL);
238

    
239
  *range = qei_lld_get_range(qei);
240

    
241
  return APAL_STATUS_OK;
242
}
243

    
244
#endif /* (HAL_USE_QEI == TRUE) */
245

    
246
/*============================================================================*/
247
/* I2C                                                                        */
248
/*============================================================================*/
249

    
250
#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
251

    
252
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)
253
{
254
  apalDbgAssert(i2cd != NULL);
255

    
256
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
257
  // check whether the I2C driver was locked externally
258
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
259
  if (!i2cd_locked_external) {
260
    i2cAcquireBus(i2cd);
261
  }
262
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
263

    
264
#pragma GCC diagnostic push
265
#pragma GCC diagnostic ignored "-Wtype-limits"
266
#if defined(STM32F1XX_I2C)
267
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
268
  msg_t status = MSG_OK;
269
  if (rxbytes == 1) {
270
    uint8_t buffer[2];
271
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
272
    rxbuf[0] = buffer[0];
273
  } else {
274
    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
275
  }
276
#else /* defined(STM32F1XX_I2C) */
277
  const msg_t status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
278
#endif /* defined(STM32F1XX_I2C) */
279
#pragma GCC diagnostic pop
280

    
281
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
282
  if (!i2cd_locked_external) {
283
    i2cReleaseBus(i2cd);
284
  }
285
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
286

    
287
  switch (status)
288
  {
289
    case MSG_OK:
290
#if defined(STM32F1XX_I2C)
291
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
292
#else /* defined(STM32F1XX_I2C) */
293
      return APAL_STATUS_OK;
294
#endif /* defined(STM32F1XX_I2C) */
295
    case MSG_TIMEOUT:
296
      return APAL_STATUS_TIMEOUT;
297
    case MSG_RESET:
298
    default:
299
      return APAL_STATUS_ERROR;
300
  }
301
}
302

    
303
apalExitStatus_t apalI2CMasterReceive(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
304
{
305
  apalDbgAssert(i2cd != NULL);
306

    
307
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
308
  // check whether the I2C driver was locked externally
309
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
310
  if (!i2cd_locked_external) {
311
    i2cAcquireBus(i2cd);
312
  }
313
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
314

    
315
#pragma GCC diagnostic push
316
#pragma GCC diagnostic ignored "-Wtype-limits"
317
#if defined(STM32F1XX_I2C)
318
  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
319
  msg_t status = MSG_OK;
320
  if (rxbytes == 1) {
321
    uint8_t buffer[2];
322
    status = i2cMasterReceiveTimeout(i2cd, addr, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
323
    rxbuf[0] = buffer[0];
324
  } else {
325
    status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
326
  }
327
#else /* defined(STM32F1XX_I2C) */
328
  const msg_t status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : TIME_US2I(timeout)) );
329
#endif /* defined(STM32F1XX_I2C) */
330
#pragma GCC diagnostic pop
331

    
332
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
333
  if (!i2cd_locked_external) {
334
    i2cReleaseBus(i2cd);
335
  }
336
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
337

    
338
  switch (status)
339
  {
340
    case MSG_OK:
341
#if defined(STM32F1XX_I2C)
342
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
343
#else /* defined(STM32F1XX_I2C) */
344
      return APAL_STATUS_OK;
345
#endif /* defined(STM32F1XX_I2C) */
346
    case MSG_TIMEOUT:
347
      return APAL_STATUS_TIMEOUT;
348
    case MSG_RESET:
349
    default:
350
      return APAL_STATUS_ERROR;
351
  }
352
}
353

    
354
#endif /* (HAL_USE_I2C == TRUE) */
355

    
356
/*============================================================================*/
357
/* SPI                                                                        */
358
/*============================================================================*/
359

    
360
#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
361

    
362
apalExitStatus_t apalSPITransmit(apalSPIDriver_t* spid, const uint8_t* const data, const size_t length)
363
{
364
  apalDbgAssert(spid != NULL);
365

    
366
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
367
  // check whether the SPI driver was locked externally
368
  const bool spid_locked_external = spid->mutex.owner == currp;
369
  if (!spid_locked_external) {
370
    spiAcquireBus(spid);
371
  }
372
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
373

    
374
  spiSelect(spid);
375
  spiSend(spid, length, data);
376
  spiUnselect(spid);
377

    
378
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
379
  if (!spid_locked_external) {
380
    spiReleaseBus(spid);
381
  }
382
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
383

    
384
  return APAL_STATUS_OK;
385
}
386

    
387
apalExitStatus_t apalSPIReceive(apalSPIDriver_t* spid, uint8_t* const data, const size_t length)
388
{
389
  apalDbgAssert(spid != NULL);
390

    
391
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
392
  // check whether the SPI driver was locked externally
393
  const bool spid_locked_external = spid->mutex.owner == currp;
394
  if (!spid_locked_external) {
395
    spiAcquireBus(spid);
396
  }
397
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
398

    
399
  spiSelect(spid);
400
  spiReceive(spid, length, data);
401
  spiUnselect(spid);
402

    
403
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
404
  if (!spid_locked_external) {
405
    spiReleaseBus(spid);
406
  }
407
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
408

    
409
  return APAL_STATUS_OK;
410
}
411

    
412
apalExitStatus_t apalSPITransmitAndReceive(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t txLength, const size_t rxLength)
413
{
414
  apalDbgAssert(spid != NULL);
415

    
416
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
417
  // check whether the SPI driver was locked externally
418
  const bool spid_locked_external = spid->mutex.owner == currp;
419
  if (!spid_locked_external) {
420
    spiAcquireBus(spid);
421
  }
422
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
423

    
424
  spiSelect(spid);
425
  spiSend(spid, txLength, txData);
426
  spiReceive(spid, rxLength, rxData);
427
  spiUnselect(spid);
428

    
429
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
430
  if (!spid_locked_external) {
431
    spiReleaseBus(spid);
432
  }
433
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
434

    
435
  return APAL_STATUS_OK;
436
}
437

    
438
apalExitStatus_t apalSPIExchange(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t length)
439
{
440
  apalDbgAssert(spid != NULL);
441

    
442
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
443
  // check whether the SPI driver was locked externally
444
  const bool spid_locked_external = spid->mutex.owner == currp;
445
  if (!spid_locked_external) {
446
    spiAcquireBus(spid);
447
  }
448
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
449

    
450
  spiSelect(spid);
451
  spiExchange(spid, length, txData, rxData);
452
  spiUnselect(spid);
453

    
454
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
455
  if (!spid_locked_external) {
456
    spiReleaseBus(spid);
457
  }
458
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
459

    
460
  return APAL_STATUS_OK;
461
}
462

    
463
apalExitStatus_t apalSPIReconfigure(apalSPIDriver_t* spid, const apalSPIConfig_t* config)
464
{
465
  apalDbgAssert(spid != NULL);
466
  apalDbgAssert(config != NULL);
467

    
468
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
469
  // check whether the SPI driver was locked externally
470
  const bool spid_locked_external = spid->mutex.owner == currp;
471
  if (!spid_locked_external) {
472
    spiAcquireBus(spid);
473
  }
474
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
475

    
476
  spiStop(spid);
477
  spiStart(spid, config);
478

    
479
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
480
  if (!spid_locked_external) {
481
    spiReleaseBus(spid);
482
  }
483
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
484

    
485
  return APAL_STATUS_OK;
486
}
487

    
488
#endif /* (HAL_USE_SPI == TRUE) */