Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (14.856 KB)

1
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2020  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
#include <amiroos.h>
21

    
22
/*============================================================================*/
23
/* DEBUG                                                                      */
24
/*============================================================================*/
25

    
26
#if (AMIROLLD_CFG_DBG == true) && (AMIROOS_CFG_DBG == true)
27

    
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 /* (AMIROLLD_CFG_DBG == true) && (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
apalTime_t apalGetTime(void)
80
{
81
  aos_timestamp_t uptime;
82
  aosSysGetUptime(&uptime);
83

    
84
  return uptime & ~((apalTime_t)0);
85
}
86

    
87
/*============================================================================*/
88
/* GPIO                                                                       */
89
/*============================================================================*/
90

    
91
#if (HAL_USE_PAL == TRUE)
92

    
93
apalExitStatus_t apalGpioRead(apalGpio_t* gpio, apalGpioState_t* const val)
94
{
95
  apalDbgAssert(gpio != NULL);
96
  apalDbgAssert(val != NULL);
97

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

    
100
  return APAL_STATUS_OK;
101
}
102

    
103
apalExitStatus_t apalGpioWrite(apalGpio_t* gpio, const apalGpioState_t val)
104
{
105
  apalDbgAssert(gpio != NULL);
106

    
107
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
108
  syssts_t sysstatus = chSysGetStatusAndLockX();
109
  palWriteLine(gpio->line, (val == APAL_GPIO_HIGH) ? PAL_HIGH : PAL_LOW);
110
  chSysRestoreStatusX(sysstatus);
111

    
112
  return APAL_STATUS_OK;
113
}
114

    
115
apalExitStatus_t apalGpioToggle(apalGpio_t* gpio)
116
{
117
  apalDbgAssert(gpio != NULL);
118

    
119
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
120
  syssts_t sysstatus = chSysGetStatusAndLockX();
121
  palWriteLine(gpio->line, (palReadLine(gpio->line) == PAL_HIGH) ? PAL_LOW : PAL_HIGH);
122
  chSysRestoreStatusX(sysstatus);
123

    
124
  return APAL_STATUS_OK;
125
}
126

    
127
apalExitStatus_t apalGpioIsInterruptEnabled(apalGpio_t* gpio, bool* const enabled)
128
{
129
  apalDbgAssert(gpio != NULL);
130
  apalDbgAssert(enabled != NULL);
131

    
132
  *enabled = palIsLineEventEnabledX(gpio->line);
133

    
134
  return APAL_STATUS_OK;
135
}
136

    
137
apalExitStatus_t apalControlGpioGet(const apalControlGpio_t* const cgpio, apalControlGpioState_t* const val)
138
{
139
  apalDbgAssert(cgpio != NULL);
140
  apalDbgAssert(cgpio->gpio != NULL);
141
  apalDbgAssert(val != NULL);
142

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

    
145
  return APAL_STATUS_OK;
146
}
147

    
148
apalExitStatus_t apalControlGpioSet(const apalControlGpio_t* const cgpio, const apalControlGpioState_t val)
149
{
150
  apalDbgAssert(cgpio != NULL);
151
  apalDbgAssert(cgpio->gpio != NULL);
152
  apalDbgAssert(cgpio->meta.direction == APAL_GPIO_DIRECTION_OUTPUT || cgpio->meta.direction == APAL_GPIO_DIRECTION_BIDIRECTIONAL);
153

    
154
  // palWriteLine() is not guaranteed to be atomic, thus the scheduler is locked.
155
  syssts_t sysstatus = chSysGetStatusAndLockX();
156
  palWriteLine(cgpio->gpio->line, ((cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH) ^ (val == APAL_GPIO_ON)) ? PAL_LOW : PAL_HIGH);
157
  chSysRestoreStatusX(sysstatus);
158

    
159
  return APAL_STATUS_OK;
160
}
161

    
162
apalExitStatus_t apalControlGpioSetInterrupt(const apalControlGpio_t* const cgpio, const bool enable)
163
{
164
  apalDbgAssert(cgpio != NULL);
165
  apalDbgAssert(cgpio->gpio != NULL);
166

    
167
  if (enable) {
168
    apalDbgAssert(pal_lld_get_line_event(cgpio->gpio->line) != NULL);
169
    palEnableLineEvent(cgpio->gpio->line, APAL2CH_EDGE(cgpio->meta.edge));
170
  } else {
171
    palDisableLineEvent(cgpio->gpio->line);
172
  }
173

    
174
  return APAL_STATUS_OK;
175
}
176

    
177
#endif /* (HAL_USE_PAL == TRUE) */
178

    
179
/*============================================================================*/
180
/* PWM                                                                        */
181
/*============================================================================*/
182

    
183
#if (HAL_USE_PWM == TRUE)
184

    
185
apalExitStatus_t apalPWMSet(apalPWMDriver_t* pwm, const apalPWMchannel_t channel, const apalPWMwidth_t width)
186
{
187
  apalDbgAssert(pwm != NULL);
188

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

    
191
  return APAL_STATUS_OK;
192
}
193

    
194
apalExitStatus_t apalPWMGetFrequency(apalPWMDriver_t* pwm, apalPWMfrequency_t* const frequency)
195
{
196
  apalDbgAssert(pwm != NULL);
197
  apalDbgAssert(frequency != NULL);
198

    
199
  *frequency = pwm->config->frequency;
200

    
201
  return APAL_STATUS_OK;
202
}
203

    
204
apalExitStatus_t apalPWMGetPeriod(apalPWMDriver_t* pwm, apalPWMperiod_t* const period)
205
{
206
  apalDbgAssert(pwm != NULL);
207
  apalDbgAssert(period != NULL);
208

    
209
  *period = pwm->period;
210

    
211
  return APAL_STATUS_OK;
212
}
213

    
214
#endif /* (HAL_USE_PWM == TRUE) */
215

    
216
/*============================================================================*/
217
/* QEI                                                                        */
218
/*============================================================================*/
219

    
220
#if (HAL_USE_QEI == TRUE)
221

    
222
apalExitStatus_t apalQEIGetDirection(apalQEIDriver_t* qei, apalQEIDirection_t* const direction)
223
{
224
  apalDbgAssert(qei != NULL);
225
  apalDbgAssert(direction != NULL);
226

    
227
  *direction = (qei_lld_get_direction(qei)) ? APAL_QEI_DIRECTION_DOWN : APAL_QEI_DIRECTION_UP;
228

    
229
  return APAL_STATUS_OK;
230
}
231

    
232
apalExitStatus_t apalQEIGetPosition(apalQEIDriver_t* qei, apalQEICount_t* const position)
233
{
234
  apalDbgAssert(qei != NULL);
235
  apalDbgAssert(position != NULL);
236

    
237
  *position = qei_lld_get_position(qei);
238

    
239
  return APAL_STATUS_OK;
240
}
241

    
242
apalExitStatus_t apalQEIGetRange(apalQEIDriver_t* qei, apalQEICount_t* const range)
243
{
244
  apalDbgAssert(qei != NULL);
245
  apalDbgAssert(range != NULL);
246

    
247
  *range = qei_lld_get_range(qei);
248

    
249
  return APAL_STATUS_OK;
250
}
251

    
252
#endif /* (HAL_USE_QEI == TRUE) */
253

    
254
/*============================================================================*/
255
/* I2C                                                                        */
256
/*============================================================================*/
257

    
258
#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
259

    
260
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)
261
{
262
  apalDbgAssert(i2cd != NULL);
263

    
264
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
265
  // check whether the I2C driver was locked externally
266
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
267
  if (!i2cd_locked_external) {
268
    i2cAcquireBus(i2cd);
269
  }
270
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
271

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

    
289
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
290
  if (!i2cd_locked_external) {
291
    i2cReleaseBus(i2cd);
292
  }
293
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
294

    
295
  switch (status)
296
  {
297
    case MSG_OK:
298
#if defined(STM32F1XX_I2C)
299
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
300
#else /* defined(STM32F1XX_I2C) */
301
      return APAL_STATUS_OK;
302
#endif /* defined(STM32F1XX_I2C) */
303
    case MSG_TIMEOUT:
304
      return APAL_STATUS_TIMEOUT;
305
    case MSG_RESET:
306
    default:
307
      return APAL_STATUS_ERROR;
308
  }
309
}
310

    
311
apalExitStatus_t apalI2CMasterReceive(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
312
{
313
  apalDbgAssert(i2cd != NULL);
314

    
315
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
316
  // check whether the I2C driver was locked externally
317
  const bool i2cd_locked_external = i2cd->mutex.owner == currp;
318
  if (!i2cd_locked_external) {
319
    i2cAcquireBus(i2cd);
320
  }
321
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
322

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

    
340
#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
341
  if (!i2cd_locked_external) {
342
    i2cReleaseBus(i2cd);
343
  }
344
#endif /* (I2C_USE_MUTUAL_EXCLUSION == TRUE) */
345

    
346
  switch (status)
347
  {
348
    case MSG_OK:
349
#if defined(STM32F1XX_I2C)
350
      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
351
#else /* defined(STM32F1XX_I2C) */
352
      return APAL_STATUS_OK;
353
#endif /* defined(STM32F1XX_I2C) */
354
    case MSG_TIMEOUT:
355
      return APAL_STATUS_TIMEOUT;
356
    case MSG_RESET:
357
    default:
358
      return APAL_STATUS_ERROR;
359
  }
360
}
361

    
362
#endif /* (HAL_USE_I2C == TRUE) */
363

    
364
/*============================================================================*/
365
/* SPI                                                                        */
366
/*============================================================================*/
367

    
368
#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
369

    
370
apalExitStatus_t apalSPITransmit(apalSPIDriver_t* spid, const uint8_t* const data, const size_t length)
371
{
372
  apalDbgAssert(spid != NULL);
373

    
374
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
375
  // check whether the SPI driver was locked externally
376
  const bool spid_locked_external = spid->mutex.owner == currp;
377
  if (!spid_locked_external) {
378
    spiAcquireBus(spid);
379
  }
380
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
381

    
382
  spiSelect(spid);
383
  spiSend(spid, length, data);
384
  spiUnselect(spid);
385

    
386
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
387
  if (!spid_locked_external) {
388
    spiReleaseBus(spid);
389
  }
390
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
391

    
392
  return APAL_STATUS_OK;
393
}
394

    
395
apalExitStatus_t apalSPIReceive(apalSPIDriver_t* spid, uint8_t* const data, const size_t length)
396
{
397
  apalDbgAssert(spid != NULL);
398

    
399
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
400
  // check whether the SPI driver was locked externally
401
  const bool spid_locked_external = spid->mutex.owner == currp;
402
  if (!spid_locked_external) {
403
    spiAcquireBus(spid);
404
  }
405
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
406

    
407
  spiSelect(spid);
408
  spiReceive(spid, length, data);
409
  spiUnselect(spid);
410

    
411
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
412
  if (!spid_locked_external) {
413
    spiReleaseBus(spid);
414
  }
415
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
416

    
417
  return APAL_STATUS_OK;
418
}
419

    
420
apalExitStatus_t apalSPITransmitAndReceive(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t txLength, const size_t rxLength)
421
{
422
  apalDbgAssert(spid != NULL);
423

    
424
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
425
  // check whether the SPI driver was locked externally
426
  const bool spid_locked_external = spid->mutex.owner == currp;
427
  if (!spid_locked_external) {
428
    spiAcquireBus(spid);
429
  }
430
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
431

    
432
  spiSelect(spid);
433
  spiSend(spid, txLength, txData);
434
  spiReceive(spid, rxLength, rxData);
435
  spiUnselect(spid);
436

    
437
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
438
  if (!spid_locked_external) {
439
    spiReleaseBus(spid);
440
  }
441
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
442

    
443
  return APAL_STATUS_OK;
444
}
445

    
446
apalExitStatus_t apalSPIExchange(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t length)
447
{
448
  apalDbgAssert(spid != NULL);
449

    
450
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
451
  // check whether the SPI driver was locked externally
452
  const bool spid_locked_external = spid->mutex.owner == currp;
453
  if (!spid_locked_external) {
454
    spiAcquireBus(spid);
455
  }
456
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
457

    
458
  spiSelect(spid);
459
  spiExchange(spid, length, txData, rxData);
460
  spiUnselect(spid);
461

    
462
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
463
  if (!spid_locked_external) {
464
    spiReleaseBus(spid);
465
  }
466
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
467

    
468
  return APAL_STATUS_OK;
469
}
470

    
471
apalExitStatus_t apalSPIReconfigure(apalSPIDriver_t* spid, const apalSPIConfig_t* config)
472
{
473
  apalDbgAssert(spid != NULL);
474
  apalDbgAssert(config != NULL);
475

    
476
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
477
  // check whether the SPI driver was locked externally
478
  const bool spid_locked_external = spid->mutex.owner == currp;
479
  if (!spid_locked_external) {
480
    spiAcquireBus(spid);
481
  }
482
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
483

    
484
  spiStop(spid);
485
  spiStart(spid, config);
486

    
487
#if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
488
  if (!spid_locked_external) {
489
    spiReleaseBus(spid);
490
  }
491
#endif /* (SPI_USE_MUTUAL_EXCLUSION == TRUE) */
492

    
493
  return APAL_STATUS_OK;
494
}
495

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