From 5805e10f74104e3de60470c38d6643d2bdb00fe0 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sat, 9 Jul 2016 23:57:48 +0200 Subject: NRF52832 implementation --- os/hal/ports/NRF5/LLD/hal_pal_lld.c | 158 +++++++++++++++ os/hal/ports/NRF5/LLD/hal_pal_lld.h | 351 +++++++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_serial_lld.c | 335 +++++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_serial_lld.h | 155 +++++++++++++++ os/hal/ports/NRF5/LLD/hal_st_lld.c | 302 ++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_st_lld.h | 275 ++++++++++++++++++++++++++ 6 files changed, 1576 insertions(+) create mode 100644 os/hal/ports/NRF5/LLD/hal_pal_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_pal_lld.h create mode 100644 os/hal/ports/NRF5/LLD/hal_serial_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_serial_lld.h create mode 100644 os/hal/ports/NRF5/LLD/hal_st_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_st_lld.h (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_pal_lld.c b/os/hal/ports/NRF5/LLD/hal_pal_lld.c new file mode 100644 index 0000000..cb25ee4 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_pal_lld.c @@ -0,0 +1,158 @@ +/* + Copyright (C) 2015 Fabio Utzig + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file pal_lld.c + * @brief NRF5 PAL subsystem low level driver source. + * + * @addtogroup PAL + * @{ + */ + +#include "osal.h" +#include "hal.h" + +#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +void _pal_lld_setpadmode(ioportid_t port, uint8_t pad, iomode_t mode) +{ + (void)port; + osalDbgAssert(pad <= 31, "pal_lld_setpadmode() - invalid pad"); + + switch (mode) { + case PAL_MODE_RESET: + case PAL_MODE_UNCONNECTED: + IOPORT1->PIN_CNF[pad] = + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | + (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | + (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | + (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | + (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); + break; + case PAL_MODE_INPUT: + case PAL_MODE_INPUT_ANALOG: + IOPORT1->PIN_CNF[pad] = + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | + (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | + (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | + (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | + (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); + break; + case PAL_MODE_INPUT_PULLUP: + IOPORT1->PIN_CNF[pad] = + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | + (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | + (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | + (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | + (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); + break; + case PAL_MODE_INPUT_PULLDOWN: + IOPORT1->PIN_CNF[pad] = + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | + (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | + (GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos) | + (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | + (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); + break; + case PAL_MODE_OUTPUT_PUSHPULL: + IOPORT1->PIN_CNF[pad] = + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | + (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | + (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | + (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | + (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); + break; + case PAL_MODE_OUTPUT_OPENDRAIN: + IOPORT1->PIN_CNF[pad] = + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | + (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) | + (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | + (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | + (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); + break; + default: + osalDbgAssert(FALSE, "invalid pal mode"); + break; + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief NRF5 I/O ports configuration. + * + * @param[in] config the NRF5 ports configuration + * + * @notapi + */ +void _pal_lld_init(const PALConfig *config) +{ + uint8_t i; + + for (i = 0; i < TOTAL_GPIO_PADS; i++) { + pal_lld_setpadmode(IOPORT1, i, config->pads[i]); + } +} + +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the mode + * + * @notapi + */ +void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode) +{ + uint8_t i; + + for (i = 0; i < TOTAL_GPIO_PADS; i++, mask >>= 1) { + if (mask & 1) { + pal_lld_setpadmode(port, i, mode); + } + } +} + +#endif /* HAL_USE_PAL == TRUE */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_pal_lld.h b/os/hal/ports/NRF5/LLD/hal_pal_lld.h new file mode 100644 index 0000000..da2da74 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_pal_lld.h @@ -0,0 +1,351 @@ +/* + Copyright (C) 2015 Fabio Utzig + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file pal_lld.h + * @brief NRF5 PAL subsystem low level driver header. + * + * @addtogroup PAL + * @{ + */ + +#ifndef HAL_PAL_LLD_H +#define HAL_PAL_LLD_H + +#if (HAL_USE_PAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* I/O Ports Types and constants. */ +/*===========================================================================*/ + +#define TOTAL_GPIO_PADS 32 + +/** + * @name Port related definitions + * @{ + */ +/** + * @brief Width, in bits, of an I/O port. + */ +#define PAL_IOPORTS_WIDTH 32U + +/** + * @brief Whole port mask. + * @brief This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFFU) +/** @} */ + +/** + * @name Line handling macros + * @{ + */ +/** + * @brief Forms a line identifier. + * @details A port/pad pair are encoded into an @p ioline_t type. The encoding + * of this type is platform-dependent. + */ +#define PAL_LINE(port, pad) \ + ((ioline_t)((uint32_t)(pad))) + +/** + * @brief Decodes a port identifier from a line identifier. + */ +#define PAL_PORT(line) \ + ((ioportid_t)(IOPORT1)) + +/** + * @brief Decodes a pad identifier from a line identifier. + */ +#define PAL_PAD(line) \ + ((uint32_t)(line)) + +/** + * @brief Value identifying an invalid line. + */ +#define PAL_NOLINE ((ioline_t)-1) +/** @} */ + +/** + * @brief Generic I/O ports static initializer. + * @details An instance of this structure must be passed to @p palInit() at + * system startup time in order to initialized the digital I/O + * subsystem. This represents only the initial setup, specific pads + * or whole ports can be reprogrammed at later time. + * @note Implementations may extend this structure to contain more, + * architecture dependent, fields. + */ +typedef struct { + uint32_t pads[TOTAL_GPIO_PADS]; +} PALConfig; + +/** + * @brief Digital I/O port sized unsigned type. + */ +typedef uint32_t ioportmask_t; + +/** + * @brief Digital I/O modes. + */ +typedef uint8_t iomode_t; + +/** + * @brief Type of an I/O line. + */ +typedef uint32_t ioline_t; + +/** + * @brief Port Identifier. + * @details This type can be a scalar or some kind of pointer, do not make + * any assumption about it, use the provided macros when populating + * variables of this type. + */ +typedef NRF_GPIO_Type *ioportid_t; + +/*===========================================================================*/ +/* I/O Ports Identifiers. */ +/*===========================================================================*/ + +/** + * @brief First I/O port identifier. + * @details Low level drivers can define multiple ports, it is suggested to + * use this naming convention. + */ +#if NRF_SERIE == 51 +#define IOPORT1 NRF_GPIO +#elif NRF_SERIE == 52 +#define IOPORT1 NRF_P0 +#endif + +/*===========================================================================*/ +/* Implementation, some of the following macros could be implemented as */ +/* functions, if so please put them in pal_lld.c. */ +/*===========================================================================*/ + +/** + * @brief Low level PAL subsystem initialization. + * + * @param[in] config architecture-dependent ports configuration + * + * @notapi + */ +#define pal_lld_init(config) _pal_lld_init(config) + +/** + * @brief Reads the physical I/O port states. + * + * @param[in] port port identifier + * @return The port bits. + * + * @notapi + */ +#define pal_lld_readport(port) (IOPORT1->IN) + +/** + * @brief Reads the output latch. + * @details The purpose of this function is to read back the latched output + * value. + * + * @param[in] port port identifier + * @return The latched logical states. + * + * @notapi + */ +#define pal_lld_readlatch(port) (IOPORT1->OUT) + +/** + * @brief Writes a bits mask on a I/O port. + * + * @param[in] port port identifier + * @param[in] bits bits to be written on the specified port + * + * @notapi + */ +#define pal_lld_writeport(port, bits) (IOPORT1->OUT = (bits)) + +/** + * @brief Sets a bits mask on a I/O port. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] bits bits to be ORed on the specified port + * + * @notapi + */ +#define pal_lld_setport(port, bits) (IOPORT1->OUTSET = (bits)) + + +/** + * @brief Clears a bits mask on a I/O port. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] bits bits to be cleared on the specified port + * + * @notapi + */ +#define pal_lld_clearport(port, bits) (IOPORT1->OUTCLR = (bits)) + +/** + * @brief Pads group mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] mode group mode + * + * @notapi + */ +#define pal_lld_setgroupmode(port, mask, offset, mode) \ + _pal_lld_setgroupmode(port, mask << offset, mode) + +/** + * @brief Reads a logical state from an I/O pad. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @return The logical state. + * @retval PAL_LOW low logical state. + * @retval PAL_HIGH high logical state. + * + * @notapi + */ +#define pal_lld_readpad(port, pad) \ + ((IOPORT1->IN & ((uint32_t) 1 << pad)) ? PAL_HIGH : PAL_LOW) + +/** + * @brief Writes a logical state on an output pad. + * @note This function is not meant to be invoked directly by the + * application code. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] bit logical value, the value must be @p PAL_LOW or + * @p PAL_HIGH + * + * @notapi + */ +#define pal_lld_writepad(port, pad, bit) \ + do { \ + (void)port; \ + if (bit == PAL_HIGH) \ + IOPORT1->OUTSET = ((uint32_t) 1 << pad); \ + else \ + IOPORT1->OUTCLR = ((uint32_t) 1 << pad); \ + } while (false) + +/** + * @brief Sets a pad logical state to @p PAL_HIGH. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_setpad(port, pad) (IOPORT1->OUTSET = (uint32_t) 1 << (pad)) + +/** + * @brief Clears a pad logical state to @p PAL_LOW. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_clearpad(port, pad) (IOPORT1->OUTCLR = (uint32_t) 1 << (pad)) + +/** + * @brief Toggles a pad logical state. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +#define pal_lld_togglepad(port, pad) \ + do { \ + uint8_t bit = (IOPORT1->IN >> (pad)) & 1; \ + if (bit) \ + IOPORT1->OUTCLR = 1 << (pad); \ + else \ + IOPORT1->OUTSET = 1 << (pad); \ + } while (0) + +/** + * @brief Pad mode setup. + * @details This function programs a pad with the specified mode. + * @note The @ref PAL provides a default software implementation of this + * functionality, implement this function if can optimize it by using + * special hardware functionalities or special coding. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] mode pad mode + * + * @notapi + */ +#define pal_lld_setpadmode(port, pad, mode) _pal_lld_setpadmode(port, pad, mode) + +#if !defined(__DOXYGEN__) +extern const PALConfig pal_default_config; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void _pal_lld_init(const PALConfig *config); + void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode); + void _pal_lld_setpadmode(ioportid_t port, + uint8_t pad, + iomode_t mode); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PAL == TRUE */ + +#endif /* HAL_PAL_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_serial_lld.c b/os/hal/ports/NRF5/LLD/hal_serial_lld.c new file mode 100644 index 0000000..cba7804 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_serial_lld.c @@ -0,0 +1,335 @@ +/* + Copyright (C) 2015 Fabio Utzig + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file serial_lld.c + * @brief NRF51822 serial subsystem low level driver source. + * + * @addtogroup SERIAL + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) + +#if NRF_SERIE == 51 +#include "nrf51.h" +#elif NRF_SERIE == 52 +#include "nrf52.h" +#define UART0_IRQn UARTE0_UART0_IRQn +#endif + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief USART1 serial driver identifier.*/ +#if (NRF51_SERIAL_USE_UART0 == TRUE) || defined(__DOXYGEN__) +SerialDriver SD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Driver default configuration. + */ +static const SerialConfig default_config = { + .speed = 38400, + .tx_pad = NRF51_SERIAL_PAD_DISCONNECTED, + .rx_pad = NRF51_SERIAL_PAD_DISCONNECTED, +#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) + .rts_pad = NRF51_SERIAL_PAD_DISCONNECTED, + .cts_pad = NRF51_SERIAL_PAD_DISCONNECTED, +#endif +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/* + * @brief Maps a baudrate speed to a BAUDRATE register value. + */ + +/** + * @brief Common UART configuration. + * + */ +static void configure_uart(const SerialConfig *config) +{ + uint32_t speed = UART_BAUDRATE_BAUDRATE_Baud250000; + + switch (config->speed) { + case 1200: speed = UART_BAUDRATE_BAUDRATE_Baud1200; break; + case 2400: speed = UART_BAUDRATE_BAUDRATE_Baud2400; break; + case 4800: speed = UART_BAUDRATE_BAUDRATE_Baud4800; break; + case 9600: speed = UART_BAUDRATE_BAUDRATE_Baud9600; break; + case 14400: speed = UART_BAUDRATE_BAUDRATE_Baud14400; break; + case 19200: speed = UART_BAUDRATE_BAUDRATE_Baud19200; break; + case 28800: speed = UART_BAUDRATE_BAUDRATE_Baud28800; break; + case 38400: speed = UART_BAUDRATE_BAUDRATE_Baud38400; break; + case 57600: speed = UART_BAUDRATE_BAUDRATE_Baud57600; break; + case 76800: speed = UART_BAUDRATE_BAUDRATE_Baud76800; break; + case 115200: speed = UART_BAUDRATE_BAUDRATE_Baud115200; break; + case 230400: speed = UART_BAUDRATE_BAUDRATE_Baud230400; break; + case 250000: speed = UART_BAUDRATE_BAUDRATE_Baud250000; break; + case 460800: speed = UART_BAUDRATE_BAUDRATE_Baud460800; break; + case 921600: speed = UART_BAUDRATE_BAUDRATE_Baud921600; break; + case 1000000: speed = UART_BAUDRATE_BAUDRATE_Baud1M; break; + default: osalDbgAssert(0, "invalid baudrate"); break; + }; + + /* Configure PINs mode */ + if (config->tx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + palSetPadMode(IOPORT1, config->tx_pad, PAL_MODE_OUTPUT_PUSHPULL); + } + if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + palSetPadMode(IOPORT1, config->rx_pad, PAL_MODE_INPUT); + } +#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) + if (config->rts_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + palSetPadMode(IOPORT1, config->rts_pad, PAL_MODE_OUTPUT_PUSHPULL); + } + if (config->cts_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + palSetPadMode(IOPORT1, config->cts_pad, PAL_MODE_INPUT); + } +#endif + + /* Select PINs used by UART */ + NRF_UART0->PSELTXD = config->tx_pad; + NRF_UART0->PSELRXD = config->rx_pad; +#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) + NRF_UART0->PSELRTS = config->rts_pad; + NRF_UART0->PSELCTS = config->cts_pad; +#else + NRF_UART0->PSELRTS = NRF51_SERIAL_PAD_DISCONNECTED; + NRF_UART0->PSELCTS = NRF51_SERIAL_PAD_DISCONNECTED; +#endif + + /* Set baud rate */ + NRF_UART0->BAUDRATE = speed; + + /* Set config */ + NRF_UART0->CONFIG = (UART_CONFIG_PARITY_Excluded << UART_CONFIG_PARITY_Pos); + + /* Adjust flow control */ +#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) + if ((config->rts_pad < TOTAL_GPIO_PADS) || + (config->cts_pad < TOTAL_GPIO_PADS)) { + NRF_UART0->CONFIG |= UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos; + } else { + NRF_UART0->CONFIG &= ~(UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos); + } +#else + NRF_UART0->CONFIG &= ~(UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos); +#endif + + /* Enable UART and clear events */ + NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled; + NRF_UART0->EVENTS_RXDRDY = 0; + (void)NRF_UART0->EVENTS_RXDRDY; + NRF_UART0->EVENTS_TXDRDY = 0; + (void)NRF_UART0->EVENTS_TXDRDY; + + if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + while (NRF_UART0->EVENTS_RXDRDY != 0) { + (void)NRF_UART0->RXD; + } + } +} + + +/** + * @brief Driver output notification. + */ +#if NRF51_SERIAL_USE_UART0 || defined(__DOXYGEN__) +static void notify1(io_queue_t *qp) +{ + SerialDriver *sdp = &SD1; + + (void)qp; + + if (NRF_UART0->PSELTXD == NRF51_SERIAL_PAD_DISCONNECTED) + return; + + if (!sdp->tx_busy) { + msg_t b = oqGetI(&sdp->oqueue); + + if (b < Q_OK) { + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + NRF_UART0->TASKS_STOPTX = 1; + return; + } + sdp->tx_busy = 1; + NRF_UART0->TASKS_STARTTX = 1; + NRF_UART0->TXD = b; + } +} +#endif + + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if NRF51_SERIAL_USE_UART0 || defined(__DOXYGEN__) +OSAL_IRQ_HANDLER(Vector48) { + + OSAL_IRQ_PROLOGUE(); + + SerialDriver *sdp = &SD1; + uint32_t isr = NRF_UART0->INTENSET; + + if ((NRF_UART0->EVENTS_RXDRDY != 0) && (isr & UART_INTENSET_RXDRDY_Msk)) { + // Clear UART RX event flag + NRF_UART0->EVENTS_RXDRDY = 0; + (void)NRF_UART0->EVENTS_RXDRDY; + + osalSysLockFromISR(); + if (iqIsEmptyI(&sdp->iqueue)) + chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); + if (iqPutI(&sdp->iqueue, NRF_UART0->RXD) < Q_OK) + chnAddFlagsI(sdp, SD_OVERRUN_ERROR); + osalSysUnlockFromISR(); + } + + if ((NRF_UART0->EVENTS_TXDRDY != 0) && (isr & UART_INTENSET_TXDRDY_Msk)) { + msg_t b; + + // Clear UART TX event flag. + NRF_UART0->EVENTS_TXDRDY = 0; + (void)NRF_UART0->EVENTS_TXDRDY; + + osalSysLockFromISR(); + b = oqGetI(&sdp->oqueue); + osalSysUnlockFromISR(); + + if (b < Q_OK) { + osalSysLockFromISR(); + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + osalSysUnlockFromISR(); + NRF_UART0->TASKS_STOPTX = 1; + sdp->tx_busy = 0; + } else { + sdp->tx_busy = 1; + NRF_UART0->TXD = b; + } + } + + /* TODO: Error handling for EVENTS_ERROR */ + if ((NRF_UART0->EVENTS_ERROR != 0) && (isr & UART_INTENSET_ERROR_Msk)) { + // Clear UART ERROR event flag. + NRF_UART0->EVENTS_ERROR = 0; + (void)NRF_UART0->EVENTS_ERROR; + } + + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level serial driver initialization. + * + * @notapi + */ +void sd_lld_init(void) { + +#if NRF51_SERIAL_USE_UART0 == TRUE + sdObjectInit(&SD1, NULL, notify1); +#endif +} + +/** + * @brief Low level serial driver configuration and (re)start. + * + * @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. + * + * @notapi + */ +void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { + + if (config == NULL) + config = &default_config; + + osalDbgAssert( + (config->rx_pad < TOTAL_GPIO_PADS) || (config->tx_pad < TOTAL_GPIO_PADS), + "must configure at least an RX or TX pad"); + + if (sdp->state == SD_STOP) { + +#if NRF51_SERIAL_USE_UART0 == TRUE + if (sdp == &SD1) { + configure_uart(config); + + // Enable UART interrupt + NRF_UART0->INTENCLR = (uint32_t)-1; + NRF_UART0->INTENSET = UART_INTENSET_ERROR_Msk; + if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + NRF_UART0->INTENSET |= UART_INTENSET_RXDRDY_Msk; + if (config->tx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + NRF_UART0->INTENSET |= UART_INTENSET_TXDRDY_Msk; + + nvicEnableVector(UART0_IRQn, NRF51_SERIAL_UART0_PRIORITY); + + if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + NRF_UART0->TASKS_STARTRX = 1; + } +#endif + + } +} + +/** + * @brief Low level serial driver stop. + * @details De-initializes the USART, stops the associated clock, resets the + * interrupt vector. + * + * @param[in] sdp pointer to a @p SerialDriver object + * + * @notapi + */ +void sd_lld_stop(SerialDriver *sdp) { + + if (sdp->state == SD_READY) { + +#if NRF51_SERIAL_USE_UART0 == TRUE + if (&SD1 == sdp) { + nvicDisableVector(UART0_IRQn); + NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Disabled; + } +#endif + } +} + +#endif /* HAL_USE_SERIAL == TRUE */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_serial_lld.h b/os/hal/ports/NRF5/LLD/hal_serial_lld.h new file mode 100644 index 0000000..79955b1 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_serial_lld.h @@ -0,0 +1,155 @@ +/* + Copyright (C) 2015 Fabio Utzig + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file serial_lld.h + * @brief NRF51822 serial subsystem low level driver header. + * + * @addtogroup SERIAL + * @{ + */ + +#ifndef HAL_SERIAL_LLD_H +#define HAL_SERIAL_LLD_H + +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name PLATFORM configuration options + * @{ + */ +/** + * @brief SD flow control enable switch. + * @details If set to @p TRUE the support for hardware flow control + * is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF51_SERIAL_USE_HWFLOWCTRL) || defined(__DOXYGEN__) +#define NRF51_SERIAL_USE_HWFLOWCTRL FALSE +#endif + +/** + * @brief SD1 driver enable switch. + * @details If set to @p TRUE the support for SD1 is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF51_SERIAL_USE_UART0) || defined(__DOXYGEN__) +#define NRF51_SERIAL_USE_UART0 FALSE +#endif + +/** + * @brief UART0 interrupt priority level setting. + */ +#if !defined(NRF51_SERIAL_UART0_PRIORITY) || defined(__DOXYGEN__) +#define NRF51_SERIAL_UART0_PRIORITY 3 +#endif + +/* Value indicating that no pad is connected to this UART register. */ +#define NRF51_SERIAL_PAD_DISCONNECTED 0xFFFFFFFFU +#define NRF51_SERIAL_INVALID_BAUDRATE 0xFFFFFFFFU + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if NRF51_SERIAL_USE_UART0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF51_SERIAL_UART0_PRIORITY) +#error "Invalid IRQ priority assigned to UART0" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief NRF51 Serial Driver configuration structure. + * @details An instance of this structure must be passed to @p sdStart() + * in order to configure and start a serial driver operations. + * @note This structure content is architecture dependent, each driver + * implementation defines its own version and the custom static + * initializers. + */ +typedef struct { + /** + * @brief Bit rate. + */ + uint32_t speed; + /* End of the mandatory fields.*/ + uint32_t tx_pad; + uint32_t rx_pad; +#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) + uint32_t rts_pad; + uint32_t cts_pad; +#endif +} SerialConfig; + +/** + * @brief @p SerialDriver specific data. + */ +#define _serial_driver_data \ + _base_asynchronous_channel_data \ + /* Driver state.*/ \ + sdstate_t state; \ + /* Input queue.*/ \ + input_queue_t iqueue; \ + /* Output queue.*/ \ + output_queue_t oqueue; \ + /* Input circular buffer.*/ \ + uint8_t ib[SERIAL_BUFFERS_SIZE]; \ + /* Output circular buffer.*/ \ + uint8_t ob[SERIAL_BUFFERS_SIZE]; \ + /* 1 if port is busy transmitting, 0 otherwise. */ \ + uint8_t tx_busy; \ + /* End of the mandatory fields.*/ \ + thread_t *thread; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (NRF51_SERIAL_USE_UART0 == TRUE) && !defined(__DOXYGEN__) +extern SerialDriver SD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sd_lld_init(void); + void sd_lld_start(SerialDriver *sdp, const SerialConfig *config); + void sd_lld_stop(SerialDriver *sdp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SERIAL == TRUE */ + +#endif /* HAL_SERIAL_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.c b/os/hal/ports/NRF5/LLD/hal_st_lld.c new file mode 100644 index 0000000..3a988a8 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.c @@ -0,0 +1,302 @@ +/* + ChibiOS - Copyright (C) 2015 Fabio Utzig + 2016 Stephane D'Alu + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file st_lld.c + * @brief NRF51822 ST subsystem low level driver source. + * + * @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 and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC) || defined(__DOXYGEN__) +#if NRF51_ST_USE_RTC0 == TRUE +/** + * @brief System Timer vector (RTC0) + * @details This interrupt is used for system tick in periodic mode + * if selected with NRF51_ST_USE_RTC0 + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector6C) { + + OSAL_IRQ_PROLOGUE(); + + NRF_RTC0->EVENTS_TICK = 0; + (void)NRF_RTC0->EVENTS_TICK; + + osalSysLockFromISR(); + osalOsTimerHandlerI(); + osalSysUnlockFromISR(); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if NRF51_ST_USE_RTC1 == TRUE +/** + * @brief System Timer vector (RTC1) + * @details This interrupt is used for system tick in periodic mode + * if selected with NRF51_ST_USE_RTC1 + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector84) { + + OSAL_IRQ_PROLOGUE(); + + NRF_RTC1->EVENTS_TICK = 0; + (void)NRF_RTC1->EVENTS_TICK; + + osalSysLockFromISR(); + osalOsTimerHandlerI(); + osalSysUnlockFromISR(); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if NRF51_ST_USE_TIMER0 == TRUE +/** + * @brief System Timer vector. (TIMER0) + * @details This interrupt is used for system tick in periodic mode + * if selected with NRF51_ST_USE_TIMER0 + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector60) { + + OSAL_IRQ_PROLOGUE(); + + /* Clear timer compare event */ + if (NRF_TIMER0->EVENTS_COMPARE[0] != 0) { + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + (void)NRF_TIMER0->EVENTS_COMPARE[0]; + + osalSysLockFromISR(); + osalOsTimerHandlerI(); + osalSysUnlockFromISR(); + } + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */ + +#if (OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING) || defined(__DOXYGEN__) +#if NRF51_ST_USE_RTC0 == TRUE +/** + * @brief System Timer vector (RTC0) + * @details This interrupt is used for freerunning mode (tick-less) + * if selected with NRF51_ST_USE_RTC0 + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector6C) { + + OSAL_IRQ_PROLOGUE(); + + if (NRF_RTC0->EVENTS_COMPARE[0]) { + NRF_RTC0->EVENTS_COMPARE[0] = 0; + (void)NRF_RTC0->EVENTS_COMPARE[0]; + + osalSysLockFromISR(); + osalOsTimerHandlerI(); + osalSysUnlockFromISR(); + } + +#if OSAL_ST_RESOLUTION == 16 + if (NRF_RTC0->EVENTS_COMPARE[1]) { + NRF_RTC0->EVENTS_COMPARE[1] = 0; + (void)NRF_RTC0->EVENTS_COMPARE[1]; + NRF_RTC0->TASKS_CLEAR = 1; + } +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if NRF51_ST_USE_RTC1 == TRUE +/** + * @brief System Timer vector (RTC1) + * @details This interrupt is used for freerunning mode (tick-less) + * if selected with NRF51_ST_USE_RTC1 + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector84) { + + OSAL_IRQ_PROLOGUE(); + + if (NRF_RTC1->EVENTS_COMPARE[0]) { + NRF_RTC1->EVENTS_COMPARE[0] = 0; + (void)NRF_RTC1->EVENTS_COMPARE[0]; + + osalSysLockFromISR(); + osalOsTimerHandlerI(); + osalSysUnlockFromISR(); + } + +#if OSAL_ST_RESOLUTION == 16 + if (NRF_RTC1->EVENTS_COMPARE[1]) { + NRF_RTC1->EVENTS_COMPARE[1] = 0; + (void)NRF_RTC1->EVENTS_COMPARE[1]; + NRF_RTC1->TASKS_CLEAR = 1; + } +#endif + + OSAL_IRQ_EPILOGUE(); +} +#endif +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ST driver initialization. + * + * @notapi + */ +void st_lld_init(void) { +#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING + +#if NRF51_ST_USE_RTC0 == TRUE + /* Using RTC with prescaler */ + NRF_RTC0->TASKS_STOP = 1; + NRF_RTC0->PRESCALER = (NRF51_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; + NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; + NRF_RTC0->EVENTS_COMPARE[0] = 0; + NRF_RTC0->INTENSET = RTC_INTENSET_COMPARE0_Msk; +#if OSAL_ST_RESOLUTION == 16 + NRF_RTC0->CC[1] = 0x10000; /* 2^16 */ + NRF_RTC0->EVENTS_COMPARE[1] = 0; + NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; + NRF_RTC0->INTENSET = RTC_INTENSET_COMPARE1_Msk; +#endif + NRF_RTC0->TASKS_CLEAR = 1; + + /* Start timer */ + nvicEnableVector(RTC0_IRQn, NRF51_ST_PRIORITY); + NRF_RTC0->TASKS_START = 1; +#endif /* NRF51_ST_USE_RTC0 == TRUE */ + +#if NRF51_ST_USE_RTC1 == TRUE + /* Using RTC with prescaler */ + NRF_RTC1->TASKS_STOP = 1; + NRF_RTC1->PRESCALER = (NRF51_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; + NRF_RTC1->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; + NRF_RTC1->EVENTS_COMPARE[0] = 0; + NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk; +#if OSAL_ST_RESOLUTION == 16 + NRF_RTC1->CC[1] = 0x10000; /* 2^16 */ + NRF_RTC1->EVENTS_COMPARE[1] = 0; + NRF_RTC1->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; + NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE1_Msk; +#endif + NRF_RTC1->TASKS_CLEAR = 1; + + /* Start timer */ + nvicEnableVector(RTC1_IRQn, NRF51_ST_PRIORITY); + NRF_RTC1->TASKS_START = 1; +#endif /* NRF51_ST_USE_RTC1 == TRUE */ + +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ + +#if OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC + +#if NRF51_ST_USE_RTC0 == TRUE + /* Using RTC with prescaler */ + NRF_RTC0->TASKS_STOP = 1; + NRF_RTC0->PRESCALER = (NRF51_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; + NRF_RTC0->INTENSET = RTC_INTENSET_TICK_Msk; + + /* Start timer */ + nvicEnableVector(RTC0_IRQn, NRF51_ST_PRIORITY); + NRF_RTC0->TASKS_START = 1; +#endif /* NRF51_ST_USE_RTC0 == TRUE */ + +#if NRF51_ST_USE_RTC1 == TRUE + /* Using RTC with prescaler */ + NRF_RTC1->TASKS_STOP = 1; + NRF_RTC1->PRESCALER = (NRF51_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; + NRF_RTC1->INTENSET = RTC_INTENSET_TICK_Msk; + + /* Start timer */ + nvicEnableVector(RTC1_IRQn, NRF51_ST_PRIORITY); + NRF_RTC1->TASKS_START = 1; +#endif /* NRF51_ST_USE_RTC1 == TRUE */ + +#if NRF51_ST_USE_TIMER0 == TRUE + NRF_TIMER0->TASKS_CLEAR = 1; + + /* + * Using 32-bit mode with prescaler 16 configures this + * timer with a 1MHz clock. + */ + NRF_TIMER0->BITMODE = 3; + NRF_TIMER0->PRESCALER = 4; + + /* + * Configure timer 0 compare capture 0 to generate interrupt + * and clear timer value when event is generated. + */ + NRF_TIMER0->CC[0] = (1000000 / OSAL_ST_FREQUENCY) - 1; + NRF_TIMER0->SHORTS = 1; + NRF_TIMER0->INTENSET = 0x10000; + + /* Start timer */ + nvicEnableVector(TIMER0_IRQn, NRF51_ST_PRIORITY); + NRF_TIMER0->TASKS_START = 1; +#endif /* NRF51_ST_USE_TIMER0 == TRUE */ + +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */ +} + +#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.h b/os/hal/ports/NRF5/LLD/hal_st_lld.h new file mode 100644 index 0000000..33cc0fb --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.h @@ -0,0 +1,275 @@ +/* + ChibiOS - Copyright (C) 2015 Fabio Utzig + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file st_lld.h + * @brief NRF51822 ST subsystem low level driver header. + * @details This header is designed to be include-able without having to + * include other files from the HAL. + * + * @addtogroup ST + * @{ + */ + +#ifndef HAL_ST_LLD_H +#define HAL_ST_LLD_H + +#include "halconf.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief Use RTC0 to generates system ticks + */ +#if !defined(NRF51_ST_USE_RTC0) || defined(__DOXYGEN__) +#if !defined(SOFTDEVICE_PRESENT) +#define NRF51_ST_USE_RTC0 TRUE +#else +#define NRF51_ST_USE_RTC0 FALSE +#endif +#endif + +/** + * @brief Use RTC1 to generates system ticks + */ +#if !defined(NRF51_ST_USE_RTC1) || defined(__DOXYGEN__) +#if !defined(SOFTDEVICE_PRESENT) +#define NRF51_ST_USE_RTC1 FALSE +#else +#define NRF51_ST_USE_RTC1 TRUE +#endif +#endif + +/** + * @brief Use TIMER0 to generates system ticks + */ +#if !defined(NRF51_ST_USE_TIMER0) || defined(__DOXYGEN__) +#define NRF51_ST_USE_TIMER0 FALSE +#endif + +/** + * @brief ST interrupt priority level setting. + */ +#if !defined(NRF51_ST_PRIORITY) || defined(__DOXYGEN__) +#if !defined(SOFTDEVICE_PRESENT) +#define NRF51_ST_PRIORITY CORTEX_MAX_KERNEL_PRIORITY +#else +#define NRF51_ST_PRIORITY 1 +#endif +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if OSAL_ST_MODE != OSAL_ST_MODE_NONE +#if (NRF51_ST_USE_TIMER0 == TRUE) && (NRF51_GPT_USE_TIMER0 == TRUE) +#error "TIMER0 already used by GPT driver" +#endif + +#if (NRF51_ST_USE_RTC0 == FALSE) && \ + (NRF51_ST_USE_RTC1 == FALSE) && \ + (NRF51_ST_USE_TIMER0 == FALSE) +#error "One clock source is needed, enable one (RTC0, RTC1, or TIMER0)" +#endif + +#if ((NRF51_ST_USE_RTC0 == TRUE ? 1 : 0) + \ + (NRF51_ST_USE_RTC1 == TRUE ? 1 : 0) + \ + (NRF51_ST_USE_TIMER0 == TRUE ? 1 : 0)) > 1 +#error "Only one clock source can be used (RTC0, RTC1, or TIMER0)" +#endif + +#if defined(SOFTDEVICE_PRESENT) +#if NRF51_ST_USE_RTC0 == TRUE +#error "RTC0 cannot be used for system ticks when SOFTDEVICE present" +#endif + +#if NRF51_ST_USE_TIMER0 == TRUE +#error "TIMER0 cannot be used for system ticks when SOFTDEVICE present" +#endif + +#if NRF51_ST_PRIORITY != 1 +#error "ST priority must be 1 when SOFTDEVICE present" +#endif + +#endif /* defined(SOFTDEVICE_PRESENT) */ +#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */ + +#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING +#if defined(CH_CFG_ST_TIMEDELTA) && (CH_CFG_ST_TIMEDELTA < 5) +#error "CH_CFG_ST_TIMEDELTA is too low" +#endif +#if NRF51_ST_USE_TIMER0 == TRUE +#error "Freeruning (tick-less) mode not supported with TIMER, use RTC" +#endif +#endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ + +#if !OSAL_IRQ_IS_VALID_PRIORITY(NRF51_ST_PRIORITY) +#error "Invalid IRQ priority assigned to ST driver" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void st_lld_init(void); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Driver inline functions. */ +/*===========================================================================*/ + +/** + * @brief Returns the time counter value. + * + * @return The counter value. + * + * @notapi + */ +static inline systime_t st_lld_get_counter(void) { +#if NRF51_ST_USE_RTC0 == TRUE + return (systime_t)NRF_RTC0->COUNTER; +#endif +#if NRF51_ST_USE_RTC1 == TRUE + return (systime_t)NRF_RTC1->COUNTER; +#endif +#if NRF51_ST_USE_TIMER0 == TRUE + return (systime_t)0; +#endif +} + +/** + * @brief Starts the alarm. + * @note Makes sure that no spurious alarms are triggered after + * this call. + * + * @param[in] abstime the time to be set for the first alarm + * + * @notapi + */ +static inline void st_lld_start_alarm(systime_t abstime) { +#if NRF51_ST_USE_RTC0 == TRUE + NRF_RTC0->CC[0] = abstime; + NRF_RTC0->EVENTS_COMPARE[0] = 0; + NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; +#endif +#if NRF51_ST_USE_RTC1 == TRUE + NRF_RTC1->CC[0] = abstime; + NRF_RTC1->EVENTS_COMPARE[0] = 0; + NRF_RTC1->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; +#endif +#if NRF51_ST_USE_TIMER0 == TRUE + (void)abstime; +#endif +} + +/** + * @brief Stops the alarm interrupt. + * + * @notapi + */ +static inline void st_lld_stop_alarm(void) { +#if NRF51_ST_USE_RTC0 == TRUE + NRF_RTC0->EVTENCLR = RTC_EVTENCLR_COMPARE0_Msk; + NRF_RTC0->EVENTS_COMPARE[0] = 0; +#endif +#if NRF51_ST_USE_RTC1 == TRUE + NRF_RTC1->EVTENCLR = RTC_EVTENCLR_COMPARE0_Msk; + NRF_RTC1->EVENTS_COMPARE[0] = 0; +#endif +} + +/** + * @brief Sets the alarm time. + * + * @param[in] abstime the time to be set for the next alarm + * + * @notapi + */ +static inline void st_lld_set_alarm(systime_t abstime) { +#if NRF51_ST_USE_RTC0 == TRUE + NRF_RTC0->CC[0] = abstime; +#endif +#if NRF51_ST_USE_RTC1 == TRUE + NRF_RTC1->CC[0] = abstime; +#endif +#if NRF51_ST_USE_TIMER0 == TRUE + (void)abstime; +#endif +} + +/** + * @brief Returns the current alarm time. + * + * @return The currently set alarm time. + * + * @notapi + */ +static inline systime_t st_lld_get_alarm(void) { +#if NRF51_ST_USE_RTC0 == TRUE + return (systime_t)NRF_RTC0->CC[0]; +#endif +#if NRF51_ST_USE_RTC1 == TRUE + return (systime_t)NRF_RTC1->CC[0]; +#endif +#if NRF51_ST_USE_TIMER0 == TRUE + return (systime_t)0; +#endif +} + +/** + * @brief Determines if the alarm is active. + * + * @return The alarm status. + * @retval false if the alarm is not active. + * @retval true is the alarm is active + * + * @notapi + */ +static inline bool st_lld_is_alarm_active(void) { +#if NRF51_ST_USE_RTC0 == TRUE + return NRF_RTC0->EVTEN & RTC_EVTEN_COMPARE0_Msk; +#endif +#if NRF51_ST_USE_RTC1 == TRUE + return NRF_RTC1->EVTEN & RTC_EVTEN_COMPARE0_Msk; +#endif +#if NRF51_ST_USE_TIMER0 == TRUE + return false; +#endif +} + +#endif /* HAL_ST_LLD_H */ + +/** @} */ -- cgit v1.2.3 From 7557cbac22ac5da99fa5681f3d311277bebbbaae Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 00:10:48 +0200 Subject: serie -> series --- os/hal/ports/NRF5/LLD/hal_pal_lld.h | 4 ++-- os/hal/ports/NRF5/LLD/hal_serial_lld.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_pal_lld.h b/os/hal/ports/NRF5/LLD/hal_pal_lld.h index da2da74..40a2c5e 100644 --- a/os/hal/ports/NRF5/LLD/hal_pal_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_pal_lld.h @@ -128,9 +128,9 @@ typedef NRF_GPIO_Type *ioportid_t; * @details Low level drivers can define multiple ports, it is suggested to * use this naming convention. */ -#if NRF_SERIE == 51 +#if NRF_SERIES == 51 #define IOPORT1 NRF_GPIO -#elif NRF_SERIE == 52 +#elif NRF_SERIES == 52 #define IOPORT1 NRF_P0 #endif diff --git a/os/hal/ports/NRF5/LLD/hal_serial_lld.c b/os/hal/ports/NRF5/LLD/hal_serial_lld.c index cba7804..e67b433 100644 --- a/os/hal/ports/NRF5/LLD/hal_serial_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_serial_lld.c @@ -26,9 +26,9 @@ #if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) -#if NRF_SERIE == 51 +#if NRF_SERIES == 51 #include "nrf51.h" -#elif NRF_SERIE == 52 +#elif NRF_SERIES == 52 #include "nrf52.h" #define UART0_IRQn UARTE0_UART0_IRQn #endif -- cgit v1.2.3 From 1908537785516004f2014ccb2d6db31a2fe56173 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 00:23:12 +0200 Subject: use constantes --- os/hal/ports/NRF5/LLD/hal_st_lld.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.c b/os/hal/ports/NRF5/LLD/hal_st_lld.c index 3a988a8..a2c1a8f 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.c @@ -278,7 +278,7 @@ void st_lld_init(void) { * Using 32-bit mode with prescaler 16 configures this * timer with a 1MHz clock. */ - NRF_TIMER0->BITMODE = 3; + NRF_TIMER0->BITMODE = TIMER_BITMODE_BITMODE_32Bit; NRF_TIMER0->PRESCALER = 4; /* @@ -287,7 +287,7 @@ void st_lld_init(void) { */ NRF_TIMER0->CC[0] = (1000000 / OSAL_ST_FREQUENCY) - 1; NRF_TIMER0->SHORTS = 1; - NRF_TIMER0->INTENSET = 0x10000; + NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Msk; /* Start timer */ nvicEnableVector(TIMER0_IRQn, NRF51_ST_PRIORITY); -- cgit v1.2.3 From 5259158d1727f3703bc90f88d50938eada316f67 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 10:48:04 +0200 Subject: renamed NRF51_* to NRF5_* --- os/hal/ports/NRF5/LLD/hal_pal_lld.c | 4 +- os/hal/ports/NRF5/LLD/hal_pal_lld.h | 4 +- os/hal/ports/NRF5/LLD/hal_serial_lld.c | 56 ++++++++++++------------ os/hal/ports/NRF5/LLD/hal_serial_lld.h | 28 ++++++------ os/hal/ports/NRF5/LLD/hal_st_lld.c | 62 +++++++++++++------------- os/hal/ports/NRF5/LLD/hal_st_lld.h | 80 +++++++++++++++++----------------- 6 files changed, 118 insertions(+), 116 deletions(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_pal_lld.c b/os/hal/ports/NRF5/LLD/hal_pal_lld.c index cb25ee4..21e4b0b 100644 --- a/os/hal/ports/NRF5/LLD/hal_pal_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_pal_lld.c @@ -15,7 +15,7 @@ */ /** - * @file pal_lld.c + * @file NRF5/LLD/hal_pal_lld.c * @brief NRF5 PAL subsystem low level driver source. * * @addtogroup PAL @@ -46,7 +46,7 @@ void _pal_lld_setpadmode(ioportid_t port, uint8_t pad, iomode_t mode) { (void)port; - osalDbgAssert(pad <= 31, "pal_lld_setpadmode() - invalid pad"); + osalDbgAssert(pad < PAL_IOPORTS_WIDTH, "pal_lld_setpadmode() - invalid pad"); switch (mode) { case PAL_MODE_RESET: diff --git a/os/hal/ports/NRF5/LLD/hal_pal_lld.h b/os/hal/ports/NRF5/LLD/hal_pal_lld.h index 40a2c5e..9eb333d 100644 --- a/os/hal/ports/NRF5/LLD/hal_pal_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_pal_lld.h @@ -15,7 +15,7 @@ */ /** - * @file pal_lld.h + * @file NRF5/LLD/hal_pal_lld.h * @brief NRF5 PAL subsystem low level driver header. * * @addtogroup PAL @@ -132,6 +132,8 @@ typedef NRF_GPIO_Type *ioportid_t; #define IOPORT1 NRF_GPIO #elif NRF_SERIES == 52 #define IOPORT1 NRF_P0 +#else +#error "Unknown NRF_SERIES" #endif /*===========================================================================*/ diff --git a/os/hal/ports/NRF5/LLD/hal_serial_lld.c b/os/hal/ports/NRF5/LLD/hal_serial_lld.c index e67b433..31e5ade 100644 --- a/os/hal/ports/NRF5/LLD/hal_serial_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_serial_lld.c @@ -15,8 +15,8 @@ */ /** - * @file serial_lld.c - * @brief NRF51822 serial subsystem low level driver source. + * @file NRF5/LLD/hal_serial_lld.c + * @brief NRF5 serial subsystem low level driver source. * * @addtogroup SERIAL * @{ @@ -43,7 +43,7 @@ /*===========================================================================*/ /** @brief USART1 serial driver identifier.*/ -#if (NRF51_SERIAL_USE_UART0 == TRUE) || defined(__DOXYGEN__) +#if (NRF5_SERIAL_USE_UART0 == TRUE) || defined(__DOXYGEN__) SerialDriver SD1; #endif @@ -56,11 +56,11 @@ SerialDriver SD1; */ static const SerialConfig default_config = { .speed = 38400, - .tx_pad = NRF51_SERIAL_PAD_DISCONNECTED, - .rx_pad = NRF51_SERIAL_PAD_DISCONNECTED, -#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) - .rts_pad = NRF51_SERIAL_PAD_DISCONNECTED, - .cts_pad = NRF51_SERIAL_PAD_DISCONNECTED, + .tx_pad = NRF5_SERIAL_PAD_DISCONNECTED, + .rx_pad = NRF5_SERIAL_PAD_DISCONNECTED, +#if (NRF5_SERIAL_USE_HWFLOWCTRL == TRUE) + .rts_pad = NRF5_SERIAL_PAD_DISCONNECTED, + .cts_pad = NRF5_SERIAL_PAD_DISCONNECTED, #endif }; @@ -101,17 +101,17 @@ static void configure_uart(const SerialConfig *config) }; /* Configure PINs mode */ - if (config->tx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + if (config->tx_pad != NRF5_SERIAL_PAD_DISCONNECTED) { palSetPadMode(IOPORT1, config->tx_pad, PAL_MODE_OUTPUT_PUSHPULL); } - if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + if (config->rx_pad != NRF5_SERIAL_PAD_DISCONNECTED) { palSetPadMode(IOPORT1, config->rx_pad, PAL_MODE_INPUT); } -#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) - if (config->rts_pad != NRF51_SERIAL_PAD_DISCONNECTED) { +#if (NRF5_SERIAL_USE_HWFLOWCTRL == TRUE) + if (config->rts_pad != NRF5_SERIAL_PAD_DISCONNECTED) { palSetPadMode(IOPORT1, config->rts_pad, PAL_MODE_OUTPUT_PUSHPULL); } - if (config->cts_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + if (config->cts_pad != NRF5_SERIAL_PAD_DISCONNECTED) { palSetPadMode(IOPORT1, config->cts_pad, PAL_MODE_INPUT); } #endif @@ -119,12 +119,12 @@ static void configure_uart(const SerialConfig *config) /* Select PINs used by UART */ NRF_UART0->PSELTXD = config->tx_pad; NRF_UART0->PSELRXD = config->rx_pad; -#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) +#if (NRF5_SERIAL_USE_HWFLOWCTRL == TRUE) NRF_UART0->PSELRTS = config->rts_pad; NRF_UART0->PSELCTS = config->cts_pad; #else - NRF_UART0->PSELRTS = NRF51_SERIAL_PAD_DISCONNECTED; - NRF_UART0->PSELCTS = NRF51_SERIAL_PAD_DISCONNECTED; + NRF_UART0->PSELRTS = NRF5_SERIAL_PAD_DISCONNECTED; + NRF_UART0->PSELCTS = NRF5_SERIAL_PAD_DISCONNECTED; #endif /* Set baud rate */ @@ -134,7 +134,7 @@ static void configure_uart(const SerialConfig *config) NRF_UART0->CONFIG = (UART_CONFIG_PARITY_Excluded << UART_CONFIG_PARITY_Pos); /* Adjust flow control */ -#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) +#if (NRF5_SERIAL_USE_HWFLOWCTRL == TRUE) if ((config->rts_pad < TOTAL_GPIO_PADS) || (config->cts_pad < TOTAL_GPIO_PADS)) { NRF_UART0->CONFIG |= UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos; @@ -152,7 +152,7 @@ static void configure_uart(const SerialConfig *config) NRF_UART0->EVENTS_TXDRDY = 0; (void)NRF_UART0->EVENTS_TXDRDY; - if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + if (config->rx_pad != NRF5_SERIAL_PAD_DISCONNECTED) { while (NRF_UART0->EVENTS_RXDRDY != 0) { (void)NRF_UART0->RXD; } @@ -163,14 +163,14 @@ static void configure_uart(const SerialConfig *config) /** * @brief Driver output notification. */ -#if NRF51_SERIAL_USE_UART0 || defined(__DOXYGEN__) +#if NRF5_SERIAL_USE_UART0 || defined(__DOXYGEN__) static void notify1(io_queue_t *qp) { SerialDriver *sdp = &SD1; (void)qp; - if (NRF_UART0->PSELTXD == NRF51_SERIAL_PAD_DISCONNECTED) + if (NRF_UART0->PSELTXD == NRF5_SERIAL_PAD_DISCONNECTED) return; if (!sdp->tx_busy) { @@ -193,7 +193,7 @@ static void notify1(io_queue_t *qp) /* Driver interrupt handlers. */ /*===========================================================================*/ -#if NRF51_SERIAL_USE_UART0 || defined(__DOXYGEN__) +#if NRF5_SERIAL_USE_UART0 || defined(__DOXYGEN__) OSAL_IRQ_HANDLER(Vector48) { OSAL_IRQ_PROLOGUE(); @@ -260,7 +260,7 @@ OSAL_IRQ_HANDLER(Vector48) { */ void sd_lld_init(void) { -#if NRF51_SERIAL_USE_UART0 == TRUE +#if NRF5_SERIAL_USE_UART0 == TRUE sdObjectInit(&SD1, NULL, notify1); #endif } @@ -286,21 +286,21 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { if (sdp->state == SD_STOP) { -#if NRF51_SERIAL_USE_UART0 == TRUE +#if NRF5_SERIAL_USE_UART0 == TRUE if (sdp == &SD1) { configure_uart(config); // Enable UART interrupt NRF_UART0->INTENCLR = (uint32_t)-1; NRF_UART0->INTENSET = UART_INTENSET_ERROR_Msk; - if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + if (config->rx_pad != NRF5_SERIAL_PAD_DISCONNECTED) NRF_UART0->INTENSET |= UART_INTENSET_RXDRDY_Msk; - if (config->tx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + if (config->tx_pad != NRF5_SERIAL_PAD_DISCONNECTED) NRF_UART0->INTENSET |= UART_INTENSET_TXDRDY_Msk; - nvicEnableVector(UART0_IRQn, NRF51_SERIAL_UART0_PRIORITY); + nvicEnableVector(UART0_IRQn, NRF5_SERIAL_UART0_PRIORITY); - if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + if (config->rx_pad != NRF5_SERIAL_PAD_DISCONNECTED) NRF_UART0->TASKS_STARTRX = 1; } #endif @@ -321,7 +321,7 @@ void sd_lld_stop(SerialDriver *sdp) { if (sdp->state == SD_READY) { -#if NRF51_SERIAL_USE_UART0 == TRUE +#if NRF5_SERIAL_USE_UART0 == TRUE if (&SD1 == sdp) { nvicDisableVector(UART0_IRQn); NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Disabled; diff --git a/os/hal/ports/NRF5/LLD/hal_serial_lld.h b/os/hal/ports/NRF5/LLD/hal_serial_lld.h index 79955b1..741a40a 100644 --- a/os/hal/ports/NRF5/LLD/hal_serial_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_serial_lld.h @@ -15,8 +15,8 @@ */ /** - * @file serial_lld.h - * @brief NRF51822 serial subsystem low level driver header. + * @file NRF5/LLD/hal_serial_lld.h + * @brief NRF5 serial subsystem low level driver header. * * @addtogroup SERIAL * @{ @@ -45,8 +45,8 @@ * is included. * @note The default is @p FALSE. */ -#if !defined(NRF51_SERIAL_USE_HWFLOWCTRL) || defined(__DOXYGEN__) -#define NRF51_SERIAL_USE_HWFLOWCTRL FALSE +#if !defined(NRF5_SERIAL_USE_HWFLOWCTRL) || defined(__DOXYGEN__) +#define NRF5_SERIAL_USE_HWFLOWCTRL FALSE #endif /** @@ -54,20 +54,20 @@ * @details If set to @p TRUE the support for SD1 is included. * @note The default is @p FALSE. */ -#if !defined(NRF51_SERIAL_USE_UART0) || defined(__DOXYGEN__) -#define NRF51_SERIAL_USE_UART0 FALSE +#if !defined(NRF5_SERIAL_USE_UART0) || defined(__DOXYGEN__) +#define NRF5_SERIAL_USE_UART0 FALSE #endif /** * @brief UART0 interrupt priority level setting. */ -#if !defined(NRF51_SERIAL_UART0_PRIORITY) || defined(__DOXYGEN__) -#define NRF51_SERIAL_UART0_PRIORITY 3 +#if !defined(NRF5_SERIAL_UART0_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_SERIAL_UART0_PRIORITY 3 #endif /* Value indicating that no pad is connected to this UART register. */ -#define NRF51_SERIAL_PAD_DISCONNECTED 0xFFFFFFFFU -#define NRF51_SERIAL_INVALID_BAUDRATE 0xFFFFFFFFU +#define NRF5_SERIAL_PAD_DISCONNECTED 0xFFFFFFFFU +#define NRF5_SERIAL_INVALID_BAUDRATE 0xFFFFFFFFU /** @} */ @@ -75,8 +75,8 @@ /* Derived constants and error checks. */ /*===========================================================================*/ -#if NRF51_SERIAL_USE_UART0 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(NRF51_SERIAL_UART0_PRIORITY) +#if NRF5_SERIAL_USE_UART0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_SERIAL_UART0_PRIORITY) #error "Invalid IRQ priority assigned to UART0" #endif @@ -100,7 +100,7 @@ typedef struct { /* End of the mandatory fields.*/ uint32_t tx_pad; uint32_t rx_pad; -#if (NRF51_SERIAL_USE_HWFLOWCTRL == TRUE) +#if (NRF5_SERIAL_USE_HWFLOWCTRL == TRUE) uint32_t rts_pad; uint32_t cts_pad; #endif @@ -134,7 +134,7 @@ typedef struct { /* External declarations. */ /*===========================================================================*/ -#if (NRF51_SERIAL_USE_UART0 == TRUE) && !defined(__DOXYGEN__) +#if (NRF5_SERIAL_USE_UART0 == TRUE) && !defined(__DOXYGEN__) extern SerialDriver SD1; #endif diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.c b/os/hal/ports/NRF5/LLD/hal_st_lld.c index a2c1a8f..931f1a7 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.c @@ -16,8 +16,8 @@ */ /** - * @file st_lld.c - * @brief NRF51822 ST subsystem low level driver source. + * @file NRF5/LLD/hal_st_lld.c + * @brief NRF5 ST subsystem low level driver source. * * @addtogroup ST * @{ @@ -52,11 +52,11 @@ /*===========================================================================*/ #if (OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC) || defined(__DOXYGEN__) -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE /** * @brief System Timer vector (RTC0) * @details This interrupt is used for system tick in periodic mode - * if selected with NRF51_ST_USE_RTC0 + * if selected with NRF5_ST_USE_RTC0 * * @isr */ @@ -75,11 +75,11 @@ OSAL_IRQ_HANDLER(Vector6C) { } #endif -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE /** * @brief System Timer vector (RTC1) * @details This interrupt is used for system tick in periodic mode - * if selected with NRF51_ST_USE_RTC1 + * if selected with NRF5_ST_USE_RTC1 * * @isr */ @@ -98,11 +98,11 @@ OSAL_IRQ_HANDLER(Vector84) { } #endif -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE /** * @brief System Timer vector. (TIMER0) * @details This interrupt is used for system tick in periodic mode - * if selected with NRF51_ST_USE_TIMER0 + * if selected with NRF5_ST_USE_TIMER0 * * @isr */ @@ -126,11 +126,11 @@ OSAL_IRQ_HANDLER(Vector60) { #endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */ #if (OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING) || defined(__DOXYGEN__) -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE /** * @brief System Timer vector (RTC0) * @details This interrupt is used for freerunning mode (tick-less) - * if selected with NRF51_ST_USE_RTC0 + * if selected with NRF5_ST_USE_RTC0 * * @isr */ @@ -159,11 +159,11 @@ OSAL_IRQ_HANDLER(Vector6C) { } #endif -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE /** * @brief System Timer vector (RTC1) * @details This interrupt is used for freerunning mode (tick-less) - * if selected with NRF51_ST_USE_RTC1 + * if selected with NRF5_ST_USE_RTC1 * * @isr */ @@ -205,10 +205,10 @@ OSAL_IRQ_HANDLER(Vector84) { void st_lld_init(void) { #if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE /* Using RTC with prescaler */ NRF_RTC0->TASKS_STOP = 1; - NRF_RTC0->PRESCALER = (NRF51_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; + NRF_RTC0->PRESCALER = (NRF5_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; NRF_RTC0->EVENTS_COMPARE[0] = 0; NRF_RTC0->INTENSET = RTC_INTENSET_COMPARE0_Msk; @@ -221,14 +221,14 @@ void st_lld_init(void) { NRF_RTC0->TASKS_CLEAR = 1; /* Start timer */ - nvicEnableVector(RTC0_IRQn, NRF51_ST_PRIORITY); + nvicEnableVector(RTC0_IRQn, NRF5_ST_PRIORITY); NRF_RTC0->TASKS_START = 1; -#endif /* NRF51_ST_USE_RTC0 == TRUE */ +#endif /* NRF5_ST_USE_RTC0 == TRUE */ -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE /* Using RTC with prescaler */ NRF_RTC1->TASKS_STOP = 1; - NRF_RTC1->PRESCALER = (NRF51_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; + NRF_RTC1->PRESCALER = (NRF5_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; NRF_RTC1->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; NRF_RTC1->EVENTS_COMPARE[0] = 0; NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk; @@ -241,37 +241,37 @@ void st_lld_init(void) { NRF_RTC1->TASKS_CLEAR = 1; /* Start timer */ - nvicEnableVector(RTC1_IRQn, NRF51_ST_PRIORITY); + nvicEnableVector(RTC1_IRQn, NRF5_ST_PRIORITY); NRF_RTC1->TASKS_START = 1; -#endif /* NRF51_ST_USE_RTC1 == TRUE */ +#endif /* NRF5_ST_USE_RTC1 == TRUE */ #endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ #if OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE /* Using RTC with prescaler */ NRF_RTC0->TASKS_STOP = 1; - NRF_RTC0->PRESCALER = (NRF51_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; + NRF_RTC0->PRESCALER = (NRF5_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; NRF_RTC0->INTENSET = RTC_INTENSET_TICK_Msk; /* Start timer */ - nvicEnableVector(RTC0_IRQn, NRF51_ST_PRIORITY); + nvicEnableVector(RTC0_IRQn, NRF5_ST_PRIORITY); NRF_RTC0->TASKS_START = 1; -#endif /* NRF51_ST_USE_RTC0 == TRUE */ +#endif /* NRF5_ST_USE_RTC0 == TRUE */ -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE /* Using RTC with prescaler */ NRF_RTC1->TASKS_STOP = 1; - NRF_RTC1->PRESCALER = (NRF51_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; + NRF_RTC1->PRESCALER = (NRF5_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; NRF_RTC1->INTENSET = RTC_INTENSET_TICK_Msk; /* Start timer */ - nvicEnableVector(RTC1_IRQn, NRF51_ST_PRIORITY); + nvicEnableVector(RTC1_IRQn, NRF5_ST_PRIORITY); NRF_RTC1->TASKS_START = 1; -#endif /* NRF51_ST_USE_RTC1 == TRUE */ +#endif /* NRF5_ST_USE_RTC1 == TRUE */ -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE NRF_TIMER0->TASKS_CLEAR = 1; /* @@ -290,9 +290,9 @@ void st_lld_init(void) { NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Msk; /* Start timer */ - nvicEnableVector(TIMER0_IRQn, NRF51_ST_PRIORITY); + nvicEnableVector(TIMER0_IRQn, NRF5_ST_PRIORITY); NRF_TIMER0->TASKS_START = 1; -#endif /* NRF51_ST_USE_TIMER0 == TRUE */ +#endif /* NRF5_ST_USE_TIMER0 == TRUE */ #endif /* OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC */ } diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.h b/os/hal/ports/NRF5/LLD/hal_st_lld.h index 33cc0fb..eb425f9 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.h @@ -40,40 +40,40 @@ /** * @brief Use RTC0 to generates system ticks */ -#if !defined(NRF51_ST_USE_RTC0) || defined(__DOXYGEN__) +#if !defined(NRF5_ST_USE_RTC0) || defined(__DOXYGEN__) #if !defined(SOFTDEVICE_PRESENT) -#define NRF51_ST_USE_RTC0 TRUE +#define NRF5_ST_USE_RTC0 TRUE #else -#define NRF51_ST_USE_RTC0 FALSE +#define NRF5_ST_USE_RTC0 FALSE #endif #endif /** * @brief Use RTC1 to generates system ticks */ -#if !defined(NRF51_ST_USE_RTC1) || defined(__DOXYGEN__) +#if !defined(NRF5_ST_USE_RTC1) || defined(__DOXYGEN__) #if !defined(SOFTDEVICE_PRESENT) -#define NRF51_ST_USE_RTC1 FALSE +#define NRF5_ST_USE_RTC1 FALSE #else -#define NRF51_ST_USE_RTC1 TRUE +#define NRF5_ST_USE_RTC1 TRUE #endif #endif /** * @brief Use TIMER0 to generates system ticks */ -#if !defined(NRF51_ST_USE_TIMER0) || defined(__DOXYGEN__) -#define NRF51_ST_USE_TIMER0 FALSE +#if !defined(NRF5_ST_USE_TIMER0) || defined(__DOXYGEN__) +#define NRF5_ST_USE_TIMER0 FALSE #endif /** * @brief ST interrupt priority level setting. */ -#if !defined(NRF51_ST_PRIORITY) || defined(__DOXYGEN__) +#if !defined(NRF5_ST_PRIORITY) || defined(__DOXYGEN__) #if !defined(SOFTDEVICE_PRESENT) -#define NRF51_ST_PRIORITY CORTEX_MAX_KERNEL_PRIORITY +#define NRF5_ST_PRIORITY CORTEX_MAX_KERNEL_PRIORITY #else -#define NRF51_ST_PRIORITY 1 +#define NRF5_ST_PRIORITY 1 #endif #endif @@ -82,32 +82,32 @@ /*===========================================================================*/ #if OSAL_ST_MODE != OSAL_ST_MODE_NONE -#if (NRF51_ST_USE_TIMER0 == TRUE) && (NRF51_GPT_USE_TIMER0 == TRUE) +#if (NRF5_ST_USE_TIMER0 == TRUE) && (NRF5_GPT_USE_TIMER0 == TRUE) #error "TIMER0 already used by GPT driver" #endif -#if (NRF51_ST_USE_RTC0 == FALSE) && \ - (NRF51_ST_USE_RTC1 == FALSE) && \ - (NRF51_ST_USE_TIMER0 == FALSE) +#if (NRF5_ST_USE_RTC0 == FALSE) && \ + (NRF5_ST_USE_RTC1 == FALSE) && \ + (NRF5_ST_USE_TIMER0 == FALSE) #error "One clock source is needed, enable one (RTC0, RTC1, or TIMER0)" #endif -#if ((NRF51_ST_USE_RTC0 == TRUE ? 1 : 0) + \ - (NRF51_ST_USE_RTC1 == TRUE ? 1 : 0) + \ - (NRF51_ST_USE_TIMER0 == TRUE ? 1 : 0)) > 1 +#if ((NRF5_ST_USE_RTC0 == TRUE ? 1 : 0) + \ + (NRF5_ST_USE_RTC1 == TRUE ? 1 : 0) + \ + (NRF5_ST_USE_TIMER0 == TRUE ? 1 : 0)) > 1 #error "Only one clock source can be used (RTC0, RTC1, or TIMER0)" #endif #if defined(SOFTDEVICE_PRESENT) -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE #error "RTC0 cannot be used for system ticks when SOFTDEVICE present" #endif -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE #error "TIMER0 cannot be used for system ticks when SOFTDEVICE present" #endif -#if NRF51_ST_PRIORITY != 1 +#if NRF5_ST_PRIORITY != 1 #error "ST priority must be 1 when SOFTDEVICE present" #endif @@ -118,12 +118,12 @@ #if defined(CH_CFG_ST_TIMEDELTA) && (CH_CFG_ST_TIMEDELTA < 5) #error "CH_CFG_ST_TIMEDELTA is too low" #endif -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE #error "Freeruning (tick-less) mode not supported with TIMER, use RTC" #endif #endif /* OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING */ -#if !OSAL_IRQ_IS_VALID_PRIORITY(NRF51_ST_PRIORITY) +#if !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_ST_PRIORITY) #error "Invalid IRQ priority assigned to ST driver" #endif @@ -159,13 +159,13 @@ extern "C" { * @notapi */ static inline systime_t st_lld_get_counter(void) { -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE return (systime_t)NRF_RTC0->COUNTER; #endif -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE return (systime_t)NRF_RTC1->COUNTER; #endif -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE return (systime_t)0; #endif } @@ -180,17 +180,17 @@ static inline systime_t st_lld_get_counter(void) { * @notapi */ static inline void st_lld_start_alarm(systime_t abstime) { -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE NRF_RTC0->CC[0] = abstime; NRF_RTC0->EVENTS_COMPARE[0] = 0; NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; #endif -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE NRF_RTC1->CC[0] = abstime; NRF_RTC1->EVENTS_COMPARE[0] = 0; NRF_RTC1->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; #endif -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE (void)abstime; #endif } @@ -201,11 +201,11 @@ static inline void st_lld_start_alarm(systime_t abstime) { * @notapi */ static inline void st_lld_stop_alarm(void) { -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE NRF_RTC0->EVTENCLR = RTC_EVTENCLR_COMPARE0_Msk; NRF_RTC0->EVENTS_COMPARE[0] = 0; #endif -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE NRF_RTC1->EVTENCLR = RTC_EVTENCLR_COMPARE0_Msk; NRF_RTC1->EVENTS_COMPARE[0] = 0; #endif @@ -219,13 +219,13 @@ static inline void st_lld_stop_alarm(void) { * @notapi */ static inline void st_lld_set_alarm(systime_t abstime) { -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE NRF_RTC0->CC[0] = abstime; #endif -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE NRF_RTC1->CC[0] = abstime; #endif -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE (void)abstime; #endif } @@ -238,13 +238,13 @@ static inline void st_lld_set_alarm(systime_t abstime) { * @notapi */ static inline systime_t st_lld_get_alarm(void) { -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE return (systime_t)NRF_RTC0->CC[0]; #endif -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE return (systime_t)NRF_RTC1->CC[0]; #endif -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE return (systime_t)0; #endif } @@ -259,13 +259,13 @@ static inline systime_t st_lld_get_alarm(void) { * @notapi */ static inline bool st_lld_is_alarm_active(void) { -#if NRF51_ST_USE_RTC0 == TRUE +#if NRF5_ST_USE_RTC0 == TRUE return NRF_RTC0->EVTEN & RTC_EVTEN_COMPARE0_Msk; #endif -#if NRF51_ST_USE_RTC1 == TRUE +#if NRF5_ST_USE_RTC1 == TRUE return NRF_RTC1->EVTEN & RTC_EVTEN_COMPARE0_Msk; #endif -#if NRF51_ST_USE_TIMER0 == TRUE +#if NRF5_ST_USE_TIMER0 == TRUE return false; #endif } -- cgit v1.2.3 From e0d39de32f8a422ec1e1badfe70b3f3126edcb0d Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 11:11:50 +0200 Subject: Use RTC1 as default system ticks as PPI has pre-programmed channels for RTC0 --- os/hal/ports/NRF5/LLD/hal_st_lld.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.h b/os/hal/ports/NRF5/LLD/hal_st_lld.h index eb425f9..4799792 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.h @@ -41,23 +41,15 @@ * @brief Use RTC0 to generates system ticks */ #if !defined(NRF5_ST_USE_RTC0) || defined(__DOXYGEN__) -#if !defined(SOFTDEVICE_PRESENT) -#define NRF5_ST_USE_RTC0 TRUE -#else #define NRF5_ST_USE_RTC0 FALSE #endif -#endif /** * @brief Use RTC1 to generates system ticks */ #if !defined(NRF5_ST_USE_RTC1) || defined(__DOXYGEN__) -#if !defined(SOFTDEVICE_PRESENT) -#define NRF5_ST_USE_RTC1 FALSE -#else #define NRF5_ST_USE_RTC1 TRUE #endif -#endif /** * @brief Use TIMER0 to generates system ticks -- cgit v1.2.3 From 3db81f7f03844057a6d4150e2c66a81a772df16d Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 11:15:20 +0200 Subject: adding note on RTC0 and TIMER0 as systicks --- os/hal/ports/NRF5/LLD/hal_st_lld.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.h b/os/hal/ports/NRF5/LLD/hal_st_lld.h index 4799792..3b4bf8e 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.h @@ -39,6 +39,9 @@ /** * @brief Use RTC0 to generates system ticks + * + * @note Avoid using RTC0, as PPI has pre-programmed channels on it + * that can be used to control RADIO or TIMER0 */ #if !defined(NRF5_ST_USE_RTC0) || defined(__DOXYGEN__) #define NRF5_ST_USE_RTC0 FALSE @@ -53,6 +56,8 @@ /** * @brief Use TIMER0 to generates system ticks + * + * @note Avoid using TIMER0 as it will draw more current */ #if !defined(NRF5_ST_USE_TIMER0) || defined(__DOXYGEN__) #define NRF5_ST_USE_TIMER0 FALSE -- cgit v1.2.3 From 6423c3dabeba4e4ed9217d71873653bc8af9ae4e Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 12:04:39 +0200 Subject: moved rng to LLD directory. removed rng power control (doesn't exist in nrf52, wasn't documented in nrf51) renamed peripheral to start at 0 --- os/hal/ports/NRF5/LLD/hal_rng_lld.c | 163 +++++++++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_rng_lld.h | 166 ++++++++++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_st_lld.c | 4 +- os/hal/ports/NRF5/LLD/hal_st_lld.h | 4 +- 4 files changed, 333 insertions(+), 4 deletions(-) create mode 100644 os/hal/ports/NRF5/LLD/hal_rng_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_rng_lld.h (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_rng_lld.c b/os/hal/ports/NRF5/LLD/hal_rng_lld.c new file mode 100644 index 0000000..5e85981 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_rng_lld.c @@ -0,0 +1,163 @@ +/* + RNG for ChibiOS - Copyright (C) 2016 Stephane D'Alu + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/hal_rng_lld.c + * @brief NRF5 RNG subsystem low level driver source. + * + * @addtogroup RNG + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_RNG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/** + * @brief RNG default configuration. + */ +static const RNGConfig default_config = { + .digital_error_correction = 1, +}; + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief RNGD1 driver identifier.*/ +#if NRF5_RNG_USE_RNG0 || defined(__DOXYGEN__) +RNGDriver RNGD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level RNG driver initialization. + * + * @notapi + */ +void rng_lld_init(void) { + rngObjectInit(&RNGD1); + RNGD1.rng = NRF_RNG; + RNGD1.irq = RNG_IRQn; +} + +/** + * @brief Configures and activates the RNG peripheral. + * + * @param[in] rngp pointer to the @p RNGDriver object + * + * @notapi + */ +void rng_lld_start(RNGDriver *rngp) { + NRF_RNG_Type *rng = rngp->rng; + + /* If not specified, set default configuration */ + if (rngp->config == NULL) + rngp->config = &default_config; + + /* Configure digital error correction */ + if (rngp->config->digital_error_correction) + rng->CONFIG |= RNG_CONFIG_DERCEN_Msk; + else + rng->CONFIG &= ~RNG_CONFIG_DERCEN_Msk; + + /* Clear pending events */ + rng->EVENTS_VALRDY = 0; + + /* Set interrupt mask */ + rng->INTENSET = RNG_INTENSET_VALRDY_Msk; + + /* Start */ + rng->TASKS_START = 1; +} + + +/** + * @brief Deactivates the RNG peripheral. + * + * @param[in] rngp pointer to the @p RNGDriver object + * + * @notapi + */ +void rng_lld_stop(RNGDriver *rngp) { + NRF_RNG_Type *rng = rngp->rng; + + /* Stop peripheric */ + rng->TASKS_STOP = 1; +} + + +/** + * @brief Write random bytes; + * + * @param[in] rngp pointer to the @p RNGDriver object + * @param[in] n size of buf in bytes + * @param[in] buf @p buffer location + * + * @notapi + */ +msg_t rng_lld_write(RNGDriver *rngp, uint8_t *buf, size_t n, + systime_t timeout) { + NRF_RNG_Type *rng = rngp->rng; + size_t i; + + for (i = 0 ; i < n ; i++) { + /* Wait for byte ready + * It take about 677µs to generate a new byte, not sure if + * forcing a context switch will be a benefit + */ + while (rng->EVENTS_VALRDY == 0) { + /* Sleep and wakeup on ARM event (interrupt) */ + SCB->SCR |= SCB_SCR_SEVONPEND_Msk; + __SEV(); + __WFE(); + __WFE(); + } + + /* Read byte */ + buf[i] = (char)rng->VALUE; + + /* Mark as read */ + rng->EVENTS_VALRDY = 0; + + /* Clear interrupt so we can wake up again */ + nvicClearPending(rngp->irq); + } + return MSG_OK; +} + +#endif /* HAL_USE_RNG */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_rng_lld.h b/os/hal/ports/NRF5/LLD/hal_rng_lld.h new file mode 100644 index 0000000..9a9f471 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_rng_lld.h @@ -0,0 +1,166 @@ +/* + RNG for ChibiOS - Copyright (C) 2016 Stephane D'Alu + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/hal_rng_lld.h + * @brief NRF5 RNG subsystem low level driver header. + * + * @addtogroup RNG + * @{ + */ + +#ifndef HAL_RNG_LLD_H +#define HAL_RNG_LLD_H + +#if (HAL_USE_RNG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief RNGD1 driver enable switch. + * @details If set to @p TRUE the support for RNGD1 is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_RNG_USE_RNG0) || defined(__DOXYGEN__) +#define NRF5_RNG_USE_RNG0 FALSE +#endif + +/** + * @brief RNG interrupt priority level setting for RNG0. + */ +#if !defined(NRF5_RNG_RNG0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_RNG_RNG0_IRQ_PRIORITY 3 +#endif + + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if NRF5_RNG_USE_RNG0 == FALSE +#error "Requesting RNG driver, but no RNG peripheric attached" +#endif + +#if NRF5_RNG_USE_RNG0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_RNG_RNG0_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to RNG0" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an RNG driver. + */ +typedef struct RNGDriver RNGDriver; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /* End of the mandatory fields.*/ + /** + * @brief Activate the digital error correction + * + * @details A digital corrector algorithm is employed to remove any + * bias toward '1' or '0'. Disabling it offers a substantial + * speed advantage, but may result in a statistical distribution + * that is not perfectly uniform. + * + * @note For nRF51, on average, it take 167µs to get a byte without + * digitial error correction and 677µs with, but no garantee + * is made on the necessary time to generate one byte. + */ + uint8_t digital_error_correction:1; + /** + * @brief Only power the RNG device when requeting random bytes + * + * @details Device will not be powered when started/stopped + * but only when writint bytes. + */ + uint8_t power_on_write:1; +} RNGConfig; + + +/** + * @brief Structure representing an RNG driver. + */ +struct RNGDriver { + /** + * @brief Driver state. + */ + rngstate_t state; + /** + * @brief Current configuration data. + */ + const RNGConfig *config; +#if RNG_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the peripheral. + */ + mutex_t mutex; +#endif /* RNG_USE_MUTUAL_EXCLUSION */ + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the RNGx registers block. + */ + NRF_RNG_Type *rng; + /** + * @brief IRQ number + */ + uint32_t irq; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if NRF5_RNG_USE_RNG0 && !defined(__DOXYGEN__) +extern RNGDriver RNGD1; +#endif /* NRF5_RNG_USE_RNG0 */ + +#ifdef __cplusplus +extern "C" { +#endif + void rng_lld_init(void); + void rng_lld_start(RNGDriver *rngp); + void rng_lld_stop(RNGDriver *rngp); + msg_t rng_lld_write(RNGDriver *rngp, uint8_t *buf, size_t n, + systime_t timeout); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_RNG */ + +#endif /* HAL_RNG_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.c b/os/hal/ports/NRF5/LLD/hal_st_lld.c index 931f1a7..c78b4bb 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.c @@ -275,8 +275,8 @@ void st_lld_init(void) { NRF_TIMER0->TASKS_CLEAR = 1; /* - * Using 32-bit mode with prescaler 16 configures this - * timer with a 1MHz clock. + * Using 32-bit mode with prescaler 1/16 configures this + * timer with a 1MHz clock, reducing power consumption. */ NRF_TIMER0->BITMODE = TIMER_BITMODE_BITMODE_32Bit; NRF_TIMER0->PRESCALER = 4; diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.h b/os/hal/ports/NRF5/LLD/hal_st_lld.h index 3b4bf8e..9d67ce9 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.h @@ -15,8 +15,8 @@ */ /** - * @file st_lld.h - * @brief NRF51822 ST subsystem low level driver header. + * @file NRF5/LLD/st_lld.h + * @brief NRF5 ST subsystem low level driver header. * @details This header is designed to be include-able without having to * include other files from the HAL. * -- cgit v1.2.3 From 8feec2e235fc6f28cdcdf96bacdd842f6deeb1a5 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 12:08:54 +0200 Subject: removed useless field power_on_write --- os/hal/ports/NRF5/LLD/hal_rng_lld.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_rng_lld.h b/os/hal/ports/NRF5/LLD/hal_rng_lld.h index 9a9f471..5c56be2 100644 --- a/os/hal/ports/NRF5/LLD/hal_rng_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_rng_lld.h @@ -96,13 +96,6 @@ typedef struct { * is made on the necessary time to generate one byte. */ uint8_t digital_error_correction:1; - /** - * @brief Only power the RNG device when requeting random bytes - * - * @details Device will not be powered when started/stopped - * but only when writint bytes. - */ - uint8_t power_on_write:1; } RNGConfig; -- cgit v1.2.3 From e5da7dbd39e5686ae7ecc908c55b827d2616bd5a Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 13:31:49 +0200 Subject: use anonymous struct, fixed used og wrong vector interrupt --- os/hal/ports/NRF5/LLD/hal_wdg_lld.c | 153 ++++++++++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_wdg_lld.h | 143 +++++++++++++++++++++++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 os/hal/ports/NRF5/LLD/hal_wdg_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_wdg_lld.h (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_wdg_lld.c b/os/hal/ports/NRF5/LLD/hal_wdg_lld.c new file mode 100644 index 0000000..30d31af --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_wdg_lld.c @@ -0,0 +1,153 @@ +/* + ChibiOS - Copyright (C) 2016 Stephane D'Alu + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/hal_wdg_lld.c + * @brief NRF5 Watchdog Driver subsystem low level driver source template. + * + * @addtogroup WDG + * @{ + */ + +#include "hal.h" + +#if HAL_USE_WDG || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define RELOAD_REQUEST_VALUE 0x6E524635 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +WDGDriver WDGD1; + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if WDG_USE_TIMEOUT_CALLBACK == TRUE +/** + * @brief Watchdog vector. + * @details This interrupt is used when watchdog timeout. + * + * @note Only 2 cycles at NRF5_LFCLK_FREQUENCY are available + * to they good bye. + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector80) { + + OSAL_IRQ_PROLOGUE(); + osalSysLockFromISR(); + + /* Notify */ + if (WDGD1.config->callback) + WDGD1.config->callback(); + + /* Wait for reboot */ + while (1) { /* */ } + + osalSysUnlockFromISR(); + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level WDG driver initialization. + * + * @notapi + */ +void wdg_lld_init(void) { + WDGD1.state = WDG_STOP; + WDGD1.wdt = NRF_WDT; +} + +/** + * @brief Configures and activates the WDG peripheral. + * + * @note Once started there is no way out. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @notapi + */ +void wdg_lld_start(WDGDriver *wdgp) { +#if WDG_USE_TIMEOUT_CALLBACK == TRUE + wdgp->wdt->INTENSET = WDT_INTENSET_TIMEOUT_Msk; +#endif + + /* When to pause? (halt, sleep) */ + uint32_t config = 0; + if (!wdgp->config->pause_on_sleep) + config |= WDT_CONFIG_SLEEP_Msk; + if (!wdgp->config->pause_on_halt) + config |= WDT_CONFIG_HALT_Msk; + wdgp->wdt->CONFIG = config; + + /* Timeout in milli-seconds */ + uint64_t tout = (NRF5_LFCLK_FREQUENCY * wdgp->config->timeout_ms / 1000) - 1; + osalDbgAssert(tout <= 0xFFFFFFFF, "watchdog timout value exceeded"); + wdgp->wdt->CRV = (uint32_t)tout; + + /* Reload request (using RR0) */ + wdgp->wdt->RREN = WDT_RREN_RR0_Msk; + + /* Say your prayers, little one. */ + wdgp->wdt->TASKS_START = 1; +} + +/** + * @brief Deactivates the WDG peripheral. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @api + */ +void wdg_lld_stop(WDGDriver *wdgp) { + (void)wdgp; + osalDbgAssert(false, "WDG cannot be stopped once activated"); +} + +/** + * @brief Reloads WDG's counter. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @notapi + */ +void wdg_lld_reset(WDGDriver * wdgp) { + wdgp->wdt->RR[0] = RELOAD_REQUEST_VALUE; +} + +#endif /* HAL_USE_WDG */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_wdg_lld.h b/os/hal/ports/NRF5/LLD/hal_wdg_lld.h new file mode 100644 index 0000000..109b67e --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_wdg_lld.h @@ -0,0 +1,143 @@ +/* + ChibiOS - Copyright (C) 2016 Stephane D'Alu + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/hal_wdg_lld.h + * @brief NRF5 Watchdog Driver subsystem low level driver header template. + * + * @addtogroup WDG + * @{ + */ + +#ifndef HAL_WDG_LLD_H +#define HAL_WDG_LLD_H + +#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define WDG_MAX_TIMEOUT_MS \ + ((uint32_t)(0xFFFFFFFFu * 1000 / NRF5_LFCLK_FREQUENCY)) + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ + +/** + * @brief WDG driver implement timeout callback. + * @note The default is @p FALSE. + */ +#if !defined(WDG_USE_TIMEOUT_CALLBACK) || defined(__DOXYGEN__) +#define WDG_USE_TIMEOUT_CALLBACK FALSE +#endif +/** @} */ + + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an WDG driver. + */ +typedef struct WDGDriver WDGDriver; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + struct { + /** + * @brief Pause watchdog while the CPU is sleeping + */ + uint8_t pause_on_sleep : 1; + /** + * @brief Pause watchdog while the CPU is halted by the debugger + */ + uint8_t pause_on_halt : 1; + }; + /** + * + */ + uint32_t timeout_ms; +#if WDG_USE_TIMEOUT_CALLBACK == TRUE + /** + * @brief Notification callback when watchdog timedout + * + * @note About 2 cycles at NRF5_LFCLK_FREQUENCY are available + * before automatic reboot. + * + */ + void (*callback)(void); +#endif +} WDGConfig; + + + +/** + * @brief Structure representing an WDG driver. + */ +struct WDGDriver { + /** + * @brief Driver state. + */ + wdgstate_t state; + /** + * @brief Current configuration data. + */ + const WDGConfig *config; + /* End of the mandatory fields.*/ + NRF_WDT_Type *wdt; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern WDGDriver WDGD1; + +#ifdef __cplusplus +extern "C" { +#endif + void wdg_lld_init(void); + void wdg_lld_start(WDGDriver *wdgp); + void wdg_lld_stop(WDGDriver *wdgp); + void wdg_lld_reset(WDGDriver *wdgp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_WDG == TRUE */ + +#endif /* HAL_WDG_LLD_H */ + +/** @} */ -- cgit v1.2.3 From 49afe683a0827a9b29c7e2e761f6740b67543056 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 14:10:58 +0200 Subject: assert that watchdog can't be restarted --- os/hal/ports/NRF5/LLD/hal_wdg_lld.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_wdg_lld.c b/os/hal/ports/NRF5/LLD/hal_wdg_lld.c index 30d31af..35c079f 100644 --- a/os/hal/ports/NRF5/LLD/hal_wdg_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_wdg_lld.c @@ -101,6 +101,10 @@ void wdg_lld_init(void) { * @notapi */ void wdg_lld_start(WDGDriver *wdgp) { + osalDbgAssert((wdgp->state == WDG_STOP), + "This WDG driver cannot be restarted once activated"); + + /* Generate interrupt on timeout */ #if WDG_USE_TIMEOUT_CALLBACK == TRUE wdgp->wdt->INTENSET = WDT_INTENSET_TIMEOUT_Msk; #endif @@ -134,7 +138,7 @@ void wdg_lld_start(WDGDriver *wdgp) { */ void wdg_lld_stop(WDGDriver *wdgp) { (void)wdgp; - osalDbgAssert(false, "WDG cannot be stopped once activated"); + osalDbgAssert(false, "This WDG driver cannot be stopped once activated"); } /** -- cgit v1.2.3 From 5d1b4d1d776f4e32b5f238a977172800417727bf Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 19:13:29 +0200 Subject: Use OUT instead of IN to when toggling pad --- os/hal/ports/NRF5/LLD/hal_pal_lld.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_pal_lld.h b/os/hal/ports/NRF5/LLD/hal_pal_lld.h index 9eb333d..34caa7e 100644 --- a/os/hal/ports/NRF5/LLD/hal_pal_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_pal_lld.h @@ -305,7 +305,7 @@ typedef NRF_GPIO_Type *ioportid_t; */ #define pal_lld_togglepad(port, pad) \ do { \ - uint8_t bit = (IOPORT1->IN >> (pad)) & 1; \ + uint8_t bit = (IOPORT1->OUT >> (pad)) & 1; \ if (bit) \ IOPORT1->OUTCLR = 1 << (pad); \ else \ -- cgit v1.2.3 From 321ec844af3b1e7a23c94bce65bc8aa13ef1e09e Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 19:15:46 +0200 Subject: moved GPT to LLD --- os/hal/ports/NRF5/LLD/hal_gpt_lld.c | 359 ++++++++++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_gpt_lld.h | 264 ++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_st_lld.h | 1 + 3 files changed, 624 insertions(+) create mode 100644 os/hal/ports/NRF5/LLD/hal_gpt_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_gpt_lld.h (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_gpt_lld.c b/os/hal/ports/NRF5/LLD/hal_gpt_lld.c new file mode 100644 index 0000000..e850e31 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_gpt_lld.c @@ -0,0 +1,359 @@ +/* + ChibiOS - 2015 Stephen Caudle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/hal_gpt_lld.c + * @brief NRF5 GPT subsystem low level driver source. + * + * @addtogroup GPT + * @{ + */ + +#include "hal.h" + +#if HAL_USE_GPT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define NRF5_TIMER_PRESCALER_NUM 10 +#define NRF5_TIMER_COMPARE_NUM 4 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief GPTD1 driver identifier. + * @note The driver GPTD1 allocates the complex timer TIM1 when enabled. + */ +#if NRF5_GPT_USE_TIMER0 || defined(__DOXYGEN__) +GPTDriver GPTD1; +#endif + +/** + * @brief GPTD2 driver identifier. + * @note The driver GPTD2 allocates the timer TIM2 when enabled. + */ +#if NRF5_GPT_USE_TIMER1 || defined(__DOXYGEN__) +GPTDriver GPTD2; +#endif + +/** + * @brief GPTD3 driver identifier. + * @note The driver GPTD3 allocates the timer TIM3 when enabled. + */ +#if NRF5_GPT_USE_TIMER2 || defined(__DOXYGEN__) +GPTDriver GPTD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static uint8_t prescaler(uint16_t freq) +{ + uint8_t i; + static const gptfreq_t frequencies[] = { + NRF5_GPT_FREQ_16MHZ, + NRF5_GPT_FREQ_8MHZ, + NRF5_GPT_FREQ_4MHZ, + NRF5_GPT_FREQ_2MHZ, + NRF5_GPT_FREQ_1MHZ, + NRF5_GPT_FREQ_500KHZ, + NRF5_GPT_FREQ_250KHZ, + NRF5_GPT_FREQ_125KHZ, + NRF5_GPT_FREQ_62500HZ, + NRF5_GPT_FREQ_31250HZ, + }; + + for (i = 0; i < NRF5_TIMER_PRESCALER_NUM; i++) + if (freq == frequencies[i]) + return i; + + osalDbgAssert(FALSE, "invalid timer frequency"); + + return 0; +} + +/** + * @brief Shared IRQ handler. + * + * @param[in] gptp pointer to a @p GPTDriver object + */ +static void gpt_lld_serve_interrupt(GPTDriver *gptp) { + + gptp->tim->EVENTS_COMPARE[gptp->cc_int] = 0; + (void)gptp->tim->EVENTS_COMPARE[gptp->cc_int]; + if (gptp->state == GPT_ONESHOT) + gptp->state = GPT_READY; /* Back in GPT_READY state. */ + gptp->config->callback(gptp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if NRF5_GPT_USE_TIMER0 +/** + * @brief TIMER0 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector60) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* NRF5_GPT_USE_TIMER0 */ + +#if NRF5_GPT_USE_TIMER1 +/** + * @brief TIMER1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector64) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* NRF5_GPT_USE_TIMER1 */ + +#if NRF5_GPT_USE_TIMER2 +/** + * @brief TIMER2 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector68) { + + OSAL_IRQ_PROLOGUE(); + + gpt_lld_serve_interrupt(&GPTD3); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* NRF5_GPT_USE_TIMER2 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level GPT driver initialization. + * + * @notapi + */ +void gpt_lld_init(void) { + +#if NRF5_GPT_USE_TIMER0 + /* Driver initialization.*/ + GPTD1.tim = NRF_TIMER0; + gptObjectInit(&GPTD1); +#endif + +#if NRF5_GPT_USE_TIMER1 + /* Driver initialization.*/ + GPTD2.tim = NRF_TIMER1; + gptObjectInit(&GPTD2); +#endif + +#if NRF5_GPT_USE_TIMER2 + /* Driver initialization.*/ + GPTD3.tim = NRF_TIMER2; + gptObjectInit(&GPTD3); +#endif +} + +/** + * @brief Configures and activates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_start(GPTDriver *gptp) { + + NRF_TIMER_Type *tim = gptp->tim; + + if (gptp->state == GPT_STOP) { + osalDbgAssert(gptp->cc_int < NRF5_TIMER_COMPARE_NUM, + "invalid capture/compare index"); + + tim->INTENSET = TIMER_INTENSET_COMPARE0_Msk << gptp->cc_int; +#if NRF5_GPT_USE_TIMER0 + if (&GPTD1 == gptp) + nvicEnableVector(TIMER0_IRQn, NRF5_GPT_TIMER0_IRQ_PRIORITY); +#endif +#if NRF5_GPT_USE_TIMER1 + if (&GPTD2 == gptp) + nvicEnableVector(TIMER1_IRQn, NRF5_GPT_TIMER1_IRQ_PRIORITY); +#endif +#if NRF5_GPT_USE_TIMER2 + if (&GPTD3 == gptp) + nvicEnableVector(TIMER2_IRQn, NRF5_GPT_TIMER2_IRQ_PRIORITY); +#endif + } + + /* Prescaler value calculation.*/ + tim->PRESCALER = prescaler(gptp->config->frequency); + + /* Timer configuration.*/ + tim->MODE = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos; + + switch (gptp->config->resolution) { + + case 8: + tim->BITMODE = TIMER_BITMODE_BITMODE_08Bit << TIMER_BITMODE_BITMODE_Pos; + break; + + case 16: + tim->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos; + break; + +#if NRF5_GPT_USE_TIMER0 + case 24: + tim->BITMODE = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos; + break; + + case 32: + tim->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos; + break; +#endif + + default: + osalDbgAssert(FALSE, "invalid timer resolution"); + break; + }; +} + +/** + * @brief Deactivates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop(GPTDriver *gptp) { + + if (gptp->state == GPT_READY) { + gptp->tim->TASKS_SHUTDOWN = 1; + +#if NRF5_GPT_USE_TIMER0 + if (&GPTD1 == gptp) + nvicDisableVector(TIMER0_IRQn); +#endif +#if NRF5_GPT_USE_TIMER1 + if (&GPTD2 == gptp) + nvicDisableVector(TIMER1_IRQn); +#endif +#if NRF5_GPT_USE_TIMER2 + if (&GPTD3 == gptp) + nvicDisableVector(TIMER2_IRQn); +#endif + gptp->tim->INTENCLR = TIMER_INTENSET_COMPARE0_Msk << gptp->cc_int; + } +} + +/** + * @brief Starts the timer in continuous mode. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval period in ticks + * + * @notapi + */ +void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) { + + NRF_TIMER_Type *tim = gptp->tim; + + tim->TASKS_CLEAR = 1; + tim->CC[gptp->cc_int] = (uint32_t)(interval - 1); /* Time constant. */ + if (gptp->state == GPT_ONESHOT) + gptp->tim->SHORTS = TIMER_SHORTS_COMPARE0_STOP_Msk << gptp->cc_int; + else if (gptp->state == GPT_CONTINUOUS) + gptp->tim->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk << gptp->cc_int; + tim->TASKS_START = 1; +} + +/** + * @brief Stops the timer. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop_timer(GPTDriver *gptp) { + + gptp->tim->TASKS_STOP = 1; +} + +/** + * @brief Starts the timer in one shot mode and waits for completion. + * @details This function specifically polls the timer waiting for completion + * in order to not have extra delays caused by interrupt servicing, + * this function is only recommended for short delays. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval time interval in ticks + * + * @notapi + */ +void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) { + + NRF_TIMER_Type *tim = gptp->tim; + + tim->INTENCLR = (1UL << gptp->cc_int) << TIMER_INTENSET_COMPARE0_Pos; + tim->TASKS_CLEAR = 1; + tim->CC[gptp->cc_int] = (uint32_t)(interval - 1); /* Time constant. */ + tim->TASKS_START = 1; + while (!(tim->INTENSET & (TIMER_INTENSET_COMPARE0_Msk << gptp->cc_int))) + ; + tim->INTENSET = TIMER_INTENSET_COMPARE0_Msk << gptp->cc_int; +} + +/** + * @brief Returns the counter value of GPT peripheral. + * @pre The GPT unit must be running in continuous mode. + * @note The nature of the counter is not defined, it may count upward + * or downward, it could be continuously running or not. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @return The current counter value. + * + * @notapi + */ +gptcnt_t gpt_lld_get_counter(GPTDriver *gptp) { + + gptp->tim->TASKS_CAPTURE[gptp->cc_get] = 1; + return gptp->tim->CC[gptp->cc_get]; +} + +#endif /* HAL_USE_GPT */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_gpt_lld.h b/os/hal/ports/NRF5/LLD/hal_gpt_lld.h new file mode 100644 index 0000000..4173a3a --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_gpt_lld.h @@ -0,0 +1,264 @@ +/* + Copyright (C) 2015 Stephen Caudle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/gpt_lld.h + * @brief NRF5 GPT subsystem low level driver header. + * + * @addtogroup GPT + * @{ + */ + +#ifndef HAL_GPT_LLD_H +#define HAL_GPT_LLD_H + +#if HAL_USE_GPT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief GPTD1 driver enable switch. + * @details If set to @p TRUE the support for GPTD1 is included. + * @note The default is @p TRUE. + */ +#if !defined(NRF5_GPT_USE_TIMER0) || defined(__DOXYGEN__) +#define NRF5_GPT_USE_TIMER0 FALSE +#endif + +/** + * @brief GPTD2 driver enable switch. + * @details If set to @p TRUE the support for GPTD2 is included. + * @note The default is @p TRUE. + */ +#if !defined(NRF5_GPT_USE_TIMER1) || defined(__DOXYGEN__) +#define NRF5_GPT_USE_TIMER1 FALSE +#endif + +/** + * @brief GPTD3 driver enable switch. + * @details If set to @p TRUE the support for GPTD3 is included. + * @note The default is @p TRUE. + */ +#if !defined(NRF5_GPT_USE_TIMER2) || defined(__DOXYGEN__) +#define NRF5_GPT_USE_TIMER2 FALSE +#endif + +/** + * @brief GPTD1 interrupt priority level setting. + */ +#if !defined(NRF5_GPT_TIMER0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_GPT_TIMER0_IRQ_PRIORITY 3 +#endif + +/** + * @brief GPTD2 interrupt priority level setting. + */ +#if !defined(NRF5_GPT_TIMER1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_GPT_TIMER1_IRQ_PRIORITY 3 +#endif + +/** + * @brief GPTD3 interrupt priority level setting. + */ +#if !defined(NRF5_GPT_TIMER2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_GPT_TIMER2_IRQ_PRIORITY 3 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !NRF5_GPT_USE_TIMER0 && !NRF5_GPT_USE_TIMER1 && \ + !NRF5_GPT_USE_TIMER2 +#error "GPT driver activated but no TIMER peripheral assigned" +#endif + +#if NRF5_GPT_USE_TIMER0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_GPT_TIMER0_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIMER0" +#endif + +#if NRF5_GPT_USE_TIMER1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_GPT_TIMER1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIMER1" +#endif + +#if NRF5_GPT_USE_TIMER2 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_GPT_TIMER2_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to TIMER2" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief GPT frequency type. + */ +typedef enum { + NRF5_GPT_FREQ_31250HZ = 31250, + NRF5_GPT_FREQ_62500HZ = 62500, + NRF5_GPT_FREQ_125KHZ = 125000, + NRF5_GPT_FREQ_250KHZ = 250000, + NRF5_GPT_FREQ_500KHZ = 500000, + NRF5_GPT_FREQ_1MHZ = 1000000, + NRF5_GPT_FREQ_2MHZ = 2000000, + NRF5_GPT_FREQ_4MHZ = 4000000, + NRF5_GPT_FREQ_8MHZ = 8000000, + NRF5_GPT_FREQ_16MHZ = 16000000, +} gptfreq_t; + +/** + * @brief GPT counter type. + */ +typedef uint32_t gptcnt_t; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + gptfreq_t frequency; + /** + * @brief Timer callback pointer. + * @note This callback is invoked on GPT counter events. + * @note This callback can be set to @p NULL but in that case the + * one-shot mode cannot be used. + */ + gptcallback_t callback; + /* End of the mandatory fields.*/ + /** + * @brief The timer resolution in bits (8/16/24/32) + * @note The default value of this field is 16 bits + * @note The 24 and 32 bit modes are only valid for TIMER0 + */ + uint8_t resolution; +} GPTConfig; + +/** + * @brief Structure representing a GPT driver. + */ +struct GPTDriver { + /** + * @brief Driver state. + */ + gptstate_t state; + /** + * @brief Current configuration data. + */ + const GPTConfig *config; +#if defined(GPT_DRIVER_EXT_FIELDS) + GPT_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the TIMERx registers block. + */ + NRF_TIMER_Type *tim; + /** + * @brief Index of the TIMERx capture/compare register used for setting the + * interval between compare events. + */ + uint8_t cc_int; + /** + * @brief Index of the TIMERx capture/compare register used for getting the + * current timer counter value. + */ + uint8_t cc_get; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Changes the interval of GPT peripheral. + * @details This function changes the interval of a running GPT unit. + * @pre The GPT unit must be running in continuous mode. + * @post The GPT unit interval is changed to the new value. + * @note The function has effect at the next cycle start. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @param[in] interval new cycle time in timer ticks + * + * @notapi + */ +#define gpt_lld_change_interval(gptp, interval) \ + ((gptp)->tim->CC[(gptp)->cc_int] = (uint32_t)((interval) - 1)) + +/** + * @brief Returns the interval of GPT peripheral. + * @pre The GPT unit must be running in continuous mode. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @return The current interval. + * + * @notapi + */ +#define gpt_lld_get_interval(gptp) \ + ((gptcnt_t)((gptp)->tim->CC[(gptp)->cc_int]) + 1) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if NRF5_GPT_USE_TIMER0 && !defined(__DOXYGEN__) +extern GPTDriver GPTD1; +#endif + +#if NRF5_GPT_USE_TIMER1 && !defined(__DOXYGEN__) +extern GPTDriver GPTD2; +#endif + +#if NRF5_GPT_USE_TIMER2 && !defined(__DOXYGEN__) +extern GPTDriver GPTD3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void gpt_lld_init(void); + void gpt_lld_start(GPTDriver *gptp); + void gpt_lld_stop(GPTDriver *gptp); + void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period); + void gpt_lld_stop_timer(GPTDriver *gptp); + void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval); + gptcnt_t gpt_lld_get_counter(GPTDriver *gptp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_GPT */ + +#endif /* HAL_GPT_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.h b/os/hal/ports/NRF5/LLD/hal_st_lld.h index 9d67ce9..7073e12 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.h @@ -124,6 +124,7 @@ #error "Invalid IRQ priority assigned to ST driver" #endif + /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/ -- cgit v1.2.3 From 52107b2ccbf1b5ed29123d77d5cd3bc982fdee2e Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 21:46:46 +0200 Subject: moved QEI to LLD --- os/hal/ports/NRF5/LLD/hal_pal_lld.h | 4 +- os/hal/ports/NRF5/LLD/hal_qei_lld.c | 284 ++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_qei_lld.h | 390 ++++++++++++++++++++++++++++++++++++ 3 files changed, 675 insertions(+), 3 deletions(-) create mode 100644 os/hal/ports/NRF5/LLD/hal_qei_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_qei_lld.h (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_pal_lld.h b/os/hal/ports/NRF5/LLD/hal_pal_lld.h index 34caa7e..745afd3 100644 --- a/os/hal/ports/NRF5/LLD/hal_pal_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_pal_lld.h @@ -130,10 +130,8 @@ typedef NRF_GPIO_Type *ioportid_t; */ #if NRF_SERIES == 51 #define IOPORT1 NRF_GPIO -#elif NRF_SERIES == 52 -#define IOPORT1 NRF_P0 #else -#error "Unknown NRF_SERIES" +#define IOPORT1 NRF_P0 #endif /*===========================================================================*/ diff --git a/os/hal/ports/NRF5/LLD/hal_qei_lld.c b/os/hal/ports/NRF5/LLD/hal_qei_lld.c new file mode 100644 index 0000000..9044897 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_qei_lld.c @@ -0,0 +1,284 @@ +/* + ChibiOS - Copyright (C) 2016..2016 Stéphane D'Alu + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF51/hal_qei_lld.c + * @brief NRF51 QEI subsystem low level driver. + * + * @addtogroup QEI + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) + + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief QEID1 driver identifier. + */ +#if NRF5_QEI_USE_QDEC0 || defined(__DOXYGEN__) +QEIDriver QEID1; +#endif + + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Common IRQ handler. + * + * @param[in] qeip pointer to an QEIDriver + */ +static void serve_interrupt(QEIDriver *qeip) { + NRF_QDEC_Type *qdec = qeip->qdec; + +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + /* Accumulator overflowed + */ + if (qdec->EVENTS_ACCOF) { + qdec->EVENTS_ACCOF = 0; + + qeip->overflowed++; + if (qeip->config->overflowed_cb) + qeip->config->overflowed_cb(qeip); + } +#endif + + /* Report ready + */ + if (qdec->EVENTS_REPORTRDY) { + qdec->EVENTS_REPORTRDY = 0; + + /* Read (and clear counters due to shortcut) */ + int16_t acc = ( int16_t)qdec->ACCREAD; + uint16_t accdbl = (uint16_t)qdec->ACCDBLREAD; + + /* Inverse direction if requested */ + if (qeip->config->dirinv) + acc = -acc; // acc is [-1024..+1023], its okay on int16_t + + /* Adjust counter */ + qeiAdjustI(qeip, acc); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if NRF5_QEI_USE_QDEC0 == TRUE +/** + * @brief Quadrature decoder vector (QDEC) + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector88) { + + OSAL_IRQ_PROLOGUE(); + serve_interrupt(&QEID1); + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level QEI driver initialization. + * + * @notapi + */ +void qei_lld_init(void) { + +#if NRF5_QEI_USE_QDEC0 == TRUE + /* Driver initialization.*/ + qeiObjectInit(&QEID1); + QEID1.qdec = NRF_QDEC; +#endif +} + +/** + * @brief Configures and activates the QEI peripheral. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_start(QEIDriver *qeip) { + NRF_QDEC_Type *qdec = qeip->qdec; + const QEIConfig *cfg = qeip->config; + + if (qeip->state == QEI_STOP) { + /* Set Pins */ + palSetLineMode(cfg->phase_a, PAL_MODE_INPUT); + palSetLineMode(cfg->phase_b, PAL_MODE_INPUT); +#if NRF5_QEI_USE_LED == TRUE + if (cfg->led != PAL_NOLINE) { + palSetLineMode(cfg->led, PAL_MODE_INPUT); + } +#endif + + /* Set interrupt masks and enable interrupt */ +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk | + QDEC_INTENSET_ACCOF_Msk; +#else + qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk; +#endif +#if NRF5_QEI_USE_QDEC0 == TRUE + if (&QEID1 == qeip) { + nvicEnableVector(QDEC_IRQn, NRF5_QEI_QDEC0_IRQ_PRIORITY); + } +#endif + + /* Select pin for Phase A and Phase B */ +#if NRF_SERIES == 51 + qdec->PSELA = PAL_PAD(cfg->phase_a); + qdec->PSELB = PAL_PAD(cfg->phase_b); +#else + qdec->PSEL.A = PAL_PAD(cfg->phase_a); + qdec->PSEL.B = PAL_PAD(cfg->phase_b); +#endif + /* Select (optional) pin for LED, and configure it */ +#if NRF5_QEI_USE_LED == TRUE +#if NRF_SERIES == 51 + qdec->PSELLED = PAL_PAD(cfg->led); +#else + qdec->PSEL.LED = PAL_PAD(cfg->led); +#endif + qdec->LEDPOL = ((cfg->led_polarity == QEI_LED_POLARITY_LOW) + ? QDEC_LEDPOL_LEDPOL_ActiveLow + : QDEC_LEDPOL_LEDPOL_ActiveHigh) + << QDEC_LEDPOL_LEDPOL_Pos; + qdec->LEDPRE = cfg->led_warming; +#else +#if NRF_SERIES == 51 + qdec->PSELLED = (uint32_t)-1; +#else + qdec->PSEL.LED = (uint32_t)-1; +#endif +#endif + + /* Set sampling resolution and debouncing */ + qdec->SAMPLEPER = cfg->resolution; + qdec->DBFEN = (cfg->debouncing ? QDEC_DBFEN_DBFEN_Enabled + : QDEC_DBFEN_DBFEN_Disabled) + << QDEC_DBFEN_DBFEN_Pos; + + /* Define minimum sampling before reporting + and create shortcut to clear accumulation */ + qdec->REPORTPER = cfg->report; + qdec->SHORTS = QDEC_SHORTS_REPORTRDY_READCLRACC_Msk; + + /* Enable peripheric */ + qdec->ENABLE = 1; + } + + /* Initially state is stopped, events cleared */ + qdec->TASKS_STOP = 1; + qdec->EVENTS_SAMPLERDY = 0; + qdec->EVENTS_REPORTRDY = 0; + qdec->EVENTS_ACCOF = 0; +} + +/** + * @brief Deactivates the QEI peripheral. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_stop(QEIDriver *qeip) { + + NRF_QDEC_Type *qdec = qeip->qdec; + const QEIConfig *cfg = qeip->config; + + if (qeip->state == QEI_READY) { + qdec->TASKS_STOP = 1; + qdec->ENABLE = 0; + + /* Unset interrupt masks and disable interrupt */ +#if NRF5_QEI_USE_QDEC0 == TRUE + if (&QEID1 == qeip) { + nvicDisableVector(QDEC_IRQn); + } +#endif +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + qdec->INTENCLR = QDEC_INTENCLR_REPORTRDY_Msk | + QDEC_INTENCLR_ACCOF_Msk; +#else + qdec->INTENCLR = QDEC_INTENCLR_REPORTRDY_Msk; +#endif + + /* Return pins to reset state */ + palSetLineMode(cfg->phase_a, PAL_MODE_RESET); + palSetLineMode(cfg->phase_b, PAL_MODE_RESET); +#if NRF5_QEI_USE_LED == TRUE + if (cfg->led != PAL_NOLINE) { + palSetLineMode(cfg->led, PAL_MODE_RESET); + } +#endif + } +} + +/** + * @brief Enables the input capture. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_enable(QEIDriver *qeip) { +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + qeip->overflowed = 0; +#endif + + qeip->qdec->EVENTS_SAMPLERDY = 0; + qeip->qdec->EVENTS_REPORTRDY = 0; + qeip->qdec->EVENTS_ACCOF = 0; + qeip->qdec->TASKS_START = 1; +} + +/** + * @brief Disables the input capture. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_disable(QEIDriver *qeip) { + qeip->qdec->TASKS_STOP = 1; +} + + +#endif /* HAL_USE_QEI */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_qei_lld.h b/os/hal/ports/NRF5/LLD/hal_qei_lld.h new file mode 100644 index 0000000..6328bab --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_qei_lld.h @@ -0,0 +1,390 @@ +/* + ChibiOS - Copyright (C) 2016..2016 Stéphane D'Alu + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF51/hal_qei_lld.h + * @brief NRF51 QEI subsystem low level driver header. + * + * @note Not tested with LED pin + * + * @note Pins are configured as input with no pull. + * + * @addtogroup QEI + * @{ + */ + +#ifndef HAL_QEI_LLD_H +#define HAL_QEI_LLD_H + +#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief For LED active on LOW + */ +#define QEI_LED_POLARITY_LOW 0 + +/** + * @brief For LED active on HIGH + */ +#define QEI_LED_POLARITY_HIGH 1 + +/** + * @brief Mininum usable value for defining counter underflow + */ +#define QEI_COUNT_MIN (-2147483648) + +/** + * @brief Maximum usable value for defining counter overflow + */ +#define QEI_COUNT_MAX ( 2147483647) + + + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LED control enable switch. + * @details If set to @p TRUE the support for LED control + * is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_QEI_USE_LED) || defined(__DOXYGEN__) +#define NRF5_QEI_USE_LED FALSE +#endif + +/** + * @brief Accumulator overflow notification enable switch. + * @details If set to @p TRUE the support for accumulator overflow + * is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_QEI_USE_ACC_OVERFLOWED_CB) || defined(__DOXYGEN__) +#define NRF5_QEI_USE_ACC_OVERFLOWED_CB FALSE +#endif + +/** + * @brief QEID1 driver enable switch. + * @details If set to @p TRUE the support for QEID1 is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_QEI_USE_QDEC0) || defined(__DOXYGEN__) +#define NRF5_QEI_USE_QDEC0 FALSE +#endif + +/** + * @brief QEID interrupt priority level setting for QDEC0. + */ +#if !defined(NRF5_QEI_QDEC0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_QEI_QDEC0_IRQ_PRIORITY 2 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if NRF5_QEI_USE_QDEC0 == FALSE +#error "Requesting QEI driver, but no QDEC peripheric attached" +#endif + +#if NRF5_QEI_USE_QDEC0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_QEI_QDEC0_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to QDEC0" +#endif + + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief QEI count mode. + */ +typedef enum { + QEI_MODE_QUADRATURE = 0, /**< Quadrature encoder mode. */ +} qeimode_t; + +/** + * @brief QEI resolution. + */ +typedef enum { + QEI_RESOLUTION_128us = 0x00UL, /**< 128us sample period. */ + QEI_RESOLUTION_256us = 0x01UL, /**< 256us sample period. */ + QEI_RESOLUTION_512us = 0x02UL, /**< 512us sample period. */ + QEI_RESOLUTION_1024us = 0x03UL, /**< 1024us sample period. */ + QEI_RESOLUTION_2048us = 0x04UL, /**< 2048us sample period. */ + QEI_RESOLUTION_4096us = 0x05UL, /**< 4096us sample period. */ + QEI_RESOLUTION_8192us = 0x06UL, /**< 8192us sample period. */ + QEI_RESOLUTION_16384us = 0x07UL, /**< 16384us sample period. */ +} qeiresolution_t; + +/** + * @brief Clusters of samples. + */ +typedef enum { + QEI_REPORT_10 = 0x00UL, /**< 10 samples per report. */ + QEI_REPORT_40 = 0x01UL, /**< 40 samples per report. */ + QEI_REPORT_80 = 0x02UL, /**< 80 samples per report. */ + QEI_REPORT_120 = 0x03UL, /**< 120 samples per report. */ + QEI_REPORT_160 = 0x04UL, /**< 160 samples per report. */ + QEI_REPORT_200 = 0x05UL, /**< 200 samples per report. */ + QEI_REPORT_240 = 0x06UL, /**< 240 samples per report. */ + QEI_REPORT_280 = 0x07UL, /**< 280 samples per report. */ +} qeireport_t; + +/** + * @brief QEI direction inversion. + */ +typedef enum { + QEI_DIRINV_FALSE = 0, /**< Do not invert counter direction. */ + QEI_DIRINV_TRUE = 1, /**< Invert counter direction. */ +} qeidirinv_t; + +/** + * @brief QEI counter type. + */ +typedef int32_t qeicnt_t; + +/** + * @brief QEI delta type. + */ +typedef int16_t qeidelta_t; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Count mode. + */ + qeimode_t mode; + /** + * @brief Resolution. + */ + qeiresolution_t resolution; + /** + * @brief Direction inversion. + */ + qeidirinv_t dirinv; + /** + * @brief Handling of counter overflow/underflow + * + * @details When overflow occurs, the counter value is updated + * according to: + * - QEI_OVERFLOW_DISCARD: + * discard the update value, counter doesn't change + * - QEI_OVERFLOW_MINMAX + * counter will be updated to reach min or max + * - QEI_OVERFLOW_WRAP: + * counter value will wrap around + */ + qeioverflow_t overflow; + /** + * @brief Min count value. + * + * @note If min == max, then QEI_COUNT_MIN is used. + */ + qeicnt_t min; + /** + * @brief Max count value. + * + * @note If min == max, then QEI_COUNT_MAX is used. + */ + qeicnt_t max; + /** + * @brief Notify of value change + * + * @note Called from ISR context. + */ + qeicallback_t notify_cb; + /** + * @brief Notify of overflow + * + * @note Overflow notification is performed after + * value changed notification. + * @note Called from ISR context. + */ + void (*overflow_cb)(QEIDriver *qeip, qeidelta_t delta); + /* End of the mandatory fields.*/ + /** + * @brief Line for reading Phase A + */ + ioline_t phase_a; + /** + * @brief Line for reading Phase B + */ + ioline_t phase_b; +#if (NRF5_QEI_USE_LED == TRUE) || defined(__DOXYGEN__) + /** + * @brief Line used to control LED + * + * @note If LED is not controlled by MCU, you need to use the + * PAL_NOLINE value. + */ + ioline_t led; + /** + * @brief Period in µs the LED is switched on prior to sampling. + * + * @details LED warming is expressed in micro-seconds and value + * is [0..511] + * + * @note 31µs is the recommanded default. + * + * @note If debouncing is activated, LED is always on for the + * whole sampling period (aka: resolution) + */ + uint16_t led_warming; + /** + * @brief LED polarity to used (when LED is controlled by MCU) + */ + uint8_t led_polarity; +#endif + /** + * @brief Activate debouncing filter + * + * @note If LED is controlled by MCU, the led_warming is ignored and, + * LED is always on for the whole sampling period (aka: resolution) + */ + bool debouncing; + /** + * @brief Number of samples per report + * + * @details Default to QEI_REPORT_10 + */ + qeireport_t report; +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + /** + * @brief Notify of internal accumulator overflowed + * (ie: MCU discarding samples) + * + * @note Called from ISR context. + */ + qeicallback_t overflowed_cb; +#endif +} QEIConfig; + +/** + * @brief Structure representing an QEI driver. + */ +struct QEIDriver { + /** + * @brief Driver state. + */ + qeistate_t state; + /** + * @brief Last count value. + */ + qeicnt_t last; + /** + * @brief Current configuration data. + */ + const QEIConfig *config; +#if defined(QEI_DRIVER_EXT_FIELDS) + QEI_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Counter + */ + qeicnt_t count; +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + /** + * @brief Number of time the MCU discarded updates due to + * accumulator overflow + */ + uint32_t overflowed; +#endif + /** + * @brief Pointer to the QDECx registers block. + */ + NRF_QDEC_Type *qdec; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the counter value. + * + * @param[in] qeip pointer to the @p QEIDriver object + * @return The current counter value. + * + * @notapi + */ +#define qei_lld_get_count(qeip) ((qeip)->count) + + +/** + * @brief Set the counter value. + * + * @param[in] qeip pointer to the @p QEIDriver object + * @param[in] value counter value + * + * @notapi + */ +#define qei_lld_set_count(qeip, value) \ + if ((qeip)->count != ((qeicnt_t)value)) { \ + (qeip)->count = value; \ + if ((qeip)->config->notify_cb) \ + (qeip)->config->notify_cb(qeip); \ + } while(0) + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if NRF5_QEI_USE_QDEC0 && !defined(__DOXYGEN__) +extern QEIDriver QEID1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void qei_lld_init(void); + void qei_lld_start(QEIDriver *qeip); + void qei_lld_stop(QEIDriver *qeip); + void qei_lld_enable(QEIDriver *qeip); + void qei_lld_disable(QEIDriver *qeip); + qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* To be moved in hal_qei */ +/*===========================================================================*/ + +void qeiSetCount(QEIDriver *qeip, qeicnt_t value); +qeidelta_t qeiAdjust(QEIDriver *qeip, qeidelta_t delta); + +#endif /* HAL_USE_QEI */ + +#endif /* HAL_QEI_LLD_H */ + +/** @} */ -- cgit v1.2.3 From 539338100fffb76e152be37228c4040fa072ba92 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Mon, 11 Jul 2016 22:11:27 +0200 Subject: deal with write buffer --- os/hal/ports/NRF5/LLD/hal_gpt_lld.c | 2 ++ os/hal/ports/NRF5/LLD/hal_qei_lld.c | 20 +++++++++++++++++-- os/hal/ports/NRF5/LLD/hal_rng_lld.c | 10 ++++++++-- os/hal/ports/NRF5/LLD/hal_serial_lld.c | 16 +++++++++++---- os/hal/ports/NRF5/LLD/hal_st_lld.c | 36 +++++++++++++++++++++++++++++----- os/hal/ports/NRF5/LLD/hal_st_lld.h | 12 ++++++++++++ 6 files changed, 83 insertions(+), 13 deletions(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_gpt_lld.c b/os/hal/ports/NRF5/LLD/hal_gpt_lld.c index e850e31..20dbcef 100644 --- a/os/hal/ports/NRF5/LLD/hal_gpt_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_gpt_lld.c @@ -102,7 +102,9 @@ static uint8_t prescaler(uint16_t freq) static void gpt_lld_serve_interrupt(GPTDriver *gptp) { gptp->tim->EVENTS_COMPARE[gptp->cc_int] = 0; +#if CORTEX_MODEL >= 4 (void)gptp->tim->EVENTS_COMPARE[gptp->cc_int]; +#endif if (gptp->state == GPT_ONESHOT) gptp->state = GPT_READY; /* Back in GPT_READY state. */ gptp->config->callback(gptp); diff --git a/os/hal/ports/NRF5/LLD/hal_qei_lld.c b/os/hal/ports/NRF5/LLD/hal_qei_lld.c index 9044897..d3b99cd 100644 --- a/os/hal/ports/NRF5/LLD/hal_qei_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_qei_lld.c @@ -64,7 +64,10 @@ static void serve_interrupt(QEIDriver *qeip) { */ if (qdec->EVENTS_ACCOF) { qdec->EVENTS_ACCOF = 0; - +#if CORTEX_MODEL >= 4 + (void)qdec->EVENTS_ACCOF; +#endif + qeip->overflowed++; if (qeip->config->overflowed_cb) qeip->config->overflowed_cb(qeip); @@ -75,7 +78,10 @@ static void serve_interrupt(QEIDriver *qeip) { */ if (qdec->EVENTS_REPORTRDY) { qdec->EVENTS_REPORTRDY = 0; - +#if CORTEX_MODEL >= 4 + (void)qdec->EVENTS_REPORTRDY; +#endif + /* Read (and clear counters due to shortcut) */ int16_t acc = ( int16_t)qdec->ACCREAD; uint16_t accdbl = (uint16_t)qdec->ACCDBLREAD; @@ -207,6 +213,11 @@ void qei_lld_start(QEIDriver *qeip) { qdec->EVENTS_SAMPLERDY = 0; qdec->EVENTS_REPORTRDY = 0; qdec->EVENTS_ACCOF = 0; +#if CORTEX_MODEL >= 4 + (void)qdec->EVENTS_SAMPLERDY; + (void)qdec->EVENTS_REPORTRDY; + (void)qdec->EVENTS_ACCOF; +#endif } /** @@ -264,6 +275,11 @@ void qei_lld_enable(QEIDriver *qeip) { qeip->qdec->EVENTS_SAMPLERDY = 0; qeip->qdec->EVENTS_REPORTRDY = 0; qeip->qdec->EVENTS_ACCOF = 0; +#if CORTEX_MODEL >= 4 + (void)qeip->qdec->EVENTS_SAMPLERDY; + (void)qeip->qdec->EVENTS_REPORTRDY; + (void)qeip->qdec->EVENTS_ACCOF; +#endif qeip->qdec->TASKS_START = 1; } diff --git a/os/hal/ports/NRF5/LLD/hal_rng_lld.c b/os/hal/ports/NRF5/LLD/hal_rng_lld.c index 5e85981..9712150 100644 --- a/os/hal/ports/NRF5/LLD/hal_rng_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_rng_lld.c @@ -95,7 +95,10 @@ void rng_lld_start(RNGDriver *rngp) { /* Clear pending events */ rng->EVENTS_VALRDY = 0; - +#if CORTEX_MODEL >= 4 + (void)rng->EVENTS_VALRDY; +#endif + /* Set interrupt mask */ rng->INTENSET = RNG_INTENSET_VALRDY_Msk; @@ -151,7 +154,10 @@ msg_t rng_lld_write(RNGDriver *rngp, uint8_t *buf, size_t n, /* Mark as read */ rng->EVENTS_VALRDY = 0; - +#if CORTEX_MODEL >= 4 + (void)rng->EVENTS_VALRDY; +#endif + /* Clear interrupt so we can wake up again */ nvicClearPending(rngp->irq); } diff --git a/os/hal/ports/NRF5/LLD/hal_serial_lld.c b/os/hal/ports/NRF5/LLD/hal_serial_lld.c index 31e5ade..42091e8 100644 --- a/os/hal/ports/NRF5/LLD/hal_serial_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_serial_lld.c @@ -148,10 +148,12 @@ static void configure_uart(const SerialConfig *config) /* Enable UART and clear events */ NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled; NRF_UART0->EVENTS_RXDRDY = 0; - (void)NRF_UART0->EVENTS_RXDRDY; NRF_UART0->EVENTS_TXDRDY = 0; +#if CORTEX_MODEL >= 4 + (void)NRF_UART0->EVENTS_RXDRDY; (void)NRF_UART0->EVENTS_TXDRDY; - +#endif + if (config->rx_pad != NRF5_SERIAL_PAD_DISCONNECTED) { while (NRF_UART0->EVENTS_RXDRDY != 0) { (void)NRF_UART0->RXD; @@ -204,8 +206,10 @@ OSAL_IRQ_HANDLER(Vector48) { if ((NRF_UART0->EVENTS_RXDRDY != 0) && (isr & UART_INTENSET_RXDRDY_Msk)) { // Clear UART RX event flag NRF_UART0->EVENTS_RXDRDY = 0; +#if CORTEX_MODEL >= 4 (void)NRF_UART0->EVENTS_RXDRDY; - +#endif + osalSysLockFromISR(); if (iqIsEmptyI(&sdp->iqueue)) chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); @@ -219,8 +223,10 @@ OSAL_IRQ_HANDLER(Vector48) { // Clear UART TX event flag. NRF_UART0->EVENTS_TXDRDY = 0; +#if CORTEX_MODEL >= 4 (void)NRF_UART0->EVENTS_TXDRDY; - +#endif + osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); osalSysUnlockFromISR(); @@ -241,7 +247,9 @@ OSAL_IRQ_HANDLER(Vector48) { if ((NRF_UART0->EVENTS_ERROR != 0) && (isr & UART_INTENSET_ERROR_Msk)) { // Clear UART ERROR event flag. NRF_UART0->EVENTS_ERROR = 0; +#if CORTEX_MODEL >= 4 (void)NRF_UART0->EVENTS_ERROR; +#endif } diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.c b/os/hal/ports/NRF5/LLD/hal_st_lld.c index c78b4bb..8e42029 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.c @@ -65,8 +65,10 @@ OSAL_IRQ_HANDLER(Vector6C) { OSAL_IRQ_PROLOGUE(); NRF_RTC0->EVENTS_TICK = 0; +#if CORTEX_MODEL >= 4 (void)NRF_RTC0->EVENTS_TICK; - +#endif + osalSysLockFromISR(); osalOsTimerHandlerI(); osalSysUnlockFromISR(); @@ -88,8 +90,10 @@ OSAL_IRQ_HANDLER(Vector84) { OSAL_IRQ_PROLOGUE(); NRF_RTC1->EVENTS_TICK = 0; +#if CORTEX_MODEL >= 4 (void)NRF_RTC1->EVENTS_TICK; - +#endif + osalSysLockFromISR(); osalOsTimerHandlerI(); osalSysUnlockFromISR(); @@ -113,8 +117,10 @@ OSAL_IRQ_HANDLER(Vector60) { /* Clear timer compare event */ if (NRF_TIMER0->EVENTS_COMPARE[0] != 0) { NRF_TIMER0->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 (void)NRF_TIMER0->EVENTS_COMPARE[0]; - +#endif + osalSysLockFromISR(); osalOsTimerHandlerI(); osalSysUnlockFromISR(); @@ -140,8 +146,10 @@ OSAL_IRQ_HANDLER(Vector6C) { if (NRF_RTC0->EVENTS_COMPARE[0]) { NRF_RTC0->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 (void)NRF_RTC0->EVENTS_COMPARE[0]; - +#endif + osalSysLockFromISR(); osalOsTimerHandlerI(); osalSysUnlockFromISR(); @@ -150,7 +158,9 @@ OSAL_IRQ_HANDLER(Vector6C) { #if OSAL_ST_RESOLUTION == 16 if (NRF_RTC0->EVENTS_COMPARE[1]) { NRF_RTC0->EVENTS_COMPARE[1] = 0; +#if CORTEX_MODEL >= 4 (void)NRF_RTC0->EVENTS_COMPARE[1]; +#endif NRF_RTC0->TASKS_CLEAR = 1; } #endif @@ -173,8 +183,10 @@ OSAL_IRQ_HANDLER(Vector84) { if (NRF_RTC1->EVENTS_COMPARE[0]) { NRF_RTC1->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 (void)NRF_RTC1->EVENTS_COMPARE[0]; - +#endif + osalSysLockFromISR(); osalOsTimerHandlerI(); osalSysUnlockFromISR(); @@ -183,7 +195,9 @@ OSAL_IRQ_HANDLER(Vector84) { #if OSAL_ST_RESOLUTION == 16 if (NRF_RTC1->EVENTS_COMPARE[1]) { NRF_RTC1->EVENTS_COMPARE[1] = 0; +#if CORTEX_MODEL >= 4 (void)NRF_RTC1->EVENTS_COMPARE[1]; +#endif NRF_RTC1->TASKS_CLEAR = 1; } #endif @@ -211,10 +225,16 @@ void st_lld_init(void) { NRF_RTC0->PRESCALER = (NRF5_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; NRF_RTC0->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 + (void)NRF_RTC0->EVENTS_COMPARE[0]; +#endif NRF_RTC0->INTENSET = RTC_INTENSET_COMPARE0_Msk; #if OSAL_ST_RESOLUTION == 16 NRF_RTC0->CC[1] = 0x10000; /* 2^16 */ NRF_RTC0->EVENTS_COMPARE[1] = 0; +#if CORTEX_MODEL >= 4 + (void)NRF_RTC0->EVENTS_COMPARE[1]; +#endif NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; NRF_RTC0->INTENSET = RTC_INTENSET_COMPARE1_Msk; #endif @@ -231,10 +251,16 @@ void st_lld_init(void) { NRF_RTC1->PRESCALER = (NRF5_LFCLK_FREQUENCY / OSAL_ST_FREQUENCY) - 1; NRF_RTC1->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; NRF_RTC1->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 + (void)NRF_RTC1->EVENTS_COMPARE[0]; +#endif NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk; #if OSAL_ST_RESOLUTION == 16 NRF_RTC1->CC[1] = 0x10000; /* 2^16 */ NRF_RTC1->EVENTS_COMPARE[1] = 0; +#if CORTEX_MODEL >= 4 + NRF_RTC1->EVENTS_COMPARE[1]; +#endif NRF_RTC1->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE1_Msk; #endif diff --git a/os/hal/ports/NRF5/LLD/hal_st_lld.h b/os/hal/ports/NRF5/LLD/hal_st_lld.h index 7073e12..93c2abb 100644 --- a/os/hal/ports/NRF5/LLD/hal_st_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_st_lld.h @@ -181,11 +181,17 @@ static inline void st_lld_start_alarm(systime_t abstime) { #if NRF5_ST_USE_RTC0 == TRUE NRF_RTC0->CC[0] = abstime; NRF_RTC0->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 + (void)NRF_RTC0->EVENTS_COMPARE[0]; +#endif NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; #endif #if NRF5_ST_USE_RTC1 == TRUE NRF_RTC1->CC[0] = abstime; NRF_RTC1->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 + (void)NRF_RTC1->EVENTS_COMPARE[0]; +#endif NRF_RTC1->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; #endif #if NRF5_ST_USE_TIMER0 == TRUE @@ -202,10 +208,16 @@ static inline void st_lld_stop_alarm(void) { #if NRF5_ST_USE_RTC0 == TRUE NRF_RTC0->EVTENCLR = RTC_EVTENCLR_COMPARE0_Msk; NRF_RTC0->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 + (void)NRF_RTC0->EVENTS_COMPARE[0]; +#endif #endif #if NRF5_ST_USE_RTC1 == TRUE NRF_RTC1->EVTENCLR = RTC_EVTENCLR_COMPARE0_Msk; NRF_RTC1->EVENTS_COMPARE[0] = 0; +#if CORTEX_MODEL >= 4 + (void)NRF_RTC1->EVENTS_COMPARE[0]; +#endif #endif } -- cgit v1.2.3 From 5923ee5d506d91431d8a6d4ab26e3054fc380963 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Mon, 11 Jul 2016 22:42:52 +0200 Subject: moved spi to LLD --- os/hal/ports/NRF5/LLD/hal_spi_lld.c | 383 ++++++++++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_spi_lld.h | 238 ++++++++++++++++++++++ 2 files changed, 621 insertions(+) create mode 100644 os/hal/ports/NRF5/LLD/hal_spi_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_spi_lld.h (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_spi_lld.c b/os/hal/ports/NRF5/LLD/hal_spi_lld.c new file mode 100644 index 0000000..0e90e3f --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_spi_lld.c @@ -0,0 +1,383 @@ +/* + Copyright (C) 2015 Stephen Caudle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/hal_spi_lld.c + * @brief NRF5 low level SPI driver code. + * + * @addtogroup SPI + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if NRF5_SPI_USE_SPI0 || defined(__DOXYGEN__) +/** @brief SPI1 driver identifier.*/ +SPIDriver SPID1; +#endif + +#if NRF5_SPI_USE_SPI1 || defined(__DOXYGEN__) +/** @brief SPI2 driver identifier.*/ +SPIDriver SPID2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Preloads the transmit FIFO. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static void port_fifo_preload(SPIDriver *spip) { + NRF_SPI_Type *port = spip->port; + + if (spip->txcnt > 0 && spip->txptr != NULL) + port->TXD = *(uint8_t *)spip->txptr++; + else + port->TXD = 0xFF; + spip->txcnt--; +} + +#if defined(__GNUC__) +__attribute__((noinline)) +#endif +/** + * @brief Common IRQ handler. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static void serve_interrupt(SPIDriver *spip) { + NRF_SPI_Type *port = spip->port; + + // Clear SPI READY event flag + port->EVENTS_READY = 0; +#if CORTEX_MODEL >= 4 + (void)port->EVENTS_READY; +#endif + + if (spip->rxptr != NULL) { + *(uint8_t *)spip->rxptr++ = port->RXD; + } + else { + (void)port->RXD; + if (--spip->rxcnt == 0) { + osalDbgAssert(spip->txcnt == 0, "counter out of synch"); + /* Stops the IRQ sources.*/ + spip->port->INTENCLR = (SPI_INTENCLR_READY_Clear << SPI_INTENCLR_READY_Pos); + /* Portable SPI ISR code defined in the high level driver, note, it is + a macro.*/ + _spi_isr_code(spip); + return; + } + } + if (spip->txcnt > 0) { + port_fifo_preload(spip); + } + else { + spip->port->INTENCLR = (SPI_INTENCLR_READY_Clear << SPI_INTENCLR_READY_Pos); + /* Portable SPI ISR code defined in the high level driver, note, it is + a macro.*/ + _spi_isr_code(spip); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if NRF5_SPI_USE_SPI0 || defined(__DOXYGEN__) +/** + * @brief SPI0 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector4C) { + + CH_IRQ_PROLOGUE(); + serve_interrupt(&SPID1); + CH_IRQ_EPILOGUE(); +} +#endif +#if NRF5_SPI_USE_SPI1 || defined(__DOXYGEN__) +/** + * @brief SPI1 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector50) { + + CH_IRQ_PROLOGUE(); + serve_interrupt(&SPID2); + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SPI driver initialization. + * + * @notapi + */ +void spi_lld_init(void) { + +#if NRF5_SPI_USE_SPI0 + spiObjectInit(&SPID1); + SPID1.port = NRF_SPI0; +#endif +#if NRF5_SPI_USE_SPI1 + spiObjectInit(&SPID2); + SPID2.port = NRF_SPI1; +#endif +} + +/** + * @brief Configures and activates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_start(SPIDriver *spip) { + uint32_t config; + + if (spip->state == SPI_STOP) { +#if NRF5_SPI_USE_SPI0 + if (&SPID1 == spip) + nvicEnableVector(SPI0_TWI0_IRQn, NRF5_SPI_SPI0_IRQ_PRIORITY); +#endif +#if NRF5_SPI_USE_SPI1 + if (&SPID2 == spip) + nvicEnableVector(SPI1_TWI1_IRQn, NRF5_SPI_SPI1_IRQ_PRIORITY); +#endif + } + + config = spip->config->lsbfirst ? + (SPI_CONFIG_ORDER_LsbFirst << SPI_CONFIG_ORDER_Pos) : + (SPI_CONFIG_ORDER_MsbFirst << SPI_CONFIG_ORDER_Pos); + + switch (spip->config->mode) { + case 1: + config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos); + break; + case 2: + config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos); + break; + case 3: + config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos); + break; + default: + config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos); + break; + } + + /* Configuration.*/ + spip->port->CONFIG = config; + spip->port->PSELSCK = spip->config->sckpad; + spip->port->PSELMOSI = spip->config->mosipad; + spip->port->PSELMISO = spip->config->misopad; + spip->port->FREQUENCY = spip->config->freq; + spip->port->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); + + /* clear events flag */ + spip->port->EVENTS_READY = 0; +#if CORTEX_MODEL >= 4 + (void)spip->port->EVENTS_READY; +#endif +} + +/** + * @brief Deactivates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_stop(SPIDriver *spip) { + + if (spip->state != SPI_STOP) { + spip->port->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos); + spip->port->INTENCLR = (SPI_INTENCLR_READY_Clear << SPI_INTENCLR_READY_Pos); +#if NRF5_SPI_USE_SPI0 + if (&SPID1 == spip) + nvicDisableVector(SPI0_TWI0_IRQn); +#endif +#if NRF5_SPI_USE_SPI1 + if (&SPID2 == spip) + nvicDisableVector(SPI1_TWI1_IRQn); +#endif + } +} + +/** + * @brief Asserts the slave select signal and prepares for transfers. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_select(SPIDriver *spip) { + + palClearPad(IOPORT1, spip->config->sspad); +} + +/** + * @brief Deasserts the slave select signal. + * @details The previously selected peripheral is unselected. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_unselect(SPIDriver *spip) { + + palSetPad(IOPORT1, spip->config->sspad); +} + +/** + * @brief Ignores data on the SPI bus. + * @details This function transmits a series of idle words on the SPI bus and + * ignores the received data. This function can be invoked even + * when a slave select signal has not been yet asserted. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * + * @notapi + */ +void spi_lld_ignore(SPIDriver *spip, size_t n) { + + spip->rxptr = NULL; + spip->txptr = NULL; + spip->rxcnt = spip->txcnt = n; + port_fifo_preload(spip); + spip->port->INTENSET = (SPI_INTENCLR_READY_Enabled << SPI_INTENCLR_READY_Pos); +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This asynchronous function starts a simultaneous transmit/receive + * operation. + * @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 + * + * @notapi + */ +void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + spip->rxptr = rxbuf; + spip->txptr = txbuf; + spip->rxcnt = spip->txcnt = n; + port_fifo_preload(spip); + spip->port->INTENSET = (SPI_INTENCLR_READY_Enabled << SPI_INTENCLR_READY_Pos); +} + +/** + * @brief Sends data over the SPI bus. + * @details This asynchronous function starts a transmit operation. + * @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 + * + * @notapi + */ +void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + + spip->rxptr = NULL; + spip->txptr = txbuf; + spip->rxcnt = spip->txcnt = n; + port_fifo_preload(spip); + spip->port->INTENSET = (SPI_INTENCLR_READY_Enabled << SPI_INTENCLR_READY_Pos); +} + +/** + * @brief Receives data from the SPI bus. + * @details This asynchronous function starts a receive operation. + * @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 + * + * @notapi + */ +void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + + spip->rxptr = rxbuf; + spip->txptr = NULL; + spip->rxcnt = spip->txcnt = n; + port_fifo_preload(spip); + spip->port->INTENSET = (SPI_INTENCLR_READY_Enabled << SPI_INTENCLR_READY_Pos); +} + +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + */ +uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { + + spip->port->TXD = (uint8_t)frame; + while (spip->port->EVENTS_READY == 0) + ; + spip->port->EVENTS_READY = 0; +#if CORTEX_MODEL >= 4 + (void)spip->port->EVENTS_READY; +#endif + return spip->port->RXD; +} + +#endif /* HAL_USE_SPI */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_spi_lld.h b/os/hal/ports/NRF5/LLD/hal_spi_lld.h new file mode 100644 index 0000000..afad5ab --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_spi_lld.h @@ -0,0 +1,238 @@ +/* + Copyright (C) 2015 Stephen Caudle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF/LLD/hal_spi_lld.h + * @brief NRF5 low level SPI driver header. + * + * @addtogroup SPI + * @{ + */ + +#ifndef HAL_SPI_LLD_H +#define HAL_SPI_LLD_H + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief SPI0 interrupt priority level setting. + */ +#if !defined(NRF5_SPI_SPI0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_SPI_SPI0_IRQ_PRIORITY 3 +#endif + +/** + * @brief SPI1 interrupt priority level setting. + */ +#if !defined(NRF5_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_SPI_SPI1_IRQ_PRIORITY 3 +#endif + +/** + * @brief Overflow error hook. + * @details The default action is to stop the system. + */ +#if !defined(NRF5_SPI_SPI_ERROR_HOOK) || defined(__DOXYGEN__) +#define NRF5_SPI_SPI_ERROR_HOOK() chSysHalt() +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !NRF5_SPI_USE_SPI0 && !NRF5_SPI_USE_SPI1 +#error "SPI driver activated but no SPI peripheral assigned" +#endif + +#if NRF5_SPI_USE_SPI0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_SPI_SPI0_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI0" +#endif + +#if NRF5_SPI_USE_SPI1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_SPI_SPI1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SPI1" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an SPI driver. + */ +typedef struct SPIDriver SPIDriver; + +/** + * @brief SPI notification callback type. + * + * @param[in] spip pointer to the @p SPIDriver object triggering the + * callback + */ +typedef void (*spicallback_t)(SPIDriver *spip); + +/** + * @brief SPI frequency + */ +typedef enum { + NRF5_SPI_FREQ_125KBPS = (SPI_FREQUENCY_FREQUENCY_K125 << SPI_FREQUENCY_FREQUENCY_Pos), + NRF5_SPI_FREQ_250KBPS = (SPI_FREQUENCY_FREQUENCY_K250 << SPI_FREQUENCY_FREQUENCY_Pos), + NRF5_SPI_FREQ_500KBPS = (SPI_FREQUENCY_FREQUENCY_K500 << SPI_FREQUENCY_FREQUENCY_Pos), + NRF5_SPI_FREQ_1MBPS = (SPI_FREQUENCY_FREQUENCY_M1 << SPI_FREQUENCY_FREQUENCY_Pos), + NRF5_SPI_FREQ_2MBPS = (SPI_FREQUENCY_FREQUENCY_M2 << SPI_FREQUENCY_FREQUENCY_Pos), + NRF5_SPI_FREQ_4MBPS = (SPI_FREQUENCY_FREQUENCY_M4 << SPI_FREQUENCY_FREQUENCY_Pos), + NRF5_SPI_FREQ_8MBPS = (SPI_FREQUENCY_FREQUENCY_M8 << SPI_FREQUENCY_FREQUENCY_Pos), +} spifreq_t; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief Operation complete callback or @p NULL. + */ + spicallback_t end_cb; + /** + * @brief The frequency of the SPI peripheral + */ + spifreq_t freq; + /** + * @brief The SCK pad + */ + uint16_t sckpad; + /** + * @brief The MOSI pad + */ + uint16_t mosipad; + /** + * @brief The MOSI pad + */ + uint16_t misopad; + /* End of the mandatory fields.*/ + /** + * @brief The chip select line pad number. + */ + uint16_t sspad; + /** + * @brief Shift out least significant bit first + */ + uint8_t lsbfirst; + /** + * @brief SPI mode + */ + uint8_t mode; +} SPIConfig; + +/** + * @brief Structure representing a SPI driver. + */ +struct SPIDriver { + /** + * @brief Driver state. + */ + spistate_t state; + /** + * @brief Current configuration data. + */ + const SPIConfig *config; +#if SPI_USE_WAIT || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif /* SPI_USE_WAIT */ +#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) +#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the bus. + */ + mutex_t mutex; +#elif CH_CFG_USE_SEMAPHORES + semaphore_t semaphore; +#endif +#endif /* SPI_USE_MUTUAL_EXCLUSION */ +#if defined(SPI_DRIVER_EXT_FIELDS) + SPI_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the SPI port. + */ + NRF_SPI_Type *port; + /** + * @brief Number of bytes yet to be received. + */ + uint32_t rxcnt; + /** + * @brief Receive pointer or @p NULL. + */ + void *rxptr; + /** + * @brief Number of bytes yet to be transmitted. + */ + uint32_t txcnt; + /** + * @brief Transmit pointer or @p NULL. + */ + const void *txptr; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if NRF5_SPI_USE_SPI0 && !defined(__DOXYGEN__) +extern SPIDriver SPID1; +#endif +#if NRF5_SPI_USE_SPI1 && !defined(__DOXYGEN__) +extern SPIDriver SPID2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void spi_lld_init(void); + void spi_lld_start(SPIDriver *spip); + void spi_lld_stop(SPIDriver *spip); + void spi_lld_select(SPIDriver *spip); + void spi_lld_unselect(SPIDriver *spip); + void spi_lld_ignore(SPIDriver *spip, size_t n); + void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf); + void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); + void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); + uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SPI */ + +#endif /* HAL_SPI_LLD_H */ + +/** @} */ -- cgit v1.2.3 From 8eabdabb052c686bb1dae89c81bcb92b7f02f413 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Mon, 11 Jul 2016 23:09:07 +0200 Subject: moved i2c to LLD --- os/hal/ports/NRF5/LLD/hal_i2c_lld.c | 462 ++++++++++++++++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_i2c_lld.h | 232 ++++++++++++++++++ 2 files changed, 694 insertions(+) create mode 100644 os/hal/ports/NRF5/LLD/hal_i2c_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_i2c_lld.h (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_i2c_lld.c b/os/hal/ports/NRF5/LLD/hal_i2c_lld.c new file mode 100644 index 0000000..6412844 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_i2c_lld.c @@ -0,0 +1,462 @@ +/* + Copyright (C) 2015 Stephen Caudle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/hal_i2c_lld.c + * @brief NRF5 I2C subsystem low level driver source. + * + * @addtogroup I2C + * @{ + */ + +#include "osal.h" +#include "hal.h" +#include "nrf_delay.h" + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* These macros are needed to see if the slave is stuck and we as master send dummy clock cycles to end its wait */ +#define I2C_HIGH(p) do { IOPORT1->OUTSET = (1UL << (p)); } while(0) /*!< Pulls I2C line high */ +#define I2C_LOW(p) do { IOPORT1->OUTCLR = (1UL << (p)); } while(0) /*!< Pulls I2C line low */ +#define I2C_INPUT(p) do { IOPORT1->DIRCLR = (1UL << (p)); } while(0) /*!< Configures I2C pin as input */ +#define I2C_OUTPUT(p) do { IOPORT1->DIRSET = (1UL << (p)); } while(0) /*!< Configures I2C pin as output */ + +#define I2C_PIN_CNF \ + ((GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ + | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \ + | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) \ + | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \ + | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)) + +#define I2C_PIN_CNF_CLR \ + ((GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ + | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \ + | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) \ + | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \ + | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos)) + +#if NRF5_I2C_USE_I2C0 +#define I2C_IRQ_NUM SPI0_TWI0_IRQn +#define I2C_IRQ_PRI NRF5_I2C_I2C0_IRQ_PRIORITY +#elif NRF5_I2C_USE_I2C1 +#define I2C_IRQ_NUM SPI1_TWI1_IRQn +#define I2C_IRQ_PRI NRF5_I2C_I2C1_IRQ_PRIORITY +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief I2C0 driver identifier. + */ +#if NRF5_I2C_USE_I2C0 || defined(__DOXYGEN__) +I2CDriver I2CD1; +#endif + +/** + * @brief I2C1 driver identifier. + */ +#if NRF5_I2C_USE_I2C1 || defined(__DOXYGEN__) +I2CDriver I2CD2; +#endif + +uint8_t tx_resume_count; +uint8_t rx_resume_count; +uint8_t stop_count; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Function for detecting stuck slaves (SDA = 0 and SCL = 1) and tries to clear the bus. + * + * @return + * @retval false Bus is stuck. + * @retval true Bus is clear. + */ +static void i2c_clear_bus(I2CDriver *i2cp) +{ + const I2CConfig *cfg = i2cp->config; + int i; + + IOPORT1->PIN_CNF[cfg->scl_pad] = I2C_PIN_CNF; + IOPORT1->PIN_CNF[cfg->sda_pad] = I2C_PIN_CNF; + + I2C_HIGH(cfg->sda_pad); + I2C_HIGH(cfg->scl_pad); + + IOPORT1->PIN_CNF[cfg->scl_pad] = I2C_PIN_CNF_CLR; + IOPORT1->PIN_CNF[cfg->sda_pad] = I2C_PIN_CNF_CLR; + + nrf_delay_us(4); + + for(i = 0; i < 9; i++) { + if (palReadPad(IOPORT1, cfg->sda_pad)) { + if(i > 0) + break; + else + return; + } + + I2C_LOW(cfg->scl_pad); + nrf_delay_us(4); + I2C_HIGH(cfg->scl_pad); + nrf_delay_us(4); + } + + I2C_LOW(cfg->sda_pad); + nrf_delay_us(4); + I2C_HIGH(cfg->sda_pad); +} + +static inline void i2c_setup_shortcut(I2CDriver *i2cp) +{ + uint32_t rxbytes = i2cp->rxbytes; + uint32_t txbytes = i2cp->txbytes; + + osalDbgAssert(rxbytes + txbytes, "transfer must be greater than zero"); + + if (txbytes > 1 || (!txbytes && rxbytes > 1)) + i2cp->i2c->SHORTS = TWI_SHORTS_BB_SUSPEND_Enabled << TWI_SHORTS_BB_SUSPEND_Pos; + else if (((txbytes == 1) && !rxbytes) || ((rxbytes == 1) && !txbytes)) + i2cp->i2c->SHORTS = TWI_SHORTS_BB_STOP_Enabled << TWI_SHORTS_BB_STOP_Pos; + else + i2cp->i2c->SHORTS = 0; +} + +#if defined(__GNUC__) +__attribute__((noinline)) +#endif +/** + * @brief Common IRQ handler. + * @note Tries hard to clear all the pending interrupt sources, we don't + * want to go through the whole ISR and have another interrupt soon + * after. + * + * @param[in] i2cp pointer to an I2CDriver + */ +static void serve_interrupt(I2CDriver *i2cp) { + + NRF_TWI_Type *i2c = i2cp->i2c; + + if(i2c->EVENTS_TXDSENT) { + + i2c->EVENTS_TXDSENT = 0; +#if CORTEX_MODEL >= 4 + (void)i2c->EVENTS_TXDSENT; +#endif + + if(--i2cp->txbytes) { + + i2c->TXD = *i2cp->txptr++; + i2c_setup_shortcut(i2cp); + i2c->TASKS_RESUME = 1; + tx_resume_count++; + } + else if (i2cp->rxbytes) { + + i2c_setup_shortcut(i2cp); + i2c->TASKS_STARTRX = 1; + } + } + if(i2c->EVENTS_RXDREADY) { + + i2c->EVENTS_RXDREADY = 0; +#if CORTEX_MODEL >= 4 + (void)i2c->EVENTS_RXDREADY; +#endif + + *i2cp->rxptr++ = i2c->RXD; + + if(--i2cp->rxbytes) { + i2c_setup_shortcut(i2cp); + i2c->TASKS_RESUME = 1; + rx_resume_count++; + } + } + if(i2c->EVENTS_ERROR) { + + uint32_t err = i2c->ERRORSRC; + i2c->EVENTS_ERROR = 0; +#if CORTEX_MODEL >= 4 + (void)i2c->EVENTS_ERROR; +#endif + if (err & TWI_ERRORSRC_OVERRUN_Msk) + i2cp->errors |= I2C_OVERRUN; + if (err & (TWI_ERRORSRC_ANACK_Msk | TWI_ERRORSRC_DNACK_Msk)) + i2cp->errors |= I2C_ACK_FAILURE; + + i2c->TASKS_STOP = 1; + _i2c_wakeup_error_isr(i2cp); + } else if(i2c->EVENTS_STOPPED) { + + stop_count++; + i2c->EVENTS_STOPPED = 0; +#if CORTEX_MODEL >= 4 + (void)i2c->EVENTS_STOPPED; +#endif + _i2c_wakeup_isr(i2cp); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if NRF5_I2C_USE_I2C0 || defined(__DOXYGEN__) + +OSAL_IRQ_HANDLER(Vector4C) { + + OSAL_IRQ_PROLOGUE(); + serve_interrupt(&I2CD1); + OSAL_IRQ_EPILOGUE(); +} + +#endif + +#if NRF5_I2C_USE_I2C1 || defined(__DOXYGEN__) + +OSAL_IRQ_HANDLER(Vector50) { + + OSAL_IRQ_PROLOGUE(); + serve_interrupt(&I2CD2); + OSAL_IRQ_EPILOGUE(); +} + +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2C driver initialization. + * + * @notapi + */ +void i2c_lld_init(void) { + +#if NRF5_I2C_USE_I2C0 + i2cObjectInit(&I2CD1); + I2CD1.thread = NULL; + I2CD1.i2c = NRF_TWI0; +#endif + +#if NRF5_I2C_USE_I2C1 + i2cObjectInit(&I2CD2); + I2CD2.thread = NULL; + I2CD2.i2c = NRF_TWI1; +#endif + +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_start(I2CDriver *i2cp) { + + NRF_TWI_Type *i2c = i2cp->i2c; + const I2CConfig *cfg = i2cp->config; + + if (i2cp->state != I2C_STOP) + return; + + i2c_clear_bus(i2cp); + + IOPORT1->PIN_CNF[cfg->scl_pad] = I2C_PIN_CNF; + IOPORT1->PIN_CNF[cfg->sda_pad] = I2C_PIN_CNF; + + i2c->EVENTS_RXDREADY = 0; + i2c->EVENTS_TXDSENT = 0; +#if CORTEX_MODEL >= 4 + (void)i2c->EVENTS_RXDREADY; + (void)i2c->EVENTS_TXDSENT; +#endif + i2c->PSELSCL = cfg->scl_pad; + i2c->PSELSDA = cfg->sda_pad; + + switch (cfg->clock) { + case 100000: + i2c->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K100 << TWI_FREQUENCY_FREQUENCY_Pos; + break; + case 250000: + i2c->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K250 << TWI_FREQUENCY_FREQUENCY_Pos; + break; + case 400000: + i2c->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K400 << TWI_FREQUENCY_FREQUENCY_Pos; + break; + default: + osalDbgAssert(0, "invalid I2C frequency"); + break; + }; + + nvicEnableVector(I2C_IRQ_NUM, I2C_IRQ_PRI); + + i2c->INTENSET = TWI_INTENSET_TXDSENT_Msk | TWI_INTENSET_STOPPED_Msk | + TWI_INTENSET_ERROR_Msk | TWI_INTENSET_RXDREADY_Msk; + + i2c->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos; +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_stop(I2CDriver *i2cp) { + + NRF_TWI_Type *i2c = i2cp->i2c; + const I2CConfig *cfg = i2cp->config; + + if (i2cp->state != I2C_STOP) { + + i2c->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; + + i2c->INTENCLR = TWI_INTENSET_TXDSENT_Msk | TWI_INTENSET_STOPPED_Msk | + TWI_INTENSET_ERROR_Msk | TWI_INTENSET_RXDREADY_Msk; + + nvicDisableVector(I2C_IRQ_NUM); + + IOPORT1->PIN_CNF[cfg->scl_pad] = I2C_PIN_CNF_CLR; + IOPORT1->PIN_CNF[cfg->sda_pad] = I2C_PIN_CNF_CLR; + } +} + +static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout) { + + NRF_TWI_Type *i2c = i2cp->i2c; + + (void)timeout; + msg_t msg; + + i2cp->errors = I2C_NO_ERROR; + i2cp->addr = addr; + + i2cp->txptr = txbuf; + i2cp->txbytes = txbytes; + + i2cp->rxptr = rxbuf; + i2cp->rxbytes = rxbytes; + + i2c->ADDRESS = addr; + + tx_resume_count = 0; + rx_resume_count = 0; + stop_count = 0; + + if (i2cp->txbytes) { + + i2c->TXD = *i2cp->txptr++; + i2c_setup_shortcut(i2cp); + i2c->TASKS_STARTTX = 1; + } else if (i2cp->rxbytes) { + + i2c_setup_shortcut(i2cp); + i2c->TASKS_STARTRX = 1; + } else { + + osalDbgAssert(0, "no bytes to transfer"); + } + + msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + + if (msg == MSG_TIMEOUT) + i2c->TASKS_STOP = 1; + + return msg; +} + +/** + * @brief Receives data via the I2C bus as master. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout) { + + return _i2c_txrx_timeout(i2cp, addr, NULL, 0, rxbuf, rxbytes, timeout); +} + +/** + * @brief Transmits data via the I2C bus as master. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout) { + + return _i2c_txrx_timeout(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes, timeout); +} + +#endif /* HAL_USE_I2C */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_i2c_lld.h b/os/hal/ports/NRF5/LLD/hal_i2c_lld.h new file mode 100644 index 0000000..578d69b --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_i2c_lld.h @@ -0,0 +1,232 @@ +/* + Copyright (C) 2015 Stephen Caudle + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file NRF5/LLD/hal_i2c_lld.h + * @brief NRF5 I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#ifndef HAL_I2C_LLD_H +#define HAL_I2C_LLD_H + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define STATE_STOP 0x00 +#define STATE_SEND 0x01 +#define STATE_RECV 0x02 +#define STATE_DUMMY 0x03 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief I2C0 driver enable switch. + * @details If set to @p TRUE the support for I2C0 is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_I2C_USE_I2C0) || defined(__DOXYGEN__) +#define NRF5_I2C_USE_I2C0 FALSE +#endif + +/** + * @brief I2C1 driver enable switch. + * @details If set to @p TRUE the support for I2C1 is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_I2C_USE_I2C1) || defined(__DOXYGEN__) +#define NRF5_I2C_USE_I2C1 FALSE +#endif + +/** + * @brief I2C0 interrupt priority level setting. + */ +#if !defined(NRF5_I2C_I2C0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_I2C_I2C0_IRQ_PRIORITY 3 +#endif + +/** + * @brief I2C1 interrupt priority level setting. + */ +#if !defined(NRF5_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_I2C_I2C1_IRQ_PRIORITY 3 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if NRF5_I2C_USE_I2C0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_I2C_I2C0_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C0" +#endif + +#if NRF5_I2C_USE_I2C1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_I2C_I2C1_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to I2C1" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/* @brief Type representing I2C address. */ +typedef uint8_t i2caddr_t; + +/* @brief Type of I2C Driver condition flags. */ +typedef uint32_t i2cflags_t; + +/* @brief Type used to control the ISR state machine. */ +typedef uint8_t intstate_t; + +/** + * @brief Driver configuration structure. + * @note Implementations may extend this structure to contain more, + * architecture dependent, fields. + */ + +/** + * @brief Driver configuration structure. + */ +typedef struct { + + /* @brief Clock to be used for the I2C bus. */ + uint32_t clock; + /* @brief Pad number for SCL */ + uint8_t scl_pad; + /* @brief Pad number for SDA */ + uint8_t sda_pad; + +} I2CConfig; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CDriver I2CDriver; + +/** + * @brief Structure representing an I2C driver. + */ +struct I2CDriver { + /** + * @brief Driver state. + */ + i2cstate_t state; + /** + * @brief Current configuration data. + */ + const I2CConfig *config; + /** + * @brief Error flags. + */ + i2cflags_t errors; +#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) +#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the bus. + */ + mutex_t mutex; +#elif CH_CFG_USE_SEMAPHORES + semaphore_t semaphore; +#endif +#endif /* I2C_USE_MUTUAL_EXCLUSION */ +#if defined(I2C_DRIVER_EXT_FIELDS) + I2C_DRIVER_EXT_FIELDS +#endif + /* @brief Thread waiting for I/O completion. */ + thread_reference_t thread; + /* @brief Current slave address without R/W bit. */ + i2caddr_t addr; + + /* End of the mandatory fields.*/ + + /* @brief Pointer to the buffer with data to send. */ + const uint8_t *txptr; + /* @brief Number of bytes of data to send. */ + size_t txbytes; + /* @brief Pointer to the buffer to put received data. */ + uint8_t *rxptr; + /* @brief Number of bytes of data to receive. */ + size_t rxbytes; + /* @brief Tracks current ISR state. */ + intstate_t intstate; + /* @brief Low-level register access. */ + NRF_TWI_Type *i2c; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Get errors from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_errors(i2cp) ((i2cp)->errors) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) + +#if NRF5_I2C_USE_I2C0 +extern I2CDriver I2CD1; +#endif + +#if NRF5_I2C_USE_I2C1 +extern I2CDriver I2CD2; +#endif + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void i2c_lld_init(void); + void i2c_lld_start(I2CDriver *i2cp); + void i2c_lld_stop(I2CDriver *i2cp); + msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout); + msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_I2C */ + +#endif /* HAL_I2C_LLD_H */ + +/** @} */ -- cgit v1.2.3 From 194e5ec59ce0d58f82c99d17c026de64ba3f1316 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Mon, 11 Jul 2016 23:17:26 +0200 Subject: PSEL renamed in nrf52 --- os/hal/ports/NRF5/LLD/hal_i2c_lld.c | 7 ++++++- os/hal/ports/NRF5/LLD/hal_spi_lld.c | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_i2c_lld.c b/os/hal/ports/NRF5/LLD/hal_i2c_lld.c index 6412844..fefca0c 100644 --- a/os/hal/ports/NRF5/LLD/hal_i2c_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_i2c_lld.c @@ -299,9 +299,14 @@ void i2c_lld_start(I2CDriver *i2cp) { (void)i2c->EVENTS_RXDREADY; (void)i2c->EVENTS_TXDSENT; #endif +#if NRF_SERIES == 51 i2c->PSELSCL = cfg->scl_pad; i2c->PSELSDA = cfg->sda_pad; - +#else + i2c->PSEL.SCL = cfg->scl_pad; + i2c->PSEL.SDA = cfg->sda_pad; +#endif + switch (cfg->clock) { case 100000: i2c->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K100 << TWI_FREQUENCY_FREQUENCY_Pos; diff --git a/os/hal/ports/NRF5/LLD/hal_spi_lld.c b/os/hal/ports/NRF5/LLD/hal_spi_lld.c index 0e90e3f..2c6ec91 100644 --- a/os/hal/ports/NRF5/LLD/hal_spi_lld.c +++ b/os/hal/ports/NRF5/LLD/hal_spi_lld.c @@ -204,9 +204,15 @@ void spi_lld_start(SPIDriver *spip) { /* Configuration.*/ spip->port->CONFIG = config; +#if NRF_SERIES == 51 spip->port->PSELSCK = spip->config->sckpad; spip->port->PSELMOSI = spip->config->mosipad; spip->port->PSELMISO = spip->config->misopad; +#else + spip->port->PSEL.SCK = spip->config->sckpad; + spip->port->PSEL.MOSI = spip->config->mosipad; + spip->port->PSEL.MISO = spip->config->misopad; +#endif spip->port->FREQUENCY = spip->config->freq; spip->port->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); -- cgit v1.2.3 From c7d33767e06000f9da3befd6a7954b82c42d080d Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 10 Sep 2016 15:13:23 +0200 Subject: change qei types to int16_t --- os/hal/ports/NRF5/LLD/hal_qei_lld.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'os/hal/ports/NRF5/LLD') diff --git a/os/hal/ports/NRF5/LLD/hal_qei_lld.h b/os/hal/ports/NRF5/LLD/hal_qei_lld.h index 6328bab..85c96a5 100644 --- a/os/hal/ports/NRF5/LLD/hal_qei_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_qei_lld.h @@ -166,7 +166,7 @@ typedef enum { /** * @brief QEI counter type. */ -typedef int32_t qeicnt_t; +typedef int16_t qeicnt_t; /** * @brief QEI delta type. -- cgit v1.2.3