From 0e34cd051ed686263001af3a721f6858db94d072 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 9 Aug 2013 08:25:09 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/kernel_3_dev@6109 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/src/adc.c | 326 ++++++++++++++++++++++++++++++++++++ os/hal/src/can.c | 284 ++++++++++++++++++++++++++++++++ os/hal/src/hal.c | 132 +++++++++++++++ os/hal/src/hal_queues.c | 402 +++++++++++++++++++++++++++++++++++++++++++++ os/hal/src/icu.c | 158 ++++++++++++++++++ os/hal/src/pal.c | 123 ++++++++++++++ os/hal/src/pwm.c | 204 +++++++++++++++++++++++ os/hal/src/serial.c | 243 +++++++++++++++++++++++++++ os/hal/src/spi.c | 428 ++++++++++++++++++++++++++++++++++++++++++++++++ os/hal/src/st.c | 71 ++++++++ 10 files changed, 2371 insertions(+) create mode 100644 os/hal/src/adc.c create mode 100644 os/hal/src/can.c create mode 100644 os/hal/src/hal.c create mode 100644 os/hal/src/hal_queues.c create mode 100644 os/hal/src/icu.c create mode 100644 os/hal/src/pal.c create mode 100644 os/hal/src/pwm.c create mode 100644 os/hal/src/serial.c create mode 100644 os/hal/src/spi.c create mode 100644 os/hal/src/st.c (limited to 'os/hal/src') diff --git a/os/hal/src/adc.c b/os/hal/src/adc.c new file mode 100644 index 000000000..ccc11574a --- /dev/null +++ b/os/hal/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 . +*/ + +/** + * @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/hal/src/can.c b/os/hal/src/can.c new file mode 100644 index 000000000..9a352ddd1 --- /dev/null +++ b/os/hal/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 . +*/ + +/** + * @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; + osalEventBroadcastFlagsI(&canp->sleep_event, 0); + 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; + osalEventBroadcastFlagsI(&canp->wakeup_event, 0); + osalOsRescheduleS(); + } + osalSysUnlock(); +} +#endif /* CAN_USE_SLEEP_MODE */ + +#endif /* HAL_USE_CAN */ + +/** @} */ diff --git a/os/hal/src/hal.c b/os/hal/src/hal.c new file mode 100644 index 000000000..8b56b4ac8 --- /dev/null +++ b/os/hal/src/hal.c @@ -0,0 +1,132 @@ +/* + 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 . +*/ + +/** + * @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) { + + /* Initializes the OS Abstraction Layer.*/ + osalInit(); + + /* Platform low level initializations.*/ + 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 (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__) + /* System tick service if the underlying OS requires it.*/ + stInit(); +#endif +} + +/** @} */ diff --git a/os/hal/src/hal_queues.c b/os/hal/src/hal_queues.c new file mode 100644 index 000000000..36016a1e9 --- /dev/null +++ b/os/hal/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 . +*/ + +/** + * @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).
+ * There are several kind of queues:
+ * - Input queue, unidirectional queue where the writer is the + * lower side and the reader is the upper side. + * - Output queue, unidirectional queue where the writer is the + * upper side and the reader is the lower side. + * - Full duplex queue, 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/hal/src/icu.c b/os/hal/src/icu.c new file mode 100644 index 000000000..401c0e04c --- /dev/null +++ b/os/hal/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 . +*/ + +/** + * @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/hal/src/pal.c b/os/hal/src/pal.c new file mode 100644 index 000000000..c2eb50a85 --- /dev/null +++ b/os/hal/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 . +*/ + +/** + * @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/hal/src/pwm.c b/os/hal/src/pwm.c new file mode 100644 index 000000000..bde512176 --- /dev/null +++ b/os/hal/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 . +*/ + +/** + * @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/hal/src/serial.c b/os/hal/src/serial.c new file mode 100644 index 000000000..73a0b7457 --- /dev/null +++ b/os/hal/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 . +*/ + +/** + * @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/hal/src/spi.c b/os/hal/src/spi.c new file mode 100644 index 000000000..cd7124bd3 --- /dev/null +++ b/os/hal/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 . +*/ + +/** + * @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 + osalMutexObjectInit(&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 */ + +/** @} */ diff --git a/os/hal/src/st.c b/os/hal/src/st.c new file mode 100644 index 000000000..f2e8f3bf2 --- /dev/null +++ b/os/hal/src/st.c @@ -0,0 +1,71 @@ +/* + 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 . +*/ + +/** + * @file st.c + * @brief ST Driver code. + * + * @addtogroup ST + * @{ + */ + +#include "hal.h" + +#if (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief ST Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void stInit(void) { + + st_lld_init(); +} + +#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */ + +/** @} */ -- cgit v1.2.3