aboutsummaryrefslogtreecommitdiffstats
path: root/os/halnew/src
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2013-08-04 13:38:53 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2013-08-04 13:38:53 +0000
commite619097f77edeceb5e8c38dc7e614c7fccd36cbf (patch)
treed168bb87afd7245e4af1a4420ffc1cbf44600c38 /os/halnew/src
parent7ece1d7e496df82ee78f94b455c02942258d173a (diff)
downloadChibiOS-e619097f77edeceb5e8c38dc7e614c7fccd36cbf.tar.gz
ChibiOS-e619097f77edeceb5e8c38dc7e614c7fccd36cbf.tar.bz2
ChibiOS-e619097f77edeceb5e8c38dc7e614c7fccd36cbf.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/kernel_3_dev@6073 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/halnew/src')
-rw-r--r--os/halnew/src/adc.c326
-rw-r--r--os/halnew/src/can.c284
-rw-r--r--os/halnew/src/hal.c193
-rw-r--r--os/halnew/src/hal_queues.c402
-rw-r--r--os/halnew/src/icu.c158
-rw-r--r--os/halnew/src/pal.c123
-rw-r--r--os/halnew/src/pwm.c204
-rw-r--r--os/halnew/src/serial.c243
-rw-r--r--os/halnew/src/spi.c428
9 files changed, 2361 insertions, 0 deletions
diff --git a/os/halnew/src/adc.c b/os/halnew/src/adc.c
new file mode 100644
index 000000000..ccc11574a
--- /dev/null
+++ b/os/halnew/src/adc.c
@@ -0,0 +1,326 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file adc.c
+ * @brief ADC Driver code.
+ *
+ * @addtogroup ADC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_ADC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief ADC Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void adcInit(void) {
+
+ adc_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p ADCDriver structure.
+ *
+ * @param[out] adcp pointer to the @p ADCDriver object
+ *
+ * @init
+ */
+void adcObjectInit(ADCDriver *adcp) {
+
+ adcp->state = ADC_STOP;
+ adcp->config = NULL;
+ adcp->samples = NULL;
+ adcp->depth = 0;
+ adcp->grpp = NULL;
+#if ADC_USE_WAIT
+ adcp->thread = NULL;
+#endif /* ADC_USE_WAIT */
+#if ADC_USE_MUTUAL_EXCLUSION
+ osalMutexObjectInit(&adcp->mutex);
+#endif /* ADC_USE_MUTUAL_EXCLUSION */
+#if defined(ADC_DRIVER_EXT_INIT_HOOK)
+ ADC_DRIVER_EXT_INIT_HOOK(adcp);
+#endif
+}
+
+/**
+ * @brief Configures and activates the ADC peripheral.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ * @param[in] config pointer to the @p ADCConfig object. Depending on
+ * the implementation the value can be @p NULL.
+ *
+ * @api
+ */
+void adcStart(ADCDriver *adcp, const ADCConfig *config) {
+
+ osalDbgCheck(adcp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY),
+ "adcStart(), #1", "invalid state");
+ adcp->config = config;
+ adc_lld_start(adcp);
+ adcp->state = ADC_READY;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Deactivates the ADC peripheral.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @api
+ */
+void adcStop(ADCDriver *adcp) {
+
+ osalDbgCheck(adcp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY),
+ "adcStop(), #1", "invalid state");
+ adc_lld_stop(adcp);
+ adcp->state = ADC_STOP;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Starts an ADC conversion.
+ * @details Starts an asynchronous conversion operation.
+ * @note The buffer is organized as a matrix of M*N elements where M is the
+ * channels number configured into the conversion group and N is the
+ * buffer depth. The samples are sequentially written into the buffer
+ * with no gaps.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ * @param[in] grpp pointer to a @p ADCConversionGroup object
+ * @param[out] samples pointer to the samples buffer
+ * @param[in] depth buffer depth (matrix rows number). The buffer depth
+ * must be one or an even number.
+ *
+ * @api
+ */
+void adcStartConversion(ADCDriver *adcp,
+ const ADCConversionGroup *grpp,
+ adcsample_t *samples,
+ size_t depth) {
+
+ osalSysLock();
+ adcStartConversionI(adcp, grpp, samples, depth);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Starts an ADC conversion.
+ * @details Starts an asynchronous conversion operation.
+ * @post The callbacks associated to the conversion group will be invoked
+ * on buffer fill and error events.
+ * @note The buffer is organized as a matrix of M*N elements where M is the
+ * channels number configured into the conversion group and N is the
+ * buffer depth. The samples are sequentially written into the buffer
+ * with no gaps.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ * @param[in] grpp pointer to a @p ADCConversionGroup object
+ * @param[out] samples pointer to the samples buffer
+ * @param[in] depth buffer depth (matrix rows number). The buffer depth
+ * must be one or an even number.
+ *
+ * @iclass
+ */
+void adcStartConversionI(ADCDriver *adcp,
+ const ADCConversionGroup *grpp,
+ adcsample_t *samples,
+ size_t depth) {
+
+ osalDbgCheckClassI();
+ osalDbgCheck((adcp != NULL) && (grpp != NULL) && (samples != NULL) &&
+ ((depth == 1) || ((depth & 1) == 0)));
+ osalDbgAssert((adcp->state == ADC_READY) ||
+ (adcp->state == ADC_COMPLETE) ||
+ (adcp->state == ADC_ERROR),
+ "adcStartConversionI(), #1", "not ready");
+
+ adcp->samples = samples;
+ adcp->depth = depth;
+ adcp->grpp = grpp;
+ adcp->state = ADC_ACTIVE;
+ adc_lld_start_conversion(adcp);
+}
+
+/**
+ * @brief Stops an ongoing conversion.
+ * @details This function stops the currently ongoing conversion and returns
+ * the driver in the @p ADC_READY state. If there was no conversion
+ * being processed then the function does nothing.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @api
+ */
+void adcStopConversion(ADCDriver *adcp) {
+
+ osalDbgCheck(adcp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((adcp->state == ADC_READY) ||
+ (adcp->state == ADC_ACTIVE),
+ "adcStopConversion(), #1", "invalid state");
+ if (adcp->state != ADC_READY) {
+ adc_lld_stop_conversion(adcp);
+ adcp->grpp = NULL;
+ adcp->state = ADC_READY;
+ _adc_reset_s(adcp);
+ }
+ osalSysUnlock();
+}
+
+/**
+ * @brief Stops an ongoing conversion.
+ * @details This function stops the currently ongoing conversion and returns
+ * the driver in the @p ADC_READY state. If there was no conversion
+ * being processed then the function does nothing.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @iclass
+ */
+void adcStopConversionI(ADCDriver *adcp) {
+
+ osalDbgCheckClassI();
+ osalDbgCheck(adcp != NULL);
+ osalDbgAssert((adcp->state == ADC_READY) ||
+ (adcp->state == ADC_ACTIVE) ||
+ (adcp->state == ADC_COMPLETE),
+ "adcStopConversionI(), #1", "invalid state");
+
+ if (adcp->state != ADC_READY) {
+ adc_lld_stop_conversion(adcp);
+ adcp->grpp = NULL;
+ adcp->state = ADC_READY;
+ _adc_reset_i(adcp);
+ }
+}
+
+#if ADC_USE_WAIT || defined(__DOXYGEN__)
+/**
+ * @brief Performs an ADC conversion.
+ * @details Performs a synchronous conversion operation.
+ * @note The buffer is organized as a matrix of M*N elements where M is the
+ * channels number configured into the conversion group and N is the
+ * buffer depth. The samples are sequentially written into the buffer
+ * with no gaps.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ * @param[in] grpp pointer to a @p ADCConversionGroup object
+ * @param[out] samples pointer to the samples buffer
+ * @param[in] depth buffer depth (matrix rows number). The buffer depth
+ * must be one or an even number.
+ * @return The operation result.
+ * @retval RDY_OK Conversion finished.
+ * @retval RDY_RESET The conversion has been stopped using
+ * @p acdStopConversion() or @p acdStopConversionI(),
+ * the result buffer may contain incorrect data.
+ * @retval RDY_TIMEOUT The conversion has been stopped because an hardware
+ * error.
+ *
+ * @api
+ */
+msg_t adcConvert(ADCDriver *adcp,
+ const ADCConversionGroup *grpp,
+ adcsample_t *samples,
+ size_t depth) {
+ msg_t msg;
+
+ osalSysLock();
+ osalDbgAssert(adcp->thread == NULL, "adcConvert(), #1", "already waiting");
+ adcStartConversionI(adcp, grpp, samples, depth);
+ msg = osalThreadSuspendS(&adcp->thread);
+ osalSysUnlock();
+ return msg;
+}
+#endif /* ADC_USE_WAIT */
+
+#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+/**
+ * @brief Gains exclusive access to the ADC peripheral.
+ * @details This function tries to gain ownership to the ADC bus, if the bus
+ * is already being used then the invoking thread is queued.
+ * @pre In order to use this function the option
+ * @p ADC_USE_MUTUAL_EXCLUSION must be enabled.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @api
+ */
+void adcAcquireBus(ADCDriver *adcp) {
+
+ osalDbgCheck(adcp != NULL);
+
+ osalMutexLock(&adcp->mutex);
+}
+
+/**
+ * @brief Releases exclusive access to the ADC peripheral.
+ * @pre In order to use this function the option
+ * @p ADC_USE_MUTUAL_EXCLUSION must be enabled.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @api
+ */
+void adcReleaseBus(ADCDriver *adcp) {
+
+ osalDbgCheck(adcp != NULL);
+
+ osalMutexUnlock(&adcp->mutex);
+}
+#endif /* ADC_USE_MUTUAL_EXCLUSION */
+
+#endif /* HAL_USE_ADC */
+
+/** @} */
diff --git a/os/halnew/src/can.c b/os/halnew/src/can.c
new file mode 100644
index 000000000..394e1d6a8
--- /dev/null
+++ b/os/halnew/src/can.c
@@ -0,0 +1,284 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file can.c
+ * @brief CAN Driver code.
+ *
+ * @addtogroup CAN
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_CAN || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief CAN Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void canInit(void) {
+
+ can_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p CANDriver structure.
+ *
+ * @param[out] canp pointer to the @p CANDriver object
+ *
+ * @init
+ */
+void canObjectInit(CANDriver *canp) {
+
+ canp->state = CAN_STOP;
+ canp->config = NULL;
+ osalQueueObjectInit(&canp->txqueue);
+ osalQueueObjectInit(&canp->rxqueue);
+ osalEventObjectInit(&canp->rxfull_event);
+ osalEventObjectInit(&canp->txempty_event);
+ osalEventObjectInit(&canp->error_event);
+#if CAN_USE_SLEEP_MODE
+ osalEventObjectInit(&canp->sleep_event);
+ osalEventObjectInit(&canp->wakeup_event);
+#endif /* CAN_USE_SLEEP_MODE */
+}
+
+/**
+ * @brief Configures and activates the CAN peripheral.
+ * @note Activating the CAN bus can be a slow operation this this function
+ * is not atomic, it waits internally for the initialization to
+ * complete.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] config pointer to the @p CANConfig object. Depending on
+ * the implementation the value can be @p NULL.
+ *
+ * @api
+ */
+void canStart(CANDriver *canp, const CANConfig *config) {
+
+ osalDbgCheck(canp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((canp->state == CAN_STOP) ||
+ (canp->state == CAN_STARTING) ||
+ (canp->state == CAN_READY),
+ "canStart(), #1", "invalid state");
+ while (canp->state == CAN_STARTING)
+ osalThreadSleepS(1);
+ if (canp->state == CAN_STOP) {
+ canp->config = config;
+ can_lld_start(canp);
+ canp->state = CAN_READY;
+ }
+ osalSysUnlock();
+}
+
+/**
+ * @brief Deactivates the CAN peripheral.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @api
+ */
+void canStop(CANDriver *canp) {
+
+ osalDbgCheck(canp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((canp->state == CAN_STOP) || (canp->state == CAN_READY),
+ "canStop(), #1", "invalid state");
+ can_lld_stop(canp);
+ canp->state = CAN_STOP;
+ osalQueueWakeupAllI(&canp->rxqueue, MSG_RESET);
+ osalQueueWakeupAllI(&canp->txqueue, MSG_RESET);
+ osalOsRescheduleS();
+ osalSysUnlock();
+}
+
+/**
+ * @brief Can frame transmission.
+ * @details The specified frame is queued for transmission, if the hardware
+ * queue is full then the invoking thread is queued.
+ * @note Trying to transmit while in sleep mode simply enqueues the thread.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ * @param[in] ctfp pointer to the CAN frame to be transmitted
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_IMMEDIATE immediate timeout.
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation result.
+ * @retval MSG_OK the frame has been queued for transmission.
+ * @retval MSG_TIMEOUT The operation has timed out.
+ * @retval MSG_RESET The driver has been stopped while waiting.
+ *
+ * @api
+ */
+msg_t canTransmit(CANDriver *canp,
+ canmbx_t mailbox,
+ const CANTxFrame *ctfp,
+ systime_t timeout) {
+
+ osalDbgCheck((canp != NULL) && (ctfp != NULL) &&
+ (mailbox <= CAN_TX_MAILBOXES));
+
+ osalSysLock();
+ osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP),
+ "canTransmit(), #1", "invalid state");
+ while ((canp->state == CAN_SLEEP) || !can_lld_is_tx_empty(canp, mailbox)) {
+ msg_t msg = osalQueueGoSleepTimeoutS(&canp->txqueue, timeout);
+ if (msg != MSG_OK) {
+ osalSysUnlock();
+ return msg;
+ }
+ }
+ can_lld_transmit(canp, mailbox, ctfp);
+ osalSysUnlock();
+ return MSG_OK;
+}
+
+/**
+ * @brief Can frame receive.
+ * @details The function waits until a frame is received.
+ * @note Trying to receive while in sleep mode simply enqueues the thread.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
+ * @param[out] crfp pointer to the buffer where the CAN frame is copied
+ * @param[in] timeout the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_IMMEDIATE immediate timeout (useful in an
+ * event driven scenario where a thread never blocks
+ * for I/O).
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation result.
+ * @retval MSG_OK a frame has been received and placed in the buffer.
+ * @retval MSG_TIMEOUT The operation has timed out.
+ * @retval MSG_RESET The driver has been stopped while waiting.
+ *
+ * @api
+ */
+msg_t canReceive(CANDriver *canp,
+ canmbx_t mailbox,
+ CANRxFrame *crfp,
+ systime_t timeout) {
+
+ osalDbgCheck((canp != NULL) && (crfp != NULL) &&
+ (mailbox < CAN_RX_MAILBOXES));
+
+ osalSysLock();
+ osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP),
+ "canReceive(), #1", "invalid state");
+ while ((canp->state == CAN_SLEEP) || !can_lld_is_rx_nonempty(canp, mailbox)) {
+ msg_t msg = osalQueueGoSleepTimeoutS(&canp->rxqueue, timeout);
+ if (msg != MSG_OK) {
+ osalSysUnlock();
+ return msg;
+ }
+ }
+ can_lld_receive(canp, mailbox, crfp);
+ osalSysUnlock();
+ return MSG_OK;
+}
+
+#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__)
+/**
+ * @brief Enters the sleep mode.
+ * @details This function puts the CAN driver in sleep mode and broadcasts
+ * the @p sleep_event event source.
+ * @pre In order to use this function the option @p CAN_USE_SLEEP_MODE must
+ * be enabled and the @p CAN_SUPPORTS_SLEEP mode must be supported
+ * by the low level driver.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @api
+ */
+void canSleep(CANDriver *canp) {
+
+ osalDbgCheck(canp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP),
+ "canSleep(), #1", "invalid state");
+ if (canp->state == CAN_READY) {
+ can_lld_sleep(canp);
+ canp->state = CAN_SLEEP;
+ osalEventBroadcastI(&canp->sleep_event);
+ osalOsRescheduleS();
+ }
+ osalSysUnlock();
+}
+
+/**
+ * @brief Enforces leaving the sleep mode.
+ * @note The sleep mode is supposed to be usually exited automatically by
+ * an hardware event.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ */
+void canWakeup(CANDriver *canp) {
+
+ osalDbgCheck(canp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP),
+ "canWakeup(), #1", "invalid state");
+ if (canp->state == CAN_SLEEP) {
+ can_lld_wakeup(canp);
+ canp->state = CAN_READY;
+ osalEventBroadcastI(&canp->wakeup_event);
+ chSchRescheduleS();
+ }
+ osalSysUnlock();
+}
+#endif /* CAN_USE_SLEEP_MODE */
+
+#endif /* HAL_USE_CAN */
+
+/** @} */
diff --git a/os/halnew/src/hal.c b/os/halnew/src/hal.c
new file mode 100644
index 000000000..c104f5eae
--- /dev/null
+++ b/os/halnew/src/hal.c
@@ -0,0 +1,193 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file hal.c
+ * @brief HAL subsystem code.
+ *
+ * @addtogroup HAL
+ * @{
+ */
+
+#include "hal.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief HAL initialization.
+ * @details This function invokes the low level initialization code then
+ * initializes all the drivers enabled in the HAL. Finally the
+ * board-specific initialization is performed by invoking
+ * @p boardInit() (usually defined in @p board.c).
+ *
+ * @init
+ */
+void halInit(void) {
+
+ hal_lld_init();
+
+#if HAL_USE_TM || defined(__DOXYGEN__)
+ tmInit();
+#endif
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+ palInit(&pal_default_config);
+#endif
+#if HAL_USE_ADC || defined(__DOXYGEN__)
+ adcInit();
+#endif
+#if HAL_USE_CAN || defined(__DOXYGEN__)
+ canInit();
+#endif
+#if HAL_USE_EXT || defined(__DOXYGEN__)
+ extInit();
+#endif
+#if HAL_USE_GPT || defined(__DOXYGEN__)
+ gptInit();
+#endif
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+ i2cInit();
+#endif
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+ icuInit();
+#endif
+#if HAL_USE_MAC || defined(__DOXYGEN__)
+ macInit();
+#endif
+#if HAL_USE_PWM || defined(__DOXYGEN__)
+ pwmInit();
+#endif
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+ sdInit();
+#endif
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+ sdcInit();
+#endif
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+ spiInit();
+#endif
+#if HAL_USE_UART || defined(__DOXYGEN__)
+ uartInit();
+#endif
+#if HAL_USE_USB || defined(__DOXYGEN__)
+ usbInit();
+#endif
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+ mmcInit();
+#endif
+#if HAL_USE_SERIAL_USB || defined(__DOXYGEN__)
+ sduInit();
+#endif
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+ rtcInit();
+#endif
+ /* Board specific initialization.*/
+ boardInit();
+}
+
+#if HAL_IMPLEMENTS_COUNTERS || defined(__DOXYGEN__)
+/**
+ * @brief Realtime window test.
+ * @details This function verifies if the current realtime counter value
+ * lies within the specified range or not. The test takes care
+ * of the realtime counter wrapping to zero on overflow.
+ * @note When start==end then the function returns always true because the
+ * whole time range is specified.
+ * @note This is an optional service that could not be implemented in
+ * all HAL implementations.
+ * @note This function can be called from any context.
+ *
+ * @par Example 1
+ * Example of a guarded loop using the realtime counter. The loop implements
+ * a timeout after one second.
+ * @code
+ * halrtcnt_t start = halGetCounterValue();
+ * halrtcnt_t timeout = start + S2RTT(1);
+ * while (my_condition) {
+ * if (!halIsCounterWithin(start, timeout)
+ * return TIMEOUT;
+ * // Do something.
+ * }
+ * // Continue.
+ * @endcode
+ *
+ * @par Example 2
+ * Example of a loop that lasts exactly 50 microseconds.
+ * @code
+ * halrtcnt_t start = halGetCounterValue();
+ * halrtcnt_t timeout = start + US2RTT(50);
+ * while (halIsCounterWithin(start, timeout)) {
+ * // Do something.
+ * }
+ * // Continue.
+ * @endcode
+ *
+ * @param[in] start the start of the time window (inclusive)
+ * @param[in] end the end of the time window (non inclusive)
+ * @retval TRUE current time within the specified time window.
+ * @retval FALSE current time not within the specified time window.
+ *
+ * @special
+ */
+bool_t halIsCounterWithin(halrtcnt_t start, halrtcnt_t end) {
+ halrtcnt_t now = halGetCounterValue();
+
+ return end > start ? (now >= start) && (now < end) :
+ (now >= start) || (now < end);
+}
+
+/**
+ * @brief Polled delay.
+ * @note The real delays is always few cycles in excess of the specified
+ * value.
+ * @note This is an optional service that could not be implemented in
+ * all HAL implementations.
+ * @note This function can be called from any context.
+ *
+ * @param[in] ticks number of ticks
+ *
+ * @special
+ */
+void halPolledDelay(halrtcnt_t ticks) {
+ halrtcnt_t start = halGetCounterValue();
+ halrtcnt_t timeout = start + (ticks);
+ while (halIsCounterWithin(start, timeout))
+ ;
+}
+#endif /* HAL_IMPLEMENTS_COUNTERS */
+
+/** @} */
diff --git a/os/halnew/src/hal_queues.c b/os/halnew/src/hal_queues.c
new file mode 100644
index 000000000..36016a1e9
--- /dev/null
+++ b/os/halnew/src/hal_queues.c
@@ -0,0 +1,402 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file hal_queues.c
+ * @brief I/O Queues code.
+ *
+ * @addtogroup io_queues
+ * @details ChibiOS/RT queues are mostly used in serial-like device drivers.
+ * The device drivers are usually designed to have a lower side
+ * (lower driver, it is usually an interrupt service routine) and an
+ * upper side (upper driver, accessed by the application threads).<br>
+ * There are several kind of queues:<br>
+ * - <b>Input queue</b>, unidirectional queue where the writer is the
+ * lower side and the reader is the upper side.
+ * - <b>Output queue</b>, unidirectional queue where the writer is the
+ * upper side and the reader is the lower side.
+ * - <b>Full duplex queue</b>, bidirectional queue. Full duplex queues
+ * are implemented by pairing an input queue and an output queue
+ * together.
+ * .
+ * @{
+ */
+
+#include "hal.h"
+
+#if !defined(_CHIBIOS_RT_) || !CH_USE_QUEUES || defined(__DOXYGEN__)
+
+/**
+ * @brief Initializes an input queue.
+ * @details A Semaphore is internally initialized and works as a counter of
+ * the bytes contained in the queue.
+ * @note The callback is invoked from within the S-Locked system state,
+ * see @ref system_states.
+ *
+ * @param[out] iqp pointer to an @p InputQueue structure
+ * @param[in] bp pointer to a memory area allocated as queue buffer
+ * @param[in] size size of the queue buffer
+ * @param[in] infy pointer to a callback function that is invoked when
+ * data is read from the queue. The value can be @p NULL.
+ * @param[in] link application defined pointer
+ *
+ * @init
+ */
+void iqInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy,
+ void *link) {
+
+ osalQueueObjectInit(&iqp->q_waiting);
+ iqp->q_counter = 0;
+ iqp->q_buffer = iqp->q_rdptr = iqp->q_wrptr = bp;
+ iqp->q_top = bp + size;
+ iqp->q_notify = infy;
+ iqp->q_link = link;
+}
+
+/**
+ * @brief Resets an input queue.
+ * @details All the data in the input queue is erased and lost, any waiting
+ * thread is resumed with status @p Q_RESET.
+ * @note A reset operation can be used by a low level driver in order to
+ * obtain immediate attention from the high level layers.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ *
+ * @iclass
+ */
+void iqResetI(InputQueue *iqp) {
+
+ osalDbgCheckClassI();
+
+ iqp->q_rdptr = iqp->q_wrptr = iqp->q_buffer;
+ iqp->q_counter = 0;
+ osalQueueWakeupAllI(&iqp->q_waiting, Q_RESET);
+}
+
+/**
+ * @brief Input queue write.
+ * @details A byte value is written into the low end of an input queue.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ * @param[in] b the byte value to be written in the queue
+ * @return The operation status.
+ * @retval Q_OK if the operation has been completed with success.
+ * @retval Q_FULL if the queue is full and the operation cannot be
+ * completed.
+ *
+ * @iclass
+ */
+msg_t iqPutI(InputQueue *iqp, uint8_t b) {
+
+ osalDbgCheckClassI();
+
+ if (iqIsFullI(iqp))
+ return Q_FULL;
+
+ iqp->q_counter++;
+ *iqp->q_wrptr++ = b;
+ if (iqp->q_wrptr >= iqp->q_top)
+ iqp->q_wrptr = iqp->q_buffer;
+
+ osalQueueWakeupOneI(&iqp->q_waiting, Q_OK);
+
+ return Q_OK;
+}
+
+/**
+ * @brief Input queue read with timeout.
+ * @details This function reads a byte value from an input queue. If the queue
+ * is empty then the calling thread is suspended until a byte arrives
+ * in the queue or a timeout occurs.
+ * @note The callback is invoked before reading the character from the
+ * buffer or before entering the state @p THD_STATE_WTQUEUE.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ * @param[in] time the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_IMMEDIATE immediate timeout.
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return A byte value from the queue.
+ * @retval Q_TIMEOUT if the specified time expired.
+ * @retval Q_RESET if the queue has been reset.
+ *
+ * @api
+ */
+msg_t iqGetTimeout(InputQueue *iqp, systime_t time) {
+ uint8_t b;
+
+ osalSysLock();
+ if (iqp->q_notify)
+ iqp->q_notify(iqp);
+
+ while (iqIsEmptyI(iqp)) {
+ msg_t msg;
+ if ((msg = osalQueueGoSleepTimeoutS(&iqp->q_waiting, time)) < Q_OK) {
+ osalSysUnlock();
+ return msg;
+ }
+ }
+
+ iqp->q_counter--;
+ b = *iqp->q_rdptr++;
+ if (iqp->q_rdptr >= iqp->q_top)
+ iqp->q_rdptr = iqp->q_buffer;
+
+ osalSysUnlock();
+ return b;
+}
+
+/**
+ * @brief Input queue read with timeout.
+ * @details The function reads data from an input queue into a buffer. The
+ * operation completes when the specified amount of data has been
+ * transferred or after the specified timeout or if the queue has
+ * been reset.
+ * @note The function is not atomic, if you need atomicity it is suggested
+ * to use a semaphore or a mutex for mutual exclusion.
+ * @note The callback is invoked before reading each character from the
+ * buffer or before entering the state @p THD_STATE_WTQUEUE.
+ *
+ * @param[in] iqp pointer to an @p InputQueue structure
+ * @param[out] bp pointer to the data buffer
+ * @param[in] n the maximum amount of data to be transferred, the
+ * value 0 is reserved
+ * @param[in] time the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_IMMEDIATE immediate timeout.
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The number of bytes effectively transferred.
+ *
+ * @api
+ */
+size_t iqReadTimeout(InputQueue *iqp, uint8_t *bp,
+ size_t n, systime_t time) {
+ qnotify_t nfy = iqp->q_notify;
+ size_t r = 0;
+
+ osalDbgCheck(n > 0);
+
+ osalSysLock();
+ while (TRUE) {
+ if (nfy)
+ nfy(iqp);
+
+ while (iqIsEmptyI(iqp)) {
+ if (osalQueueGoSleepTimeoutS(&iqp->q_waiting, time) != Q_OK) {
+ osalSysUnlock();
+ return r;
+ }
+ }
+
+ iqp->q_counter--;
+ *bp++ = *iqp->q_rdptr++;
+ if (iqp->q_rdptr >= iqp->q_top)
+ iqp->q_rdptr = iqp->q_buffer;
+
+ osalSysUnlock(); /* Gives a preemption chance in a controlled point.*/
+ r++;
+ if (--n == 0)
+ return r;
+
+ osalSysLock();
+ }
+}
+
+/**
+ * @brief Initializes an output queue.
+ * @details A Semaphore is internally initialized and works as a counter of
+ * the free bytes in the queue.
+ * @note The callback is invoked from within the S-Locked system state,
+ * see @ref system_states.
+ *
+ * @param[out] oqp pointer to an @p OutputQueue structure
+ * @param[in] bp pointer to a memory area allocated as queue buffer
+ * @param[in] size size of the queue buffer
+ * @param[in] onfy pointer to a callback function that is invoked when
+ * data is written to the queue. The value can be @p NULL.
+ * @param[in] link application defined pointer
+ *
+ * @init
+ */
+void oqInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy,
+ void *link) {
+
+ osalQueueObjectInit(&oqp->q_waiting);
+ oqp->q_counter = size;
+ oqp->q_buffer = oqp->q_rdptr = oqp->q_wrptr = bp;
+ oqp->q_top = bp + size;
+ oqp->q_notify = onfy;
+ oqp->q_link = link;
+}
+
+/**
+ * @brief Resets an output queue.
+ * @details All the data in the output queue is erased and lost, any waiting
+ * thread is resumed with status @p Q_RESET.
+ * @note A reset operation can be used by a low level driver in order to
+ * obtain immediate attention from the high level layers.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ *
+ * @iclass
+ */
+void oqResetI(OutputQueue *oqp) {
+
+ osalDbgCheckClassI();
+
+ oqp->q_rdptr = oqp->q_wrptr = oqp->q_buffer;
+ oqp->q_counter = qSizeI(oqp);
+ osalQueueWakeupAllI(&oqp->q_waiting, Q_RESET);
+}
+
+/**
+ * @brief Output queue write with timeout.
+ * @details This function writes a byte value to an output queue. If the queue
+ * is full then the calling thread is suspended until there is space
+ * in the queue or a timeout occurs.
+ * @note The callback is invoked after writing the character into the
+ * buffer.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @param[in] b the byte value to be written in the queue
+ * @param[in] time the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_IMMEDIATE immediate timeout.
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The operation status.
+ * @retval Q_OK if the operation succeeded.
+ * @retval Q_TIMEOUT if the specified time expired.
+ * @retval Q_RESET if the queue has been reset.
+ *
+ * @api
+ */
+msg_t oqPutTimeout(OutputQueue *oqp, uint8_t b, systime_t time) {
+
+ osalSysLock();
+ while (oqIsFullI(oqp)) {
+ msg_t msg;
+
+ if ((msg = osalQueueGoSleepTimeoutS(&oqp->q_waiting, time)) < Q_OK) {
+ osalSysUnlock();
+ return msg;
+ }
+ }
+
+ oqp->q_counter--;
+ *oqp->q_wrptr++ = b;
+ if (oqp->q_wrptr >= oqp->q_top)
+ oqp->q_wrptr = oqp->q_buffer;
+
+ if (oqp->q_notify)
+ oqp->q_notify(oqp);
+
+ osalSysUnlock();
+ return Q_OK;
+}
+
+/**
+ * @brief Output queue read.
+ * @details A byte value is read from the low end of an output queue.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @return The byte value from the queue.
+ * @retval Q_EMPTY if the queue is empty.
+ *
+ * @iclass
+ */
+msg_t oqGetI(OutputQueue *oqp) {
+ uint8_t b;
+
+ osalDbgCheckClassI();
+
+ if (oqIsEmptyI(oqp))
+ return Q_EMPTY;
+
+ oqp->q_counter++;
+ b = *oqp->q_rdptr++;
+ if (oqp->q_rdptr >= oqp->q_top)
+ oqp->q_rdptr = oqp->q_buffer;
+
+ osalQueueWakeupOneI(&oqp->q_waiting, Q_OK);
+
+ return b;
+}
+
+/**
+ * @brief Output queue write with timeout.
+ * @details The function writes data from a buffer to an output queue. The
+ * operation completes when the specified amount of data has been
+ * transferred or after the specified timeout or if the queue has
+ * been reset.
+ * @note The function is not atomic, if you need atomicity it is suggested
+ * to use a semaphore or a mutex for mutual exclusion.
+ * @note The callback is invoked after writing each character into the
+ * buffer.
+ *
+ * @param[in] oqp pointer to an @p OutputQueue structure
+ * @param[out] bp pointer to the data buffer
+ * @param[in] n the maximum amount of data to be transferred, the
+ * value 0 is reserved
+ * @param[in] time the number of ticks before the operation timeouts,
+ * the following special values are allowed:
+ * - @a TIME_IMMEDIATE immediate timeout.
+ * - @a TIME_INFINITE no timeout.
+ * .
+ * @return The number of bytes effectively transferred.
+ *
+ * @api
+ */
+size_t oqWriteTimeout(OutputQueue *oqp, const uint8_t *bp,
+ size_t n, systime_t time) {
+ qnotify_t nfy = oqp->q_notify;
+ size_t w = 0;
+
+ osalDbgCheck(n > 0);
+
+ osalSysLock();
+ while (TRUE) {
+ while (oqIsFullI(oqp)) {
+ if (osalQueueGoSleepTimeoutS(&oqp->q_waiting, time) != Q_OK) {
+ osalSysUnlock();
+ return w;
+ }
+ }
+ oqp->q_counter--;
+ *oqp->q_wrptr++ = *bp++;
+ if (oqp->q_wrptr >= oqp->q_top)
+ oqp->q_wrptr = oqp->q_buffer;
+
+ if (nfy)
+ nfy(oqp);
+
+ osalSysUnlock(); /* Gives a preemption chance in a controlled point.*/
+ w++;
+ if (--n == 0)
+ return w;
+ osalSysLock();
+ }
+}
+
+#endif /* !defined(_CHIBIOS_RT_) || !CH_USE_QUEUES */
+
+/** @} */
diff --git a/os/halnew/src/icu.c b/os/halnew/src/icu.c
new file mode 100644
index 000000000..401c0e04c
--- /dev/null
+++ b/os/halnew/src/icu.c
@@ -0,0 +1,158 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file icu.c
+ * @brief ICU Driver code.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief ICU Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void icuInit(void) {
+
+ icu_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p ICUDriver structure.
+ *
+ * @param[out] icup pointer to the @p ICUDriver object
+ *
+ * @init
+ */
+void icuObjectInit(ICUDriver *icup) {
+
+ icup->state = ICU_STOP;
+ icup->config = NULL;
+}
+
+/**
+ * @brief Configures and activates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @param[in] config pointer to the @p ICUConfig object
+ *
+ * @api
+ */
+void icuStart(ICUDriver *icup, const ICUConfig *config) {
+
+ osalDbgCheck((icup != NULL) && (config != NULL));
+
+ osalSysLock();
+ osalDbgAssert((icup->state == ICU_STOP) || (icup->state == ICU_READY),
+ "icuStart(), #1", "invalid state");
+ icup->config = config;
+ icu_lld_start(icup);
+ icup->state = ICU_READY;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Deactivates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @api
+ */
+void icuStop(ICUDriver *icup) {
+
+ osalDbgCheck(icup != NULL);
+
+ osalSysLock();
+ osalDbgAssert((icup->state == ICU_STOP) || (icup->state == ICU_READY),
+ "icuStop(), #1", "invalid state");
+ icu_lld_stop(icup);
+ icup->state = ICU_STOP;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Enables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @api
+ */
+void icuEnable(ICUDriver *icup) {
+
+ osalDbgCheck(icup != NULL);
+
+ osalSysLock();
+ osalDbgAssert(icup->state == ICU_READY, "icuEnable(), #1", "invalid state");
+ icu_lld_enable(icup);
+ icup->state = ICU_WAITING;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Disables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @api
+ */
+void icuDisable(ICUDriver *icup) {
+
+ osalDbgCheck(icup != NULL);
+
+ osalSysLock();
+ osalDbgAssert((icup->state == ICU_READY) || (icup->state == ICU_WAITING) ||
+ (icup->state == ICU_ACTIVE) || (icup->state == ICU_IDLE),
+ "icuDisable(), #1", "invalid state");
+ icu_lld_disable(icup);
+ icup->state = ICU_READY;
+ osalSysUnlock();
+}
+
+#endif /* HAL_USE_ICU */
+
+/** @} */
diff --git a/os/halnew/src/pal.c b/os/halnew/src/pal.c
new file mode 100644
index 000000000..c2eb50a85
--- /dev/null
+++ b/os/halnew/src/pal.c
@@ -0,0 +1,123 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file pal.c
+ * @brief I/O Ports Abstraction Layer code.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Read from an I/O bus.
+ * @note The operation is not guaranteed to be atomic on all the
+ * architectures, for atomicity and/or portability reasons you may
+ * need to enclose port I/O operations between @p chSysLock() and
+ * @p chSysUnlock().
+ * @note The function internally uses the @p palReadGroup() macro. The use
+ * of this function is preferred when you value code size, readability
+ * and error checking over speed.
+ *
+ * @param[in] bus the I/O bus, pointer to a @p IOBus structure
+ * @return The bus logical states.
+ *
+ * @api
+ */
+ioportmask_t palReadBus(IOBus *bus) {
+
+ osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH));
+
+ return palReadGroup(bus->portid, bus->mask, bus->offset);
+}
+
+/**
+ * @brief Write to an I/O bus.
+ * @note The operation is not guaranteed to be atomic on all the
+ * architectures, for atomicity and/or portability reasons you may
+ * need to enclose port I/O operations between @p chSysLock() and
+ * @p chSysUnlock().
+ * @note The default implementation is non atomic and not necessarily
+ * optimal. Low level drivers may optimize the function by using
+ * specific hardware or coding.
+ *
+ * @param[in] bus the I/O bus, pointer to a @p IOBus structure
+ * @param[in] bits the bits to be written on the I/O bus. Values exceeding
+ * the bus width are masked so most significant bits are
+ * lost.
+ *
+ * @api
+ */
+void palWriteBus(IOBus *bus, ioportmask_t bits) {
+
+ osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH));
+
+ palWriteGroup(bus->portid, bus->mask, bus->offset, bits);
+}
+
+/**
+ * @brief Programs a bus with the specified mode.
+ * @note The operation is not guaranteed to be atomic on all the
+ * architectures, for atomicity and/or portability reasons you may
+ * need to enclose port I/O operations between @p chSysLock() and
+ * @p chSysUnlock().
+ * @note The default implementation is non atomic and not necessarily
+ * optimal. Low level drivers may optimize the function by using
+ * specific hardware or coding.
+ *
+ * @param[in] bus the I/O bus, pointer to a @p IOBus structure
+ * @param[in] mode the mode
+ *
+ * @api
+ */
+void palSetBusMode(IOBus *bus, iomode_t mode) {
+
+ osalDbgCheck((bus != NULL) && (bus->offset < PAL_IOPORTS_WIDTH));
+
+ palSetGroupMode(bus->portid, bus->mask, bus->offset, mode);
+}
+
+#endif /* HAL_USE_PAL */
+
+/** @} */
diff --git a/os/halnew/src/pwm.c b/os/halnew/src/pwm.c
new file mode 100644
index 000000000..bde512176
--- /dev/null
+++ b/os/halnew/src/pwm.c
@@ -0,0 +1,204 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file pwm.c
+ * @brief PWM Driver code.
+ *
+ * @addtogroup PWM
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PWM || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief PWM Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void pwmInit(void) {
+
+ pwm_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p PWMDriver structure.
+ *
+ * @param[out] pwmp pointer to a @p PWMDriver object
+ *
+ * @init
+ */
+void pwmObjectInit(PWMDriver *pwmp) {
+
+ pwmp->state = PWM_STOP;
+ pwmp->config = NULL;
+#if defined(PWM_DRIVER_EXT_INIT_HOOK)
+ PWM_DRIVER_EXT_INIT_HOOK(pwmp);
+#endif
+}
+
+/**
+ * @brief Configures and activates the PWM peripheral.
+ * @note Starting a driver that is already in the @p PWM_READY state
+ * disables all the active channels.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] config pointer to a @p PWMConfig object
+ *
+ * @api
+ */
+void pwmStart(PWMDriver *pwmp, const PWMConfig *config) {
+
+ osalDbgCheck((pwmp != NULL) && (config != NULL));
+
+ osalSysLock();
+ osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY),
+ "pwmStart(), #1", "invalid state");
+ pwmp->config = config;
+ pwmp->period = config->period;
+ pwm_lld_start(pwmp);
+ pwmp->state = PWM_READY;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Deactivates the PWM peripheral.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @api
+ */
+void pwmStop(PWMDriver *pwmp) {
+
+ osalDbgCheck(pwmp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY),
+ "pwmStop(), #1", "invalid state");
+ pwm_lld_stop(pwmp);
+ pwmp->state = PWM_STOP;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Changes the period the PWM peripheral.
+ * @details This function changes the period of a PWM unit that has already
+ * been activated using @p pwmStart().
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The PWM unit period is changed to the new value.
+ * @note If a period is specified that is shorter than the pulse width
+ * programmed in one of the channels then the behavior is not
+ * guaranteed.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] period new cycle time in ticks
+ *
+ * @api
+ */
+void pwmChangePeriod(PWMDriver *pwmp, pwmcnt_t period) {
+
+ osalDbgCheck(pwmp != NULL);
+
+ osalSysLock();
+ osalDbgAssert(pwmp->state == PWM_READY,
+ "pwmChangePeriod(), #1", "invalid state");
+ pwmChangePeriodI(pwmp, period);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Enables a PWM channel.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The channel is active using the specified configuration.
+ * @note Depending on the hardware implementation this function has
+ * effect starting on the next cycle (recommended implementation)
+ * or immediately (fallback implementation).
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
+ * @param[in] width PWM pulse width as clock pulses number
+ *
+ * @api
+ */
+void pwmEnableChannel(PWMDriver *pwmp,
+ pwmchannel_t channel,
+ pwmcnt_t width) {
+
+ osalDbgCheck((pwmp != NULL) && (channel < PWM_CHANNELS));
+
+ osalSysLock();
+ osalDbgAssert(pwmp->state == PWM_READY,
+ "pwmEnableChannel(), #1", "not ready");
+ pwm_lld_enable_channel(pwmp, channel, width);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Disables a PWM channel.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The channel is disabled and its output line returned to the
+ * idle state.
+ * @note Depending on the hardware implementation this function has
+ * effect starting on the next cycle (recommended implementation)
+ * or immediately (fallback implementation).
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
+ *
+ * @api
+ */
+void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel) {
+
+ osalDbgCheck((pwmp != NULL) && (channel < PWM_CHANNELS));
+
+ osalSysLock();
+ osalDbgAssert(pwmp->state == PWM_READY,
+ "pwmDisableChannel(), #1", "not ready");
+ pwm_lld_disable_channel(pwmp, channel);
+ osalSysUnlock();
+}
+
+#endif /* HAL_USE_PWM */
+
+/** @} */
diff --git a/os/halnew/src/serial.c b/os/halnew/src/serial.c
new file mode 100644
index 000000000..73a0b7457
--- /dev/null
+++ b/os/halnew/src/serial.c
@@ -0,0 +1,243 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file serial.c
+ * @brief Serial Driver code.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*
+ * Interface implementation, the following functions just invoke the equivalent
+ * queue-level function or macro.
+ */
+
+static size_t write(void *ip, const uint8_t *bp, size_t n) {
+
+ return oqWriteTimeout(&((SerialDriver *)ip)->oqueue, bp,
+ n, TIME_INFINITE);
+}
+
+static size_t read(void *ip, uint8_t *bp, size_t n) {
+
+ return iqReadTimeout(&((SerialDriver *)ip)->iqueue, bp,
+ n, TIME_INFINITE);
+}
+
+static msg_t put(void *ip, uint8_t b) {
+
+ return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, TIME_INFINITE);
+}
+
+static msg_t get(void *ip) {
+
+ return iqGetTimeout(&((SerialDriver *)ip)->iqueue, TIME_INFINITE);
+}
+
+static msg_t putt(void *ip, uint8_t b, systime_t timeout) {
+
+ return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, timeout);
+}
+
+static msg_t gett(void *ip, systime_t timeout) {
+
+ return iqGetTimeout(&((SerialDriver *)ip)->iqueue, timeout);
+}
+
+static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t time) {
+
+ return oqWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, n, time);
+}
+
+static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t time) {
+
+ return iqReadTimeout(&((SerialDriver *)ip)->iqueue, bp, n, time);
+}
+
+static const struct SerialDriverVMT vmt = {
+ write, read, put, get,
+ putt, gett, writet, readt
+};
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Serial Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void sdInit(void) {
+
+ sd_lld_init();
+}
+
+/**
+ * @brief Initializes a generic full duplex driver object.
+ * @details The HW dependent part of the initialization has to be performed
+ * outside, usually in the hardware initialization code.
+ *
+ * @param[out] sdp pointer to a @p SerialDriver structure
+ * @param[in] inotify pointer to a callback function that is invoked when
+ * some data is read from the Queue. The value can be
+ * @p NULL.
+ * @param[in] onotify pointer to a callback function that is invoked when
+ * some data is written in the Queue. The value can be
+ * @p NULL.
+ *
+ * @init
+ */
+void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) {
+
+ sdp->vmt = &vmt;
+ osalEventObjectInit(&sdp->event);
+ sdp->state = SD_STOP;
+ iqInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify, sdp);
+ oqInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp);
+}
+
+/**
+ * @brief Configures and starts the driver.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration.
+ * If this parameter is set to @p NULL then a default
+ * configuration is used.
+ *
+ * @api
+ */
+void sdStart(SerialDriver *sdp, const SerialConfig *config) {
+
+ osalDbgCheck(sdp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY),
+ "sdStart(), #1", "invalid state");
+ sd_lld_start(sdp, config);
+ sdp->state = SD_READY;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Stops the driver.
+ * @details Any thread waiting on the driver's queues will be awakened with
+ * the message @p Q_RESET.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ *
+ * @api
+ */
+void sdStop(SerialDriver *sdp) {
+
+ osalDbgCheck(sdp != NULL);
+
+ osalSysLock();
+ osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY),
+ "sdStop(), #1", "invalid state");
+ sd_lld_stop(sdp);
+ sdp->state = SD_STOP;
+ oqResetI(&sdp->oqueue);
+ iqResetI(&sdp->iqueue);
+ osalOsRescheduleS();
+ osalSysUnlock();
+}
+
+/**
+ * @brief Handles incoming data.
+ * @details This function must be called from the input interrupt service
+ * routine in order to enqueue incoming data and generate the
+ * related events.
+ * @note The incoming data event is only generated when the input queue
+ * becomes non-empty.
+ * @note In order to gain some performance it is suggested to not use
+ * this function directly but copy this code directly into the
+ * interrupt service routine.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver structure
+ * @param[in] b the byte to be written in the driver's Input Queue
+ *
+ * @iclass
+ */
+void sdIncomingDataI(SerialDriver *sdp, uint8_t b) {
+
+ osalDbgCheckClassI();
+ osalDbgCheck(sdp != NULL);
+
+ if (iqIsEmptyI(&sdp->iqueue))
+ chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE);
+ if (iqPutI(&sdp->iqueue, b) < Q_OK)
+ chnAddFlagsI(sdp, SD_OVERRUN_ERROR);
+}
+
+/**
+ * @brief Handles outgoing data.
+ * @details Must be called from the output interrupt service routine in order
+ * to get the next byte to be transmitted.
+ * @note In order to gain some performance it is suggested to not use
+ * this function directly but copy this code directly into the
+ * interrupt service routine.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver structure
+ * @return The byte value read from the driver's output queue.
+ * @retval Q_EMPTY if the queue is empty (the lower driver usually
+ * disables the interrupt source when this happens).
+ *
+ * @iclass
+ */
+msg_t sdRequestDataI(SerialDriver *sdp) {
+ msg_t b;
+
+ osalDbgCheckClassI();
+ osalDbgCheck(sdp != NULL);
+
+ b = oqGetI(&sdp->oqueue);
+ if (b < Q_OK)
+ chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
+ return b;
+}
+
+#endif /* HAL_USE_SERIAL */
+
+/** @} */
diff --git a/os/halnew/src/spi.c b/os/halnew/src/spi.c
new file mode 100644
index 000000000..b9b4c866a
--- /dev/null
+++ b/os/halnew/src/spi.c
@@ -0,0 +1,428 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file spi.c
+ * @brief SPI Driver code.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief SPI Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void spiInit(void) {
+
+ spi_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p SPIDriver structure.
+ *
+ * @param[out] spip pointer to the @p SPIDriver object
+ *
+ * @init
+ */
+void spiObjectInit(SPIDriver *spip) {
+
+ spip->state = SPI_STOP;
+ spip->config = NULL;
+#if SPI_USE_WAIT
+ spip->thread = NULL;
+#endif /* SPI_USE_WAIT */
+#if SPI_USE_MUTUAL_EXCLUSION
+ osalMutexInit(&spip->mutex);
+#endif /* SPI_USE_MUTUAL_EXCLUSION */
+#if defined(SPI_DRIVER_EXT_INIT_HOOK)
+ SPI_DRIVER_EXT_INIT_HOOK(spip);
+#endif
+}
+
+/**
+ * @brief Configures and activates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] config pointer to the @p SPIConfig object
+ *
+ * @api
+ */
+void spiStart(SPIDriver *spip, const SPIConfig *config) {
+
+ osalDbgCheck((spip != NULL) && (config != NULL));
+
+ osalSysLock();
+ osalDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY),
+ "spiStart(), #1", "invalid state");
+ spip->config = config;
+ spi_lld_start(spip);
+ spip->state = SPI_READY;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Deactivates the SPI peripheral.
+ * @note Deactivating the peripheral also enforces a release of the slave
+ * select line.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @api
+ */
+void spiStop(SPIDriver *spip) {
+
+ osalDbgCheck(spip != NULL);
+
+ osalSysLock();
+ osalDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY),
+ "spiStop(), #1", "invalid state");
+ spi_lld_stop(spip);
+ spip->state = SPI_STOP;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Asserts the slave select signal and prepares for transfers.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @api
+ */
+void spiSelect(SPIDriver *spip) {
+
+ osalDbgCheck(spip != NULL);
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY, "spiSelect(), #1", "not ready");
+ spiSelectI(spip);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Deasserts the slave select signal.
+ * @details The previously selected peripheral is unselected.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @api
+ */
+void spiUnselect(SPIDriver *spip) {
+
+ osalDbgCheck(spip != NULL);
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY, "spiUnselect(), #1", "not ready");
+ spiUnselectI(spip);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Ignores data on the SPI bus.
+ * @details This asynchronous function starts the transmission of a series of
+ * idle words on the SPI bus and ignores the received data.
+ * @pre A slave must have been selected using @p spiSelect() or
+ * @p spiSelectI().
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be ignored
+ *
+ * @api
+ */
+void spiStartIgnore(SPIDriver *spip, size_t n) {
+
+ osalDbgCheck((spip != NULL) && (n > 0));
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY, "spiStartIgnore(), #1", "not ready");
+ spiStartIgnoreI(spip, n);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Exchanges data on the SPI bus.
+ * @details This asynchronous function starts a simultaneous transmit/receive
+ * operation.
+ * @pre A slave must have been selected using @p spiSelect() or
+ * @p spiSelectI().
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @api
+ */
+void spiStartExchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf) {
+
+ osalDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY,
+ "spiStartExchange(), #1", "not ready");
+ spiStartExchangeI(spip, n, txbuf, rxbuf);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Sends data over the SPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @pre A slave must have been selected using @p spiSelect() or
+ * @p spiSelectI().
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @api
+ */
+void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf) {
+
+ osalDbgCheck((spip != NULL) && (n > 0) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY, "spiStartSend(), #1", "not ready");
+ spiStartSendI(spip, n, txbuf);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Receives data from the SPI bus.
+ * @details This asynchronous function starts a receive operation.
+ * @pre A slave must have been selected using @p spiSelect() or
+ * @p spiSelectI().
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @api
+ */
+void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf) {
+
+ osalDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY,
+ "spiStartReceive(), #1", "not ready");
+ spiStartReceiveI(spip, n, rxbuf);
+ osalSysUnlock();
+}
+
+#if SPI_USE_WAIT || defined(__DOXYGEN__)
+/**
+ * @brief Ignores data on the SPI bus.
+ * @details This synchronous function performs the transmission of a series of
+ * idle words on the SPI bus and ignores the received data.
+ * @pre In order to use this function the option @p SPI_USE_WAIT must be
+ * enabled.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p end_cb = @p NULL).
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be ignored
+ *
+ * @api
+ */
+void spiIgnore(SPIDriver *spip, size_t n) {
+
+ osalDbgCheck((spip != NULL) && (n > 0));
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY,
+ "spiIgnore(), #1", "not ready");
+ osalDbgAssert(spip->config->end_cb == NULL,
+ "spiIgnore(), #2", "has callback");
+ spiStartIgnoreI(spip, n);
+ _spi_wait_s(spip);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Exchanges data on the SPI bus.
+ * @details This synchronous function performs a simultaneous transmit/receive
+ * operation.
+ * @pre In order to use this function the option @p SPI_USE_WAIT must be
+ * enabled.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p end_cb = @p NULL).
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @api
+ */
+void spiExchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf) {
+
+ osalDbgCheck((spip != NULL) && (n > 0) &&
+ (rxbuf != NULL) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY, "spiExchange(), #1", "not ready");
+ osalDbgAssert(spip->config->end_cb == NULL,
+ "spiExchange(), #2", "has callback");
+ spiStartExchangeI(spip, n, txbuf, rxbuf);
+ _spi_wait_s(spip);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Sends data over the SPI bus.
+ * @details This synchronous function performs a transmit operation.
+ * @pre In order to use this function the option @p SPI_USE_WAIT must be
+ * enabled.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p end_cb = @p NULL).
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @api
+ */
+void spiSend(SPIDriver *spip, size_t n, const void *txbuf) {
+
+ osalDbgCheck((spip != NULL) && (n > 0) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY,
+ "spiSend(), #1", "not ready");
+ osalDbgAssert(spip->config->end_cb == NULL,
+ "spiSend(), #2", "has callback");
+ spiStartSendI(spip, n, txbuf);
+ _spi_wait_s(spip);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Receives data from the SPI bus.
+ * @details This synchronous function performs a receive operation.
+ * @pre In order to use this function the option @p SPI_USE_WAIT must be
+ * enabled.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p end_cb = @p NULL).
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @api
+ */
+void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
+
+ osalDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(spip->state == SPI_READY,
+ "spiReceive(), #1", "not ready");
+ osalDbgAssert(spip->config->end_cb == NULL,
+ "spiReceive(), #2", "has callback");
+ spiStartReceiveI(spip, n, rxbuf);
+ _spi_wait_s(spip);
+ osalSysUnlock();
+}
+#endif /* SPI_USE_WAIT */
+
+#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+/**
+ * @brief Gains exclusive access to the SPI bus.
+ * @details This function tries to gain ownership to the SPI bus, if the bus
+ * is already being used then the invoking thread is queued.
+ * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @api
+ */
+void spiAcquireBus(SPIDriver *spip) {
+
+ osalDbgCheck(spip != NULL);
+
+ osalMutexLock(&spip->mutex);
+}
+
+/**
+ * @brief Releases exclusive access to the SPI bus.
+ * @pre In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @api
+ */
+void spiReleaseBus(SPIDriver *spip) {
+
+ osalDbgCheck(spip != NULL);
+
+ osalMutexUnlock(&spip->mutex);
+}
+#endif /* SPI_USE_MUTUAL_EXCLUSION */
+
+#endif /* HAL_USE_SPI */
+
+/** @} */