diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf')
20 files changed, 6564 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_error.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_error.h new file mode 100644 index 0000000..c673beb --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_error.h @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* Header guard */ + +#ifndef SOFTDEVICE_PRESENT + +/** + @defgroup nrf_error Global Error Codes + @{ + + @brief Global Error definitions +*/ + +#ifndef NRF_ERROR_H__ +#define NRF_ERROR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions + * @{ */ +#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base +#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base +#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base +#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base +/** @} */ + +#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command +#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing +#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled +#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error +#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation +#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found +#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported +#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter +#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state +#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length +#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags +#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data +#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Data size exceeds limit +#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out +#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer +#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation +#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address +#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy + +#ifdef __cplusplus +} +#endif + +#endif // NRF_ERROR_H__ + +/** + @} +*/ + +#endif // SOFTDEVICE_PRESENT diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c new file mode 100644 index 0000000..8fa8b2b --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdlib.h> +#include "nrf_soc.h" +#include "nrf_error.h" + +static uint8_t m_in_critical_region = 0; + +uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) +{ + NVIC_EnableIRQ(IRQn); + return NRF_SUCCESS; +} + +uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) +{ + NVIC_DisableIRQ(IRQn); + return NRF_SUCCESS; +} + +uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t * p_pending_irq) +{ + if (p_pending_irq != NULL) + { + *p_pending_irq = NVIC_GetPendingIRQ(IRQn); + return NRF_SUCCESS; + } + return NRF_ERROR_NULL; +} + +uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC_SetPendingIRQ(IRQn); + return NRF_SUCCESS; +} + +uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC_ClearPendingIRQ(IRQn); + return NRF_SUCCESS; +} + +uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + NVIC_SetPriority(IRQn, priority); + return NRF_SUCCESS; +} + +uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t * p_priority) +{ + if (p_priority != NULL) + { + *p_priority = NVIC_GetPriority(IRQn); + return NRF_SUCCESS; + } + + return NRF_ERROR_NULL; +} + +uint32_t sd_nvic_SystemReset(void) +{ + NVIC_SystemReset(); + return NRF_SUCCESS; +} + +uint32_t sd_nvic_critical_region_enter(uint8_t * p_is_nested_critical_region) +{ + __disable_irq(); + + *p_is_nested_critical_region = (m_in_critical_region != 0); + m_in_critical_region++; + + return NRF_SUCCESS; +} + +uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) +{ + m_in_critical_region--; + + if (is_nested_critical_region == 0) + { + m_in_critical_region = 0; + __enable_irq(); + } + return NRF_SUCCESS; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.h new file mode 100644 index 0000000..58dd027 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.h @@ -0,0 +1,166 @@ +/** + * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef NRF_NVIC_H__ +#define NRF_NVIC_H__ + +#include <stdint.h> +#include "nrf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@brief Enable External Interrupt. + * @note Corresponds to NVIC_EnableIRQ in CMSIS. + * + * @pre{IRQn is valid and not reserved by the stack} + * + * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was enabled. + */ +uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); + +/**@brief Disable External Interrupt. + * @note Corresponds to NVIC_DisableIRQ in CMSIS. + * + * @pre{IRQn is valid and not reserved by the stack} + * + * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS + * + * @retval ::NRF_SUCCESS The interrupt was disabled. + */ +uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); + +/**@brief Get Pending Interrupt. + * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. + * + * @pre{IRQn is valid and not reserved by the stack} + * + * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. + * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. + * + * @retval ::NRF_SUCCESS The interrupt is available for the application. + */ +uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t * p_pending_irq); + +/**@brief Set Pending Interrupt. + * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. + * + * @pre{IRQn is valid and not reserved by the stack} + * + * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt is set pending. + */ +uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); + +/**@brief Clear Pending Interrupt. + * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. + * + * @pre{IRQn is valid and not reserved by the stack} + * + * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. + */ +uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); + +/**@brief Set Interrupt Priority. + * @note Corresponds to NVIC_SetPriority in CMSIS. + * + * @pre{IRQn is valid and not reserved by the stack} + * @pre{priority is valid and not reserved by the stack} + * + * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. + * @param[in] priority A valid IRQ priority for use by the application. + * + * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. + */ +uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); + +/**@brief Get Interrupt Priority. + * @note Corresponds to NVIC_GetPriority in CMSIS. + * + * @pre{IRQn is valid and not reserved by the stack} + * + * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. + * @param[out] p_priority Return value from NVIC_GetPriority. + * + * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. + */ +uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t * p_priority); + +/**@brief System Reset. + * @note Corresponds to NVIC_SystemReset in CMSIS. + * + * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN + */ +uint32_t sd_nvic_SystemReset(void); + +/**@brief Enters critical region. + * + * @post Application interrupts will be disabled. + * @sa sd_nvic_critical_region_exit + * + * @param[out] p_is_nested_critical_region 1: If in a nested critical region. + * 0: Otherwise. + * + * @retval ::NRF_SUCCESS + */ +uint32_t sd_nvic_critical_region_enter(uint8_t * p_is_nested_critical_region); + +/**@brief Exit critical region. + * + * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. + * @post If not in a nested critical region, the application interrupts will restored to the state before ::sd_nvic_critical_region_enter was called. + * + * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa sd_nvic_critical_region_enter. + * + * @retval ::NRF_SUCCESS + */ +uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); + + +#ifdef __cplusplus +} +#endif + +#endif /* NRF_NVIC_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_sdm.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_sdm.h new file mode 100644 index 0000000..ec3f150 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_sdm.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef NRF_SDM_H__ +#define NRF_SDM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ +#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SDM_H__ + + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_soc.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_soc.c new file mode 100644 index 0000000..da25fbb --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_soc.c @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdlib.h> +#include "nrf_soc.h" +#include "nrf_error.h" + +uint32_t sd_app_evt_wait(void) +{ + __WFE(); + return NRF_SUCCESS; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_soc.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_soc.h new file mode 100644 index 0000000..c1c9d04 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/nrf_soc_nosd/nrf_soc.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef NRF_SOC_H__ +#define NRF_SOC_H__ + +#include <stdint.h> +#include "nrf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@brief Waits for an application event. + * + * An application event is either an application interrupt or a pended interrupt when the + * interrupt is disabled. When the interrupt is enabled it will be taken immediately since + * this function will wait in thread mode, then the execution will return in the application's + * main thread. When an interrupt is disabled and gets pended it will return to the application's + * thread main. The application must ensure that the pended flag is cleared using + * ::sd_nvic_ClearPendingIRQ in order to sleep using this function. This is only necessary for + * disabled interrupts, as the interrupt handler will clear the pending flag automatically for + * enabled interrupts. + * + * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M0 + * System Control Register (SCR). @sa CMSIS_SCB + * + * @note If an application interrupt has happened since the last time sd_app_evt_wait was + * called this function will return immediately and not go to sleep. This is to avoid race + * conditions that can occur when a flag is updated in the interrupt handler and processed + * in the main loop. + * + * @post An application interrupt has happened or a interrupt pending flag is set. + * + * @retval ::NRF_SUCCESS + */ +uint32_t sd_app_evt_wait(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* NRF_SOC_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/radio_config/radio_config.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/radio_config/radio_config.c new file mode 100644 index 0000000..e3849df --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/radio_config/radio_config.c @@ -0,0 +1,188 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** @file +* @addtogroup nrf_dev_radio_rx_example_main nrf_dev_radio_tx_example_main +* @{ +*/ + +#include "radio_config.h" +#include "nrf_delay.h" + +/* These are set to zero as ShockBurst packets don't have corresponding fields. */ +#define PACKET_S1_FIELD_SIZE (0UL) /**< Packet S1 field size in bits. */ +#define PACKET_S0_FIELD_SIZE (0UL) /**< Packet S0 field size in bits. */ +#define PACKET_LENGTH_FIELD_SIZE (0UL) /**< Packet length field size in bits. */ + +/** + * @brief Function for swapping/mirroring bits in a byte. + * + *@verbatim + * output_bit_7 = input_bit_0 + * output_bit_6 = input_bit_1 + * : + * output_bit_0 = input_bit_7 + *@endverbatim + * + * @param[in] inp is the input byte to be swapped. + * + * @return + * Returns the swapped/mirrored input byte. + */ +static uint32_t swap_bits(uint32_t inp); + +/** + * @brief Function for swapping bits in a 32 bit word for each byte individually. + * + * The bits are swapped as follows: + * @verbatim + * output[31:24] = input[24:31] + * output[23:16] = input[16:23] + * output[15:8] = input[8:15] + * output[7:0] = input[0:7] + * @endverbatim + * @param[in] input is the input word to be swapped. + * + * @return + * Returns the swapped input byte. + */ +static uint32_t bytewise_bitswap(uint32_t inp); + +static uint32_t swap_bits(uint32_t inp) +{ + uint32_t i; + uint32_t retval = 0; + + inp = (inp & 0x000000FFUL); + + for (i = 0; i < 8; i++) + { + retval |= ((inp >> i) & 0x01) << (7 - i); + } + + return retval; +} + + +static uint32_t bytewise_bitswap(uint32_t inp) +{ + return (swap_bits(inp >> 24) << 24) + | (swap_bits(inp >> 16) << 16) + | (swap_bits(inp >> 8) << 8) + | (swap_bits(inp)); +} + + +/** + * @brief Function for configuring the radio to operate in ShockBurst compatible mode. + * + * To configure the application running on nRF24L series devices: + * + * @verbatim + * uint8_t tx_address[5] = { 0xC0, 0x01, 0x23, 0x45, 0x67 }; + * hal_nrf_set_rf_channel(7); + * hal_nrf_set_address_width(HAL_NRF_AW_5BYTES); + * hal_nrf_set_address(HAL_NRF_TX, tx_address); + * hal_nrf_set_address(HAL_NRF_PIPE0, tx_address); + * hal_nrf_open_pipe(0, false); + * hal_nrf_set_datarate(HAL_NRF_1MBPS); + * hal_nrf_set_crc_mode(HAL_NRF_CRC_16BIT); + * hal_nrf_setup_dynamic_payload(0xFF); + * hal_nrf_enable_dynamic_payload(false); + * @endverbatim + * + * When transmitting packets with hal_nrf_write_tx_payload(const uint8_t *tx_pload, uint8_t length), + * match the length with PACKET_STATIC_LENGTH. + * hal_nrf_write_tx_payload(payload, PACKET_STATIC_LENGTH); + * +*/ +void radio_configure() +{ + // Radio config + NRF_RADIO->TXPOWER = (RADIO_TXPOWER_TXPOWER_0dBm << RADIO_TXPOWER_TXPOWER_Pos); + NRF_RADIO->FREQUENCY = 7UL; // Frequency bin 7, 2407MHz + NRF_RADIO->MODE = (RADIO_MODE_MODE_Nrf_1Mbit << RADIO_MODE_MODE_Pos); + + // Radio address config + NRF_RADIO->PREFIX0 = + ((uint32_t)swap_bits(0xC3) << 24) // Prefix byte of address 3 converted to nRF24L series format + | ((uint32_t)swap_bits(0xC2) << 16) // Prefix byte of address 2 converted to nRF24L series format + | ((uint32_t)swap_bits(0xC1) << 8) // Prefix byte of address 1 converted to nRF24L series format + | ((uint32_t)swap_bits(0xC0) << 0); // Prefix byte of address 0 converted to nRF24L series format + + NRF_RADIO->PREFIX1 = + ((uint32_t)swap_bits(0xC7) << 24) // Prefix byte of address 7 converted to nRF24L series format + | ((uint32_t)swap_bits(0xC6) << 16) // Prefix byte of address 6 converted to nRF24L series format + | ((uint32_t)swap_bits(0xC4) << 0); // Prefix byte of address 4 converted to nRF24L series format + + NRF_RADIO->BASE0 = bytewise_bitswap(0x01234567UL); // Base address for prefix 0 converted to nRF24L series format + NRF_RADIO->BASE1 = bytewise_bitswap(0x89ABCDEFUL); // Base address for prefix 1-7 converted to nRF24L series format + + NRF_RADIO->TXADDRESS = 0x00UL; // Set device address 0 to use when transmitting + NRF_RADIO->RXADDRESSES = 0x01UL; // Enable device address 0 to use to select which addresses to receive + + // Packet configuration + NRF_RADIO->PCNF0 = (PACKET_S1_FIELD_SIZE << RADIO_PCNF0_S1LEN_Pos) | + (PACKET_S0_FIELD_SIZE << RADIO_PCNF0_S0LEN_Pos) | + (PACKET_LENGTH_FIELD_SIZE << RADIO_PCNF0_LFLEN_Pos); //lint !e845 "The right argument to operator '|' is certain to be 0" + + // Packet configuration + NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | + (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | + (PACKET_BASE_ADDRESS_LENGTH << RADIO_PCNF1_BALEN_Pos) | + (PACKET_STATIC_LENGTH << RADIO_PCNF1_STATLEN_Pos) | + (PACKET_PAYLOAD_MAXSIZE << RADIO_PCNF1_MAXLEN_Pos); //lint !e845 "The right argument to operator '|' is certain to be 0" + + // CRC Config + NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos); // Number of checksum bits + if ((NRF_RADIO->CRCCNF & RADIO_CRCCNF_LEN_Msk) == (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos)) + { + NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value + NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16 + x^12^x^5 + 1 + } + else if ((NRF_RADIO->CRCCNF & RADIO_CRCCNF_LEN_Msk) == (RADIO_CRCCNF_LEN_One << RADIO_CRCCNF_LEN_Pos)) + { + NRF_RADIO->CRCINIT = 0xFFUL; // Initial value + NRF_RADIO->CRCPOLY = 0x107UL; // CRC poly: x^8 + x^2^x^1 + 1 + } +} + +/** + * @} + */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/radio_config/radio_config.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/radio_config/radio_config.h new file mode 100644 index 0000000..f8e8be5 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/radio_config/radio_config.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef RADIO_CONFIG_H +#define RADIO_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PACKET_BASE_ADDRESS_LENGTH (4UL) //!< Packet base address length field size in bytes +#define PACKET_STATIC_LENGTH (1UL) //!< Packet static length in bytes +#define PACKET_PAYLOAD_MAXSIZE (PACKET_STATIC_LENGTH) //!< Packet payload maximum size in bytes + +void radio_configure(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/config/sdio_config.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/config/sdio_config.h new file mode 100644 index 0000000..6551ec0 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/config/sdio_config.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef SDIO_CONFIG_H +#define SDIO_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SDIO_CONFIG_CLOCK_PIN_NUMBER 24 +#define SDIO_CONFIG_DATA_PIN_NUMBER 25 + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/sdio.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/sdio.c new file mode 100644 index 0000000..68763b0 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/sdio.c @@ -0,0 +1,244 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdint.h> + +#include "nrf.h" +#include "nrf_delay.h" +#include "sdio.h" +#include "nrf_gpio.h" + +#include "sdio_config.h" + +/*lint ++flb "Enter library region" */ + +/*lint -e717 -save "Suppress do {} while (0) for these macros" */ +#define SDIO_CLOCK_HIGH() do { NRF_GPIO->OUTSET = (1UL << SDIO_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Pulls SCL line high */ +#define SDIO_CLOCK_LOW() do { NRF_GPIO->OUTCLR = (1UL << SDIO_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Pulls SCL line low */ +#define SDIO_DATA_HIGH() do { NRF_GPIO->OUTSET = (1UL << SDIO_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Pulls SDA line high */ +#define SDIO_DATA_LOW() do { NRF_GPIO->OUTCLR = (1UL << SDIO_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Pulls SDA line low */ +#define SDIO_DATA_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << SDIO_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Configures SDA pin as output */ +#define SDIO_CLOCK_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << SDIO_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Configures SCL pin as output */ +/*lint -restore */ + +/*lint -emacro(845,SDIO_DATA_INPUT) // A zero has been given as right argument to operator '|'" */ + +#define SDIO_DATA_INPUT() do { \ + nrf_gpio_cfg_input(25, NRF_GPIO_PIN_NOPULL); \ +} while (0) + +#define SDIO_DATA_READ() ((NRF_GPIO->IN >> SDIO_CONFIG_DATA_PIN_NUMBER) & 0x1UL) /*!< Reads current state of SDA */ +#define SDIO_CLOCK_READ() ((NRF_GPIO->IN >> SDIO_CONFIG_CLOCK_PIN_NUMBER) & 0x1UL) /*!< Reads current state of SCL */ +#define SDIO_DELAY() nrf_delay_us(10) /*!< Time to wait when pin states are changed. For fast-mode the delay can be zero and for standard-mode 4 us delay is sufficient. */ + +void sdio_init(void) +{ + SDIO_CLOCK_HIGH(); + SDIO_DATA_HIGH(); + SDIO_CLOCK_OUTPUT(); + SDIO_DATA_INPUT(); + + // If slave is stuck in the middle of transfer, clock out bits until the slave ACKs the transfer + for (uint_fast8_t i = 16; i--;) + { + SDIO_DELAY(); + SDIO_CLOCK_LOW(); + SDIO_DELAY(); + SDIO_CLOCK_HIGH(); + SDIO_DELAY(); + + if (SDIO_DATA_READ()) + { + break; + } + } + + for (uint_fast8_t i = 5; i--;) + { + SDIO_DELAY(); + SDIO_CLOCK_LOW(); + SDIO_DELAY(); + SDIO_CLOCK_HIGH(); + } + + SDIO_DATA_OUTPUT(); + SDIO_DATA_HIGH(); + + SDIO_DELAY(); +} + +uint8_t sdio_read_byte(uint8_t address) +{ + uint8_t data_byte = 0; + + SDIO_DATA_OUTPUT(); + + for (uint_fast8_t i = 8; i--;) + { + SDIO_DELAY(); + + SDIO_CLOCK_LOW(); + + if (address & (1U << i)) + { + SDIO_DATA_HIGH(); + } + else + { + SDIO_DATA_LOW(); + } + + SDIO_DELAY(); + + SDIO_CLOCK_HIGH(); + } + + nrf_delay_us(20); + + SDIO_DATA_INPUT(); + + for (uint_fast8_t i = 8; i--;) + { + SDIO_CLOCK_LOW(); + SDIO_DELAY(); + SDIO_CLOCK_HIGH(); + SDIO_DELAY(); + data_byte |= (uint8_t)(SDIO_DATA_READ() << i); + } + + SDIO_DATA_HIGH(); + SDIO_DATA_OUTPUT(); + + SDIO_DELAY(); + + return data_byte; +} + +void sdio_read_burst(uint8_t * target_buffer, uint8_t target_buffer_size) +{ + uint_fast8_t address = 0x63; + + SDIO_DATA_OUTPUT(); + + for (uint_fast8_t bit_index=8; bit_index--;) + { + SDIO_CLOCK_LOW(); + + if (address & (1U << bit_index)) + { + SDIO_DATA_HIGH(); + } + else + { + SDIO_DATA_LOW(); + } + + SDIO_CLOCK_HIGH(); + } + + SDIO_DATA_INPUT(); + + for (uint_fast8_t target_buffer_index = 0; target_buffer_index < target_buffer_size; target_buffer_index++) + { + target_buffer[target_buffer_index] = 0; + + for (uint_fast8_t bit_index = 8; bit_index--;) + { + SDIO_CLOCK_LOW(); + SDIO_CLOCK_HIGH(); + target_buffer[target_buffer_index] |= (uint8_t)(SDIO_DATA_READ() << bit_index); + } + } +} + +void sdio_write_byte(uint8_t address, uint8_t data_byte) +{ + // Add write indication bit + address |= 0x80; + + SDIO_DATA_OUTPUT(); + + for (uint_fast8_t i = 8; i--;) + { + SDIO_DELAY(); + + SDIO_CLOCK_LOW(); + + if (address & (1U << i)) + { + SDIO_DATA_HIGH(); + } + else + { + SDIO_DATA_LOW(); + } + + SDIO_DELAY(); + + SDIO_CLOCK_HIGH(); + } + + SDIO_DELAY(); + + for (uint_fast8_t i = 8; i--;) + { + SDIO_CLOCK_LOW(); + + if (data_byte & (1U << i)) + { + SDIO_DATA_HIGH(); + } + else + { + SDIO_DATA_LOW(); + } + + SDIO_DELAY(); + + SDIO_CLOCK_HIGH(); + + SDIO_DELAY(); + } + + SDIO_DATA_HIGH(); + + SDIO_DELAY(); +} + +/*lint --flb "Leave library region" */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/sdio.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/sdio.h new file mode 100644 index 0000000..bea2062 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/sdio/sdio.h @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef SDIO_H +#define SDIO_H + +/*lint ++flb "Enter library region" */ + +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file +* @brief 2-wire serial interface driver (compatible with ADNS2080 mouse sensor driver) +* +* +* @defgroup nrf_drivers_sdio SDIO driver +* @{ +* @ingroup nrf_drivers +* @brief 2-wire serial interface driver. +*/ + +/** + * @brief Function for initializing 2-wire serial interface and trying to handle stuck slaves. + * + */ +void sdio_init(void); + +/** + * @brief Function for reading a byte over 2-wire serial interface. + * + * Developer needs to implement this function in a way that suits the hardware. + * @param address Register address to read from + * @return Byte read + */ +uint8_t sdio_read_byte(uint8_t address); + +/** + * @brief Function for reading several bytes over 2-wire serial interface using burst mode. + * + * Developer needs to implement this function in a way that suits the hardware. + * @param target_buffer Buffer location to store read bytes to + * @param target_buffer_size Bytes allocated for target_buffer + */ +void sdio_read_burst(uint8_t *target_buffer, uint8_t target_buffer_size); + +/** + * @brief Function for writing a byte over 2-wire serial interface. + * + * Developer needs to implement this function in a way that suits the hardware. + * @param address Register address to write to + * @param data_byte Data byte to write + */ +void sdio_write_byte(uint8_t address, uint8_t data_byte); + +/** + *@} + **/ + +/*lint --flb "Leave library region" */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/spi_master/spi_5W_master.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/spi_master/spi_5W_master.c new file mode 100644 index 0000000..031863d --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/spi_master/spi_5W_master.c @@ -0,0 +1,629 @@ +/** + * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/**@file + * + * @defgroup ser_phy_spi_5W_hw_driver_master spi_5W_master.c + * @{ + * @ingroup ser_phy_spi_5W_hw_driver_master + * + * @brief SPI_5W_RAW hardware driver. + */ + +#include "app_error.h" +#include "app_util_platform.h" +#include "nrf_gpio.h" +#include "nrf.h" +#include "spi_5W_master.h" +#include "ser_config_5W_app.h" +#include "ser_phy_debug_app.h" +#include "sdk_common.h" + + +#define _static + +#define DOUBLE_BUFFERED /**< A flag for enabling double buffering. */ + +#define SPI_PIN_DISCONNECTED 0xFFFFFFFF /**< A value used to the PIN deinitialization. */ +#define SPI_DEFAULT_TX_BYTE 0x00 /**< Default byte (used to clock transmission + from slave to the master) */ + +typedef struct +{ + NRF_SPI_Type * p_nrf_spi; /**< A pointer to the NRF SPI master */ + IRQn_Type irq_type; /**< A type of NVIC IRQn */ + + uint8_t * p_tx_buffer; /**< A pointer to TX buffer. */ + uint16_t tx_length; /**< A length of TX buffer. */ + uint16_t tx_index; /**< A index of the current element in the TX buffer. */ + + uint8_t * p_rx_buffer; /**< A pointer to RX buffer. */ + uint16_t rx_length; /**< A length RX buffer. */ + uint16_t rx_index; /**< A index of the current element in the RX buffer. */ + + uint16_t max_length; /**< Max length (Max of the TX and RX length). */ + uint16_t bytes_count; + uint8_t pin_slave_select; /**< A pin for Slave Select. */ + + spi_master_event_handler_t callback_event_handler; /**< A handler for event callback function. */ + spi_master_state_t state; /**< A state of an instance of SPI master. */ + bool start_flag; + bool abort_flag; + +} spi_master_instance_t; + +#ifdef _SPI_5W_ +typedef enum +{ + HOOK_STATE_DISABLED, + HOOK_STATE_IDLE, + HOOK_STATE_GUARDED, + HOOK_STATE_ABORTED, + HOOK_STATE_RESTARTED, + HOOK_STATE_PASSING +} spi_hook_state_t; + + +_static spi_master_event_handler_t m_ser_phy_event_handler; +_static spi_master_hw_instance_t m_spi_master_hw_instance; +_static spi_hook_state_t m_hook_state = HOOK_STATE_DISABLED; +#endif + +#ifdef SER_PHY_DEBUG_APP_ENABLE +_static spi_master_raw_callback_t m_debug_callback; +#endif + +_static spi_master_instance_t m_spi_master_instances[SPI_MASTER_HW_ENABLED_COUNT]; + +static __INLINE spi_master_instance_t * spi_master_get_instance( + const spi_master_hw_instance_t spi_master_hw_instance); +static __INLINE void spi_master_send_recv_irq(spi_master_instance_t * const p_spi_instance); +static __INLINE void spi_master_signal_evt(spi_master_instance_t * const p_spi_instance, + spi_master_evt_type_t event_type, + const uint16_t data); + +#ifdef SPI_MASTER_0_ENABLE +/** + * @brief SPI0 interrupt handler. + */ +void SPI0_TWI0_IRQHandler(void) +{ + if (NRF_SPI0->EVENTS_READY != 0) + { + NRF_SPI0->EVENTS_READY = 0; + + spi_master_instance_t * p_spi_instance = spi_master_get_instance(SPI_MASTER_0); + + spi_master_send_recv_irq(p_spi_instance); + } +} +#endif //SPI_MASTER_0_ENABLE + +#ifdef SPI_MASTER_1_ENABLE +/** + * @brief SPI0 interrupt handler. + */ +void SPI1_TWI1_IRQHandler(void) +{ + if (NRF_SPI1->EVENTS_READY != 0) + { + NRF_SPI1->EVENTS_READY = 0; + + spi_master_instance_t * p_spi_instance = spi_master_get_instance(SPI_MASTER_1); + + spi_master_send_recv_irq(p_spi_instance); + } +} +#endif //SPI_MASTER_1_ENABLE + +#if defined(SPI_MASTER_0_ENABLE) || defined(SPI_MASTER_1_ENABLE) + +/**@brief Function for getting an instance of SPI master. */ +static __INLINE spi_master_instance_t * spi_master_get_instance( + const spi_master_hw_instance_t spi_master_hw_instance) +{ + return &(m_spi_master_instances[(uint8_t)spi_master_hw_instance]); +} + +/** @brief Function for initializing instance of SPI master by default values. */ +static __INLINE void spi_master_init_hw_instance(NRF_SPI_Type * p_nrf_spi, + IRQn_Type irq_type, + spi_master_instance_t * p_spi_instance) +{ + APP_ERROR_CHECK_BOOL(p_spi_instance != NULL); + + p_spi_instance->p_nrf_spi = p_nrf_spi; + p_spi_instance->irq_type = irq_type; + + p_spi_instance->p_tx_buffer = NULL; + p_spi_instance->tx_length = 0; + p_spi_instance->tx_index = 0; + + p_spi_instance->p_rx_buffer = NULL; + p_spi_instance->rx_length = 0; + p_spi_instance->rx_index = 0; + + p_spi_instance->bytes_count = 0; + p_spi_instance->max_length = 0; + p_spi_instance->pin_slave_select = 0; + + p_spi_instance->callback_event_handler = NULL; + + p_spi_instance->state = SPI_MASTER_STATE_DISABLED; + p_spi_instance->abort_flag = false; + p_spi_instance->start_flag = false; +} + +/**@brief Function for initializing TX or RX buffer. */ +static __INLINE void spi_master_buffer_init(uint8_t * const p_buf, + const uint16_t buf_len, + uint8_t * * pp_buf, + uint16_t * const p_buf_len, + uint16_t * const p_index) +{ + APP_ERROR_CHECK_BOOL(pp_buf != NULL); + APP_ERROR_CHECK_BOOL(p_buf_len != NULL); + APP_ERROR_CHECK_BOOL(p_index != NULL); + + *pp_buf = p_buf; + *p_buf_len = (p_buf != NULL) ? buf_len : 0; + *p_index = 0; +} + +/**@brief Function for releasing TX or RX buffer. */ +static __INLINE void spi_master_buffer_release(uint8_t * * const pp_buf, uint16_t * const p_buf_len) +{ + APP_ERROR_CHECK_BOOL(pp_buf != NULL); + APP_ERROR_CHECK_BOOL(p_buf_len != NULL); + + *pp_buf = NULL; + *p_buf_len = 0; +} + +/**@brief Function for sending events by callback. */ +static __INLINE void spi_master_signal_evt(spi_master_instance_t * const p_spi_instance, + spi_master_evt_type_t event_type, + const uint16_t data) +{ + APP_ERROR_CHECK_BOOL(p_spi_instance != NULL); + + if (p_spi_instance->callback_event_handler != NULL) + { + spi_master_evt_t event = {SPI_MASTER_EVT_TYPE_MAX, 0}; + event.type = event_type; + event.data = data; + p_spi_instance->callback_event_handler(event); + } +} + +/**@brief Function insert to a TX buffer another byte or two bytes (depends on flag @ref DOUBLE_BUFFERED). */ +static __INLINE void spi_master_send_initial_bytes(spi_master_instance_t * const p_spi_instance) +{ + APP_ERROR_CHECK_BOOL(p_spi_instance != NULL); + + p_spi_instance->p_nrf_spi->TXD = ((p_spi_instance->p_tx_buffer != NULL) && + (p_spi_instance->tx_index < p_spi_instance->tx_length)) ? + p_spi_instance->p_tx_buffer[p_spi_instance->tx_index] : + SPI_DEFAULT_TX_BYTE; + (p_spi_instance->tx_index)++; + + #ifdef DOUBLE_BUFFERED + + if (p_spi_instance->tx_index < p_spi_instance->max_length) + { + p_spi_instance->p_nrf_spi->TXD = ((p_spi_instance->p_tx_buffer != NULL) && + (p_spi_instance->tx_index < p_spi_instance->tx_length)) ? + p_spi_instance->p_tx_buffer[p_spi_instance->tx_index] : + SPI_DEFAULT_TX_BYTE; + (p_spi_instance->tx_index)++; + } + #endif +} + +/**@brief Function for receiving and sending data from IRQ. (The same for both IRQs). */ +static __INLINE void spi_master_send_recv_irq(spi_master_instance_t * const p_spi_instance) +{ + + uint8_t rx_byte; + + APP_ERROR_CHECK_BOOL(p_spi_instance != NULL); + APP_ERROR_CHECK_BOOL(p_spi_instance->state == SPI_MASTER_STATE_BUSY); + + p_spi_instance->bytes_count++; + rx_byte = p_spi_instance->p_nrf_spi->RXD; + + if (p_spi_instance->start_flag) + { + p_spi_instance->start_flag = false; + spi_master_signal_evt(p_spi_instance, SPI_MASTER_EVT_FIRST_BYTE_RECEIVED, (uint16_t)rx_byte); + } + else if (p_spi_instance->abort_flag ) //this is tricky, but callback for SPI_MASTER_EVT_FIRST_BYTE_RECEIVED will set this flag for a first byte, which is bad because there is still byte in a buffer + { //and for a single byte transaction you will get XFERDONE event to restart + p_spi_instance->abort_flag = false; + p_spi_instance->state = SPI_MASTER_STATE_ABORTED; + nrf_gpio_pin_set(p_spi_instance->pin_slave_select); + spi_master_signal_evt(p_spi_instance, SPI_MASTER_EVT_TRANSFER_ABORTED, 0); + return; + } + + if ((p_spi_instance->p_rx_buffer != NULL) && + (p_spi_instance->rx_index < p_spi_instance->rx_length)) + { + p_spi_instance->p_rx_buffer[p_spi_instance->rx_index++] = rx_byte; + } + + if ((p_spi_instance->tx_index < p_spi_instance->max_length) && (!(p_spi_instance->abort_flag))) //do not TX if you know that there is an abort to be done - this should work for a DOUBLE BUFFERING ??? + { + p_spi_instance->p_nrf_spi->TXD = ((p_spi_instance->p_tx_buffer != NULL) && + (p_spi_instance->tx_index < p_spi_instance->tx_length)) ? + p_spi_instance->p_tx_buffer[p_spi_instance->tx_index] : + SPI_DEFAULT_TX_BYTE; + (p_spi_instance->tx_index)++; + } + + if (p_spi_instance->bytes_count >= p_spi_instance->max_length) + { + APP_ERROR_CHECK_BOOL(p_spi_instance->bytes_count == p_spi_instance->max_length); + nrf_gpio_pin_set(p_spi_instance->pin_slave_select); + p_spi_instance->state = SPI_MASTER_STATE_IDLE; + spi_master_signal_evt(p_spi_instance, + SPI_MASTER_EVT_TRANSFER_COMPLETED, + p_spi_instance->tx_index); + } + return; +} +#endif //defined(SPI_MASTER_0_ENABLE) || defined(SPI_MASTER_1_ENABLE) + + +/** + * @brief Function for opening and initializing a SPI master driver. */ +uint32_t spi_master_open(const spi_master_hw_instance_t spi_master_hw_instance, + spi_master_config_t const * const p_spi_master_config) +{ + #if defined(SPI_MASTER_0_ENABLE) || defined(SPI_MASTER_1_ENABLE) + + + VERIFY_PARAM_NOT_NULL(p_spi_master_config); + + spi_master_instance_t * p_spi_instance = spi_master_get_instance(spi_master_hw_instance); + + switch (spi_master_hw_instance) + { + #ifdef SPI_MASTER_0_ENABLE + case SPI_MASTER_0: + spi_master_init_hw_instance(NRF_SPI0, SPI0_TWI0_IRQn, p_spi_instance); + break; + #endif //SPI_MASTER_0_ENABLE + + #ifdef SPI_MASTER_1_ENABLE + case SPI_MASTER_1: + spi_master_init_hw_instance(NRF_SPI1, SPI1_TWI1_IRQn, p_spi_instance); + break; + #endif //SPI_MASTER_1_ENABLE + + default: + break; + } + + //A Slave select must be set as high before setting it as output, + //because during connect it to the pin it causes glitches. + nrf_gpio_pin_set(p_spi_master_config->SPI_Pin_SS); + nrf_gpio_cfg_output(p_spi_master_config->SPI_Pin_SS); + nrf_gpio_pin_set(p_spi_master_config->SPI_Pin_SS); + + //Configure GPIO + nrf_gpio_cfg_output(p_spi_master_config->SPI_Pin_SCK); + nrf_gpio_cfg_output(p_spi_master_config->SPI_Pin_MOSI); + nrf_gpio_cfg_input(p_spi_master_config->SPI_Pin_MISO, NRF_GPIO_PIN_NOPULL); + p_spi_instance->pin_slave_select = p_spi_master_config->SPI_Pin_SS; + + /* Configure SPI hardware */ + p_spi_instance->p_nrf_spi->PSELSCK = p_spi_master_config->SPI_Pin_SCK; + p_spi_instance->p_nrf_spi->PSELMOSI = p_spi_master_config->SPI_Pin_MOSI; + p_spi_instance->p_nrf_spi->PSELMISO = p_spi_master_config->SPI_Pin_MISO; + + p_spi_instance->p_nrf_spi->FREQUENCY = p_spi_master_config->SPI_Freq; + + p_spi_instance->p_nrf_spi->CONFIG = + (uint32_t)(p_spi_master_config->SPI_CPHA << SPI_CONFIG_CPHA_Pos) | + (p_spi_master_config->SPI_CPOL << SPI_CONFIG_CPOL_Pos) | + (p_spi_master_config->SPI_ORDER << SPI_CONFIG_ORDER_Pos); + + + /* Clear waiting interrupts and events */ + p_spi_instance->p_nrf_spi->EVENTS_READY = 0; + + NVIC_ClearPendingIRQ(p_spi_instance->irq_type); + NVIC_SetPriority(p_spi_instance->irq_type, APP_IRQ_PRIORITY_MID); + + /* Clear event handler */ + p_spi_instance->callback_event_handler = NULL; + + /* Enable interrupt */ + p_spi_instance->p_nrf_spi->INTENSET = (SPI_INTENSET_READY_Set << SPI_INTENCLR_READY_Pos); + NVIC_EnableIRQ(p_spi_instance->irq_type); + + /* Enable SPI hardware */ + p_spi_instance->p_nrf_spi->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); + + /* Change state to IDLE */ + p_spi_instance->state = SPI_MASTER_STATE_IDLE; + + return NRF_SUCCESS; + #else + return NRF_ERROR_NOT_SUPPORTED; + #endif +} + +/** + * @brief Function for closing a SPI master driver. + */ +void spi_master_close(const spi_master_hw_instance_t spi_master_hw_instance) +{ + #if defined(SPI_MASTER_0_ENABLE) || defined(SPI_MASTER_1_ENABLE) + spi_master_instance_t * p_spi_instance = spi_master_get_instance(spi_master_hw_instance); + + /* Disable interrupt */ + NVIC_ClearPendingIRQ(p_spi_instance->irq_type); + NVIC_DisableIRQ(p_spi_instance->irq_type); + + p_spi_instance->p_nrf_spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos); + + /* Set Slave Select pin as input with pull-up. */ + nrf_gpio_pin_set(p_spi_instance->pin_slave_select); + nrf_gpio_cfg_input(p_spi_instance->pin_slave_select, NRF_GPIO_PIN_PULLUP); + p_spi_instance->pin_slave_select = (uint8_t)0xFF; + + /* Disconnect pins from SPI hardware */ + p_spi_instance->p_nrf_spi->PSELSCK = (uint32_t)SPI_PIN_DISCONNECTED; + p_spi_instance->p_nrf_spi->PSELMOSI = (uint32_t)SPI_PIN_DISCONNECTED; + p_spi_instance->p_nrf_spi->PSELMISO = (uint32_t)SPI_PIN_DISCONNECTED; + + /* Reset to default values */ + spi_master_init_hw_instance(NULL, (IRQn_Type)0, p_spi_instance); + #else + return; + #endif +} + +/** + * @brief Function for getting current state of the SPI master driver. + */ +__INLINE spi_master_state_t spi_master_get_state( + const spi_master_hw_instance_t spi_master_hw_instance) +{ + #if defined(SPI_MASTER_0_ENABLE) || defined(SPI_MASTER_1_ENABLE) + spi_master_instance_t * spi_instance = spi_master_get_instance(spi_master_hw_instance); + return spi_instance->state; + #else + return SPI_MASTER_STATE_DISABLED; + #endif +} + +/** + * @brief Function for event handler registration. + */ +__INLINE void spi_master_evt_handler_reg(const spi_master_hw_instance_t spi_master_hw_instance, + spi_master_event_handler_t event_handler) +{ + #if defined(SPI_MASTER_0_ENABLE) || defined(SPI_MASTER_1_ENABLE) + spi_master_instance_t * spi_instance = spi_master_get_instance(spi_master_hw_instance); + spi_instance->callback_event_handler = event_handler; + #else + return; + #endif +} + +/** + * @brief Function for transmitting data between SPI master and SPI slave. + */ +uint32_t spi_master_send_recv(const spi_master_hw_instance_t spi_master_hw_instance, + uint8_t * const p_tx_buf, const uint16_t tx_buf_len, + uint8_t * const p_rx_buf, const uint16_t rx_buf_len) +{ + #if defined(SPI_MASTER_0_ENABLE) || defined(SPI_MASTER_1_ENABLE) + spi_master_instance_t * p_spi_instance = spi_master_get_instance(spi_master_hw_instance); + + uint32_t err_code = NRF_SUCCESS; + uint16_t max_length = 0; + + if (p_spi_instance->state == SPI_MASTER_STATE_IDLE) + { + NVIC_DisableIRQ(p_spi_instance->irq_type); + + max_length = (rx_buf_len > tx_buf_len) ? rx_buf_len : tx_buf_len; + + if (max_length > 0) + { + p_spi_instance->state = SPI_MASTER_STATE_BUSY; + p_spi_instance->start_flag = true; //abort_flag should set by abort and cleared only by restart + p_spi_instance->bytes_count = 0; + p_spi_instance->max_length = max_length; + spi_master_buffer_release(&(p_spi_instance->p_tx_buffer), &(p_spi_instance->tx_length)); + spi_master_buffer_release(&(p_spi_instance->p_rx_buffer), &(p_spi_instance->rx_length)); + /* Initialize buffers */ + spi_master_buffer_init(p_tx_buf, tx_buf_len, &(p_spi_instance->p_tx_buffer), + &(p_spi_instance->tx_length), &(p_spi_instance->tx_index)); + spi_master_buffer_init(p_rx_buf, rx_buf_len, &(p_spi_instance->p_rx_buffer), + &(p_spi_instance->rx_length), &(p_spi_instance->rx_index)); + nrf_gpio_pin_clear(p_spi_instance->pin_slave_select); + spi_master_send_initial_bytes(p_spi_instance); + spi_master_signal_evt(p_spi_instance, SPI_MASTER_EVT_TRANSFER_STARTED, max_length); + } + else + { + err_code = NRF_ERROR_INVALID_PARAM; + } + + NVIC_EnableIRQ(p_spi_instance->irq_type); + } + else + { + err_code = NRF_ERROR_BUSY; + } + + return err_code; + #else + return NRF_ERROR_NOT_SUPPORTED; + #endif +} + +#ifdef _SPI_5W_ + +/** + * @brief Function for aborting transfer + */ +uint32_t spi_master_abort(const spi_master_hw_instance_t spi_master_hw_instance) +{ + spi_master_instance_t * p_spi_instance = spi_master_get_instance(spi_master_hw_instance); + + NVIC_DisableIRQ(p_spi_instance->irq_type); + + if (p_spi_instance->state == SPI_MASTER_STATE_BUSY) + { + //set_flag - but only when there are events pending + //ignore when in IDLE - must be able to restart a completed transfer + p_spi_instance->abort_flag = true; + } + NVIC_EnableIRQ(p_spi_instance->irq_type); + return NRF_SUCCESS; +} + +/** + * @brief Function for restarting transfer + */ +uint32_t spi_master_restart(const spi_master_hw_instance_t spi_master_hw_instance) +{ + spi_master_instance_t * p_spi_instance = spi_master_get_instance(spi_master_hw_instance); + + NVIC_DisableIRQ(p_spi_instance->irq_type); + spi_master_signal_evt(p_spi_instance, SPI_MASTER_EVT_TRANSFER_RESTARTED, 0); + p_spi_instance->state = SPI_MASTER_STATE_BUSY; + p_spi_instance->bytes_count = 0; + p_spi_instance->tx_index = 0; + p_spi_instance->rx_index = 0; + p_spi_instance->start_flag = true; + p_spi_instance->abort_flag = false; //you should force clearing abort flag - no other way for 1 byte transfer + nrf_gpio_pin_clear(p_spi_instance->pin_slave_select); + spi_master_send_initial_bytes(p_spi_instance); + NVIC_EnableIRQ(p_spi_instance->irq_type); + + return NRF_SUCCESS; +} + +static void spi_5W_master_event_handler(spi_master_evt_t evt) +{ + + switch (m_hook_state) + { + case HOOK_STATE_IDLE: + + if (evt.type == SPI_MASTER_EVT_TRANSFER_STARTED) + { + DEBUG_EVT_SPI_MASTER_RAW_XFER_GUARDED(0); + m_hook_state = HOOK_STATE_GUARDED; + m_ser_phy_event_handler(evt); + } + break; + + case HOOK_STATE_GUARDED: + + if (evt.type == SPI_MASTER_EVT_FIRST_BYTE_RECEIVED) + { + if (evt.data == 0) + { + DEBUG_EVT_SPI_MASTER_RAW_XFER_PASSED(0); + m_hook_state = HOOK_STATE_PASSING; + } + else + { + DEBUG_EVT_SPI_MASTER_RAW_XFER_ABORTED(0); + m_hook_state = HOOK_STATE_ABORTED; + (void)spi_master_abort(m_spi_master_hw_instance); + } + } + break; + + case HOOK_STATE_ABORTED: + + if ((evt.type == SPI_MASTER_EVT_TRANSFER_ABORTED) || + (evt.type == SPI_MASTER_EVT_TRANSFER_COMPLETED)) + { + DEBUG_EVT_SPI_MASTER_RAW_XFER_RESTARTED(0); + m_hook_state = HOOK_STATE_RESTARTED; + (void)spi_master_restart(m_spi_master_hw_instance); + } + break; + + case HOOK_STATE_RESTARTED: + + if (evt.type == SPI_MASTER_EVT_TRANSFER_RESTARTED) + { + DEBUG_EVT_SPI_MASTER_RAW_XFER_GUARDED(0); + m_hook_state = HOOK_STATE_GUARDED; + } + break; + + case HOOK_STATE_PASSING: + + if (evt.type == SPI_MASTER_EVT_TRANSFER_COMPLETED) + { + m_hook_state = HOOK_STATE_IDLE; + m_ser_phy_event_handler(evt); //this is the only way to get a signal from complete transaction + } + break; + + default: + break; + } +} + +void spi_5W_master_evt_handler_reg(const spi_master_hw_instance_t spi_master_hw_instance, + spi_master_event_handler_t event_handler) +{ + m_ser_phy_event_handler = event_handler; + m_spi_master_hw_instance = spi_master_hw_instance; + m_hook_state = HOOK_STATE_IDLE; + spi_master_evt_handler_reg(spi_master_hw_instance, spi_5W_master_event_handler); + return; +} + +#endif + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/spi_master/spi_5W_master.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/spi_master/spi_5W_master.h new file mode 100644 index 0000000..a0017c5 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/spi_master/spi_5W_master.h @@ -0,0 +1,206 @@ +/** + * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef APP_SPI_MASTER_H +#define APP_SPI_MASTER_H + +#include <stdint.h> +#include <stdlib.h> +#include "boards.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define _SPI_5W_ + +/**@brief Struct containing configuration parameters of the SPI master. */ +typedef struct +{ + uint32_t SPI_Freq; /**< SPI frequency. */ + uint32_t SPI_Pin_SCK; /**< SCK pin number. */ + uint32_t SPI_Pin_MISO; /**< MISO pin number. */ + uint32_t SPI_Pin_MOSI; /**< MOSI pin number .*/ + uint32_t SPI_Pin_SS; /**< Slave select pin number. */ + uint8_t SPI_ORDER; /**< Bytes order MSBFIRST or LSBFIRST. */ + uint8_t SPI_CPOL; /**< Serial clock polarity ACTIVEHIGH or ACTIVELOW. */ + uint8_t SPI_CPHA; /**< Serial clock phase LEADING or TRAILING. */ + } spi_master_config_t; + +/**@brief SPI master driver events types. */ +typedef enum +{ + SPI_MASTER_EVT_TRANSFER_STARTED = 0, /**< An event indicating that transfer has been started */ + SPI_MASTER_EVT_TRANSFER_COMPLETED, /**< An event indicating that transfer has been completed */ + SPI_MASTER_EVT_TRANSFER_ABORTED, /**< An event indicating that transfer has been aborted */ + SPI_MASTER_EVT_TRANSFER_RESTARTED, /**< An event indicating that transfer has been resumed */ + SPI_MASTER_EVT_FIRST_BYTE_RECEIVED, /**< An event indicating end of one byte transfer */ + SPI_MASTER_EVT_TYPE_MAX /**< Enumeration upper bound. */ +} spi_master_evt_type_t; + +/**@brief Struct containing parameters of the SPI MASTER event */ + typedef struct + { + spi_master_evt_type_t type; /**< Type of an event */ + uint16_t data; /**< event data - context dependent */ + } spi_master_evt_t; + + /**@brief SPI MASTER internal states types. */ + typedef enum + { + SPI_MASTER_STATE_DISABLED, /**< A state indicating that SPI master is disabled. */ + SPI_MASTER_STATE_BUSY, /**< A state indicating that SPI master is sending now. */ + SPI_MASTER_STATE_ABORTED, + SPI_MASTER_STATE_IDLE /**< A state indicating that SPI master is idle now. */ + } spi_master_state_t; + + /**@brief Instances of SPI master module. */ + typedef enum + { + #ifdef SPI_MASTER_0_ENABLE + SPI_MASTER_0, /**< A instance of SPI master 0. */ + #endif + + #ifdef SPI_MASTER_1_ENABLE + SPI_MASTER_1, /**< A instance of SPI master 1. */ + #endif + + SPI_MASTER_HW_ENABLED_COUNT /**< A number of enabled instances of SPI master. */ + } spi_master_hw_instance_t; + +/**@brief Type of generic callback function handler to be used by all SPI MASTER driver events. + * + * @param[in] spi_master_evt SPI MASTER driver event. + */ +typedef void (*spi_master_event_handler_t) (spi_master_evt_t spi_master_evt); + + +/**@brief Function for opening and initializing a SPI master driver. + * + * @note Function initializes SPI master hardware and internal module states, unregister events callback. + * + * @warning If the function has been already called, the function @ref spi_master_close has to be + * called before spi_master_open can be called again. + * + * @param[in] spi_master_hw_instance Instance of SPI master module. + * @param[in] p_spi_master_config Pointer to configuration structure which will be used + * to initialize SPI MASTER hardware. + * + * @retval NRF_SUCCESS Operation success. + * @retval NRF_ERROR_INVALID_STATE Operation failure. The function has been already called. + * To call it again the function @ref spi_master_close + * has to be called previously. + * @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied. + */ +uint32_t spi_master_open(const spi_master_hw_instance_t spi_master_hw_instance, + spi_master_config_t const * const p_spi_master_config); + + +/**@brief Function for closing a SPI MASTER driver. + * + * @note Function disable hardware, reset internal module states and unregister events callback + * function. + * + * @param[in] spi_master_hw_instance A instance of SPI master. + */ +void spi_master_close(const spi_master_hw_instance_t spi_master_hw_instance); + + +/**@brief Function for transferring data between SPI master and SPI slave + * + * @note Function registers buffers pointed by p_tx_buf and p_rx_buf parameters, after that starts transmission. + * Function generates an event of type @ref SPI_MASTER_EVT_TRANSFER_STARTED when transfer has been started + * and @ref SPI_MASTER_EVT_TRANSFER_COMPLETED when transfer has been completed. + * + * @param[in] spi_master_hw_instance Instance of SPI master module. + * @param[in] p_tx_buf Pointer to a transmit buffer. + * @param[in] tx_buf_len Number of octets to the transfer. + * @param[out] p_rx_buf Pointer to a receive buffer. + * @param[in] rx_buf_len Number of octets to be received. + * + * @retval NRF_SUCCESS Operation success. Packet was registered to the transmission + * and event will be send upon transmission completion. + * @retval NRF_ERROR_BUSY Operation failure. Transmitting of a data is in progress. + */ + uint32_t spi_master_send_recv(const spi_master_hw_instance_t spi_master_hw_instance, + uint8_t * const p_tx_buf, const uint16_t tx_buf_len, + uint8_t * const p_rx_buf, const uint16_t rx_buf_len); + + +/**@brief Function for registration event handler. +* +* @note Function registers a event handler to be used by SPI MASTER driver for sending events. +* @ref SPI_MASTER_EVT_TRANSFER_STARTED and @ref SPI_MASTER_EVT_TRANSFER_COMPLETED. +* +* @param[in] spi_master_hw_instance Instance of SPI master module. +* @param[in] event_handler Generic callback function handler to be used +* by all SPI master driver events. +*/ +void spi_master_evt_handler_reg(const spi_master_hw_instance_t spi_master_hw_instance, + spi_master_event_handler_t event_handler); + + +/**@brief Function for getting current state of the SPI master driver. + * + * @note Function gets current state of the SPI master driver. + * + * @param[in] spi_master_hw_instance Instance of SPI master module. + * + * @retval SPI_MASTER_STATE_DISABLED SPI MASTER is disabled. + * @retval SPI_MASTER_STATE_BUSY SPI_MASTER is sending now. + * @retval SPI_MASTER_STATE_IDLE SPI_MASTER is idle now. + */ +spi_master_state_t spi_master_get_state(const spi_master_hw_instance_t spi_master_hw_instance); + +#ifdef _SPI_5W_ + +uint32_t spi_master_abort(const spi_master_hw_instance_t spi_master_hw_instance); + +uint32_t spi_master_restart(const spi_master_hw_instance_t spi_master_hw_instance); + +void spi_5W_master_evt_handler_reg(const spi_master_hw_instance_t spi_master_hw_instance, + spi_master_event_handler_t event_handler); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/config/twi_master_config.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/config/twi_master_config.h new file mode 100644 index 0000000..9c182e6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/config/twi_master_config.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef TWI_MASTER_CONFIG +#define TWI_MASTER_CONFIG + +#ifdef __cplusplus +extern "C" { +#endif + +#define TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER (24U) +#define TWI_MASTER_CONFIG_DATA_PIN_NUMBER (25U) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_hw_master.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_hw_master.c new file mode 100644 index 0000000..e3692a3 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_hw_master.c @@ -0,0 +1,331 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "twi_master.h" +#include "twi_master_config.h" +#include <stdbool.h> +#include <stdint.h> +#include "nrf.h" +#include "nrf_delay.h" +#include "nrf_gpio.h" + +/* Max cycles approximately to wait on RXDREADY and TXDREADY event, + * This is optimized way instead of using timers, this is not power aware. */ +#define MAX_TIMEOUT_LOOPS (20000UL) /**< MAX while loops to wait for RXD/TXD event */ + +static bool twi_master_write(uint8_t * data, uint8_t data_length, bool issue_stop_condition) +{ + uint32_t timeout = MAX_TIMEOUT_LOOPS; /* max loops to wait for EVENTS_TXDSENT event*/ + + if (data_length == 0) + { + /* Return false for requesting data of size 0 */ + return false; + } + + NRF_TWI1->TXD = *data++; + NRF_TWI1->TASKS_STARTTX = 1; + + /** @snippet [TWI HW master write] */ + while (true) + { + while (NRF_TWI1->EVENTS_TXDSENT == 0 && NRF_TWI1->EVENTS_ERROR == 0 && (--timeout)) + { + // Do nothing. + } + + if (timeout == 0 || NRF_TWI1->EVENTS_ERROR != 0) + { + // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at + // Product Anomaly Notification document found at + // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads + NRF_TWI1->EVENTS_ERROR = 0; + NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; + NRF_TWI1->POWER = 0; + nrf_delay_us(5); + NRF_TWI1->POWER = 1; + NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos; + + (void)twi_master_init(); + + return false; + } + NRF_TWI1->EVENTS_TXDSENT = 0; + if (--data_length == 0) + { + break; + } + + NRF_TWI1->TXD = *data++; + } + /** @snippet [TWI HW master write] */ + + if (issue_stop_condition) + { + NRF_TWI1->EVENTS_STOPPED = 0; + NRF_TWI1->TASKS_STOP = 1; + /* Wait until stop sequence is sent */ + while (NRF_TWI1->EVENTS_STOPPED == 0) + { + // Do nothing. + } + } + return true; +} + + +/** @brief Function for read by twi_master. + */ +static bool twi_master_read(uint8_t * data, uint8_t data_length, bool issue_stop_condition) +{ + uint32_t timeout = MAX_TIMEOUT_LOOPS; /* max loops to wait for RXDREADY event*/ + + if (data_length == 0) + { + /* Return false for requesting data of size 0 */ + return false; + } + else if (data_length == 1) + { + NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_STOP; + } + else + { + NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_SUSPEND; + } + + NRF_PPI->CHENSET = PPI_CHENSET_CH0_Msk; + NRF_TWI1->EVENTS_RXDREADY = 0; + NRF_TWI1->TASKS_STARTRX = 1; + + /** @snippet [TWI HW master read] */ + while (true) + { + while (NRF_TWI1->EVENTS_RXDREADY == 0 && NRF_TWI1->EVENTS_ERROR == 0 && (--timeout)) + { + // Do nothing. + } + NRF_TWI1->EVENTS_RXDREADY = 0; + + if (timeout == 0 || NRF_TWI1->EVENTS_ERROR != 0) + { + // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at + // Product Anomaly Notification document found at + // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads + NRF_TWI1->EVENTS_ERROR = 0; + NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; + NRF_TWI1->POWER = 0; + nrf_delay_us(5); + NRF_TWI1->POWER = 1; + NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos; + + (void)twi_master_init(); + + return false; + } + + *data++ = NRF_TWI1->RXD; + + /* Configure PPI to stop TWI master before we get last BB event */ + if (--data_length == 1) + { + NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_STOP; + } + + if (data_length == 0) + { + break; + } + + // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at + // Product Anomaly Notification document found at + // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads + nrf_delay_us(20); + NRF_TWI1->TASKS_RESUME = 1; + } + /** @snippet [TWI HW master read] */ + + /* Wait until stop sequence is sent */ + while (NRF_TWI1->EVENTS_STOPPED == 0) + { + // Do nothing. + } + NRF_TWI1->EVENTS_STOPPED = 0; + + NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk; + return true; +} + + +/** + * @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 bool twi_master_clear_bus(void) +{ + uint32_t twi_state; + bool bus_clear; + uint32_t clk_pin_config; + uint32_t data_pin_config; + + // Save and disable TWI hardware so software can take control over the pins. + twi_state = NRF_TWI1->ENABLE; + NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; + + clk_pin_config = \ + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER]; + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = \ + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ + | (GPIO_PIN_CNF_DRIVE_S0D1 << 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_Output << GPIO_PIN_CNF_DIR_Pos); + + data_pin_config = \ + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER]; + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = \ + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ + | (GPIO_PIN_CNF_DRIVE_S0D1 << 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_Output << GPIO_PIN_CNF_DIR_Pos); + + TWI_SDA_HIGH(); + TWI_SCL_HIGH(); + TWI_DELAY(); + + if ((TWI_SDA_READ() == 1) && (TWI_SCL_READ() == 1)) + { + bus_clear = true; + } + else + { + uint_fast8_t i; + bus_clear = false; + + // Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9 + // for slave to respond) to SCL line and wait for SDA come high. + for (i=18; i--;) + { + TWI_SCL_LOW(); + TWI_DELAY(); + TWI_SCL_HIGH(); + TWI_DELAY(); + + if (TWI_SDA_READ() == 1) + { + bus_clear = true; + break; + } + } + } + + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = clk_pin_config; + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = data_pin_config; + + NRF_TWI1->ENABLE = twi_state; + + return bus_clear; +} + + +/** @brief Function for initializing the twi_master. + */ +bool twi_master_init(void) +{ + /* To secure correct signal levels on the pins used by the TWI + master when the system is in OFF mode, and when the TWI master is + disabled, these pins must be configured in the GPIO peripheral. + */ + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = \ + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ + | (GPIO_PIN_CNF_DRIVE_S0D1 << 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); + + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = \ + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ + | (GPIO_PIN_CNF_DRIVE_S0D1 << 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); + + NRF_TWI1->EVENTS_RXDREADY = 0; + NRF_TWI1->EVENTS_TXDSENT = 0; + NRF_TWI1->PSELSCL = TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER; + NRF_TWI1->PSELSDA = TWI_MASTER_CONFIG_DATA_PIN_NUMBER; + NRF_TWI1->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K100 << TWI_FREQUENCY_FREQUENCY_Pos; + NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TWI1->EVENTS_BB; + NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_SUSPEND; + NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk; + NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos; + + return twi_master_clear_bus(); +} + + +/** @brief Function for transfer by twi_master. + */ +bool twi_master_transfer(uint8_t address, + uint8_t * data, + uint8_t data_length, + bool issue_stop_condition) +{ + bool transfer_succeeded = false; + if (data_length > 0 && twi_master_clear_bus()) + { + NRF_TWI1->ADDRESS = (address >> 1); + + if ((address & TWI_READ_BIT)) + { + transfer_succeeded = twi_master_read(data, data_length, issue_stop_condition); + } + else + { + transfer_succeeded = twi_master_write(data, data_length, issue_stop_condition); + } + } + return transfer_succeeded; +} + +/*lint --flb "Leave library region" */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_master.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_master.h new file mode 100644 index 0000000..3cd975e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_master.h @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef TWI_MASTER_H +#define TWI_MASTER_H + +/*lint ++flb "Enter library region" */ + +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file +* @brief Software controlled TWI Master driver. +* +* +* @defgroup lib_driver_twi_master Software controlled TWI Master driver +* @{ +* @ingroup nrf_twi +* @brief Software controlled TWI Master driver (deprecated). +* +* @warning This module is deprecated. +* +* Supported features: +* - Repeated start +* - No multi-master +* - Only 7-bit addressing +* - Supports clock stretching (with optional SMBus style slave timeout) +* - Tries to handle slaves stuck in the middle of transfer +*/ + +#define TWI_READ_BIT (0x01) //!< If this bit is set in the address field, transfer direction is from slave to master. + +#define TWI_ISSUE_STOP ((bool)true) //!< Parameter for @ref twi_master_transfer +#define TWI_DONT_ISSUE_STOP ((bool)false) //!< Parameter for @ref twi_master_transfer + +/* These macros are needed to see if the slave is stuck and we as master send dummy clock cycles to end its wait */ +/*lint -e717 -save "Suppress do {} while (0) for these macros" */ +/*lint ++flb "Enter library region" */ +#define TWI_SCL_HIGH() do { NRF_GPIO->OUTSET = (1UL << TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Pulls SCL line high */ +#define TWI_SCL_LOW() do { NRF_GPIO->OUTCLR = (1UL << TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Pulls SCL line low */ +#define TWI_SDA_HIGH() do { NRF_GPIO->OUTSET = (1UL << TWI_MASTER_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Pulls SDA line high */ +#define TWI_SDA_LOW() do { NRF_GPIO->OUTCLR = (1UL << TWI_MASTER_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Pulls SDA line low */ +#define TWI_SDA_INPUT() do { NRF_GPIO->DIRCLR = (1UL << TWI_MASTER_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Configures SDA pin as input */ +#define TWI_SDA_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << TWI_MASTER_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Configures SDA pin as output */ +#define TWI_SCL_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Configures SCL pin as output */ +/*lint -restore */ + +#define TWI_SDA_READ() ((NRF_GPIO->IN >> TWI_MASTER_CONFIG_DATA_PIN_NUMBER) & 0x1UL) /*!< Reads current state of SDA */ +#define TWI_SCL_READ() ((NRF_GPIO->IN >> TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER) & 0x1UL) /*!< Reads current state of SCL */ + +#define TWI_DELAY() nrf_delay_us(4) /*!< Time to wait when pin states are changed. For fast-mode the delay can be zero and for standard-mode 4 us delay is sufficient. */ + + +/** + * @brief Function for initializing TWI bus IO pins and checks if the bus is operational. + * + * Both pins are configured as Standard-0, No-drive-1 (open drain). + * + * @return + * @retval true TWI bus is clear for transfers. + * @retval false TWI bus is stuck. + */ +bool twi_master_init(void); + +/** + * @brief Function for transferring data over TWI bus. + * + * If TWI master detects even one NACK from the slave or timeout occurs, STOP condition is issued + * and the function returns false. + * Bit 0 (@ref TWI_READ_BIT) in the address parameter controls transfer direction; + * - If 1, master reads data_length number of bytes from the slave + * - If 0, master writes data_length number of bytes to the slave. + * + * @note Make sure at least data_length number of bytes is allocated in data if TWI_READ_BIT is set. + * @note @ref TWI_ISSUE_STOP + * + * @param address Data transfer direction (LSB) / Slave address (7 MSBs). + * @param data Pointer to data. + * @param data_length Number of bytes to transfer. + * @param issue_stop_condition If @ref TWI_ISSUE_STOP, STOP condition is issued before exiting function. If @ref TWI_DONT_ISSUE_STOP, STOP condition is not issued before exiting function. If transfer failed for any reason, STOP condition will be issued in any case. + * @return + * @retval true Data transfer succeeded without errors. + * @retval false Data transfer failed. + */ +bool twi_master_transfer(uint8_t address, uint8_t *data, uint8_t data_length, bool issue_stop_condition); + +/** + *@} + **/ + +/*lint --flb "Leave library region" */ + +#ifdef __cplusplus +} +#endif + +#endif //TWI_MASTER_H diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_sw_master.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_sw_master.c new file mode 100644 index 0000000..115e997 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/twi_master/deprecated/twi_sw_master.c @@ -0,0 +1,519 @@ +/** + * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdbool.h> +#include <stdint.h> +#include "twi_master.h" +#include "nrf_delay.h" + +#include "twi_master_config.h" + +/*lint -e415 -e845 -save "Out of bounds access" */ +#define TWI_SDA_STANDARD0_NODRIVE1() do { \ + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ + |(GPIO_PIN_CNF_DRIVE_S0D1 << 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); \ +} while (0) /*!< Configures SDA pin to Standard-0, No-drive 1 */ + + +#define TWI_SCL_STANDARD0_NODRIVE1() do { \ + NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ + |(GPIO_PIN_CNF_DRIVE_S0D1 << 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); \ +} while (0) /*!< Configures SCL pin to Standard-0, No-drive 1 */ + + +/*lint -restore */ + +#ifndef TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE +#define TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE (0UL) //!< Unit is number of empty loops. Timeout for SMBus devices is 35 ms. Set to zero to disable slave timeout altogether. +#endif + +static bool twi_master_clear_bus(void); +static bool twi_master_issue_startcondition(void); +static bool twi_master_issue_stopcondition(void); +static bool twi_master_clock_byte(uint_fast8_t databyte); +static bool twi_master_clock_byte_in(uint8_t * databyte, bool ack); +static bool twi_master_wait_while_scl_low(void); + +bool twi_master_init(void) +{ + // Configure both pins to output Standard 0, No-drive (open-drain) 1 + TWI_SDA_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */ + TWI_SCL_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */ + + // Configure SCL as output + TWI_SCL_HIGH(); + TWI_SCL_OUTPUT(); + + // Configure SDA as output + TWI_SDA_HIGH(); + TWI_SDA_OUTPUT(); + + return twi_master_clear_bus(); +} + +bool twi_master_transfer(uint8_t address, uint8_t * data, uint8_t data_length, bool issue_stop_condition) +{ + bool transfer_succeeded = true; + + transfer_succeeded &= twi_master_issue_startcondition(); + transfer_succeeded &= twi_master_clock_byte(address); + + if (address & TWI_READ_BIT) + { + /* Transfer direction is from Slave to Master */ + while (data_length-- && transfer_succeeded) + { + // To indicate to slave that we've finished transferring last data byte + // we need to NACK the last transfer. + if (data_length == 0) + { + transfer_succeeded &= twi_master_clock_byte_in(data, (bool)false); + } + else + { + transfer_succeeded &= twi_master_clock_byte_in(data, (bool)true); + } + data++; + } + } + else + { + /* Transfer direction is from Master to Slave */ + while (data_length-- && transfer_succeeded) + { + transfer_succeeded &= twi_master_clock_byte(*data); + data++; + } + } + + if (issue_stop_condition || !transfer_succeeded) + { + transfer_succeeded &= twi_master_issue_stopcondition(); + } + + return transfer_succeeded; +} + +/** + * @brief Function for detecting stuck slaves and tries to clear the bus. + * + * @return + * @retval false Bus is stuck. + * @retval true Bus is clear. + */ +static bool twi_master_clear_bus(void) +{ + bool bus_clear; + + TWI_SDA_HIGH(); + TWI_SCL_HIGH(); + TWI_DELAY(); + + + if (TWI_SDA_READ() == 1 && TWI_SCL_READ() == 1) + { + bus_clear = true; + } + else if (TWI_SCL_READ() == 1) + { + bus_clear = false; + // Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9 for slave to respond) to SCL line and wait for SDA come high + for (uint_fast8_t i = 18; i--;) + { + TWI_SCL_LOW(); + TWI_DELAY(); + TWI_SCL_HIGH(); + TWI_DELAY(); + + if (TWI_SDA_READ() == 1) + { + bus_clear = true; + break; + } + } + } + else + { + bus_clear = false; + } + + return bus_clear; +} + +/** + * @brief Function for issuing TWI START condition to the bus. + * + * START condition is signaled by pulling SDA low while SCL is high. After this function SCL and SDA will be low. + * + * @return + * @retval false Timeout detected + * @retval true Clocking succeeded + */ +static bool twi_master_issue_startcondition(void) +{ +#if 0 + if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 1) + { + // Pull SDA low + TWI_SDA_LOW(); + } + else if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 0) + { + // Issue Stop by pulling SDA high + TWI_SDA_HIGH(); + TWI_DELAY(); + + // Then Start by pulling SDA low + TWI_SDA_LOW(); + } + else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 0) + { + // First pull SDA high + TWI_SDA_HIGH(); + + // Then SCL high + if (!twi_master_wait_while_scl_low()) + { + return false; + } + + // Then SDA low + TWI_SDA_LOW(); + } + else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 1) + { + // SCL high + if (!twi_master_wait_while_scl_low()) + { + return false; + } + + // Then SDA low + TWI_SDA_LOW(); + } + + TWI_DELAY(); + TWI_SCL_LOW(); +#endif + + // Make sure both SDA and SCL are high before pulling SDA low. + TWI_SDA_HIGH(); + TWI_DELAY(); + if (!twi_master_wait_while_scl_low()) + { + return false; + } + + TWI_SDA_LOW(); + TWI_DELAY(); + + // Other module function expect SCL to be low + TWI_SCL_LOW(); + TWI_DELAY(); + + return true; +} + +/** + * @brief Function for issuing TWI STOP condition to the bus. + * + * STOP condition is signaled by pulling SDA high while SCL is high. After this function SDA and SCL will be high. + * + * @return + * @retval false Timeout detected + * @retval true Clocking succeeded + */ +static bool twi_master_issue_stopcondition(void) +{ +#if 0 + if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 1) + { + // Issue start, then issue stop + + // Pull SDA low to issue START + TWI_SDA_LOW(); + TWI_DELAY(); + + // Pull SDA high while SCL is high to issue STOP + TWI_SDA_HIGH(); + } + else if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 0) + { + // Pull SDA high while SCL is high to issue STOP + TWI_SDA_HIGH(); + } + else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 0) + { + if (!twi_master_wait_while_scl_low()) + { + return false; + } + + // Pull SDA high while SCL is high to issue STOP + TWI_SDA_HIGH(); + } + else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 1) + { + TWI_SDA_LOW(); + TWI_DELAY(); + + // SCL high + if (!twi_master_wait_while_scl_low()) + { + return false; + } + + // Pull SDA high while SCL is high to issue STOP + TWI_SDA_HIGH(); + } + + TWI_DELAY(); +#endif + + TWI_SDA_LOW(); + TWI_DELAY(); + if (!twi_master_wait_while_scl_low()) + { + return false; + } + + TWI_SDA_HIGH(); + TWI_DELAY(); + + return true; +} + +/** + * @brief Function for clocking one data byte out and reads slave acknowledgment. + * + * Can handle clock stretching. + * After calling this function SCL is low and SDA low/high depending on the + * value of LSB of the data byte. + * SCL is expected to be output and low when entering this function. + * + * @param databyte Data byte to clock out. + * @return + * @retval true Slave acknowledged byte. + * @retval false Timeout or slave didn't acknowledge byte. + */ +static bool twi_master_clock_byte(uint_fast8_t databyte) +{ + bool transfer_succeeded = true; + + /** @snippet [TWI SW master write] */ + // Make sure SDA is an output + TWI_SDA_OUTPUT(); + + // MSB first + for (uint_fast8_t i = 0x80; i != 0; i >>= 1) + { + TWI_SCL_LOW(); + TWI_DELAY(); + + if (databyte & i) + { + TWI_SDA_HIGH(); + } + else + { + TWI_SDA_LOW(); + } + + if (!twi_master_wait_while_scl_low()) + { + transfer_succeeded = false; // Timeout + break; + } + } + + // Finish last data bit by pulling SCL low + TWI_SCL_LOW(); + TWI_DELAY(); + + /** @snippet [TWI SW master write] */ + + // Configure TWI_SDA pin as input for receiving the ACK bit + TWI_SDA_INPUT(); + + // Give some time for the slave to load the ACK bit on the line + TWI_DELAY(); + + // Pull SCL high and wait a moment for SDA line to settle + // Make sure slave is not stretching the clock + transfer_succeeded &= twi_master_wait_while_scl_low(); + + // Read ACK/NACK. NACK == 1, ACK == 0 + transfer_succeeded &= !(TWI_SDA_READ()); + + // Finish ACK/NACK bit clock cycle and give slave a moment to release control + // of the SDA line + TWI_SCL_LOW(); + TWI_DELAY(); + + // Configure TWI_SDA pin as output as other module functions expect that + TWI_SDA_OUTPUT(); + + return transfer_succeeded; +} + + +/** + * @brief Function for clocking one data byte in and sends ACK/NACK bit. + * + * Can handle clock stretching. + * SCL is expected to be output and low when entering this function. + * After calling this function, SCL is high and SDA low/high depending if ACK/NACK was sent. + * + * @param databyte Data byte to clock out. + * @param ack If true, send ACK. Otherwise send NACK. + * @return + * @retval true Byte read succesfully + * @retval false Timeout detected + */ +static bool twi_master_clock_byte_in(uint8_t *databyte, bool ack) +{ + uint_fast8_t byte_read = 0; + bool transfer_succeeded = true; + + /** @snippet [TWI SW master read] */ + // Make sure SDA is an input + TWI_SDA_INPUT(); + + // SCL state is guaranteed to be high here + + // MSB first + for (uint_fast8_t i = 0x80; i != 0; i >>= 1) + { + if (!twi_master_wait_while_scl_low()) + { + transfer_succeeded = false; + break; + } + + if (TWI_SDA_READ()) + { + byte_read |= i; + } + else + { + // No need to do anything + } + + TWI_SCL_LOW(); + TWI_DELAY(); + } + + // Make sure SDA is an output before we exit the function + TWI_SDA_OUTPUT(); + /** @snippet [TWI SW master read] */ + + *databyte = (uint8_t)byte_read; + + // Send ACK bit + + // SDA high == NACK, SDA low == ACK + if (ack) + { + TWI_SDA_LOW(); + } + else + { + TWI_SDA_HIGH(); + } + + // Let SDA line settle for a moment + TWI_DELAY(); + + // Drive SCL high to start ACK/NACK bit transfer + // Wait until SCL is high, or timeout occurs + if (!twi_master_wait_while_scl_low()) + { + transfer_succeeded = false; // Timeout + } + + // Finish ACK/NACK bit clock cycle and give slave a moment to react + TWI_SCL_LOW(); + TWI_DELAY(); + + return transfer_succeeded; +} + + +/** + * @brief Function for pulling SCL high and waits until it is high or timeout occurs. + * + * SCL is expected to be output before entering this function. + * @note If TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE is set to zero, timeout functionality is not compiled in. + * @return + * @retval true SCL is now high. + * @retval false Timeout occurred and SCL is still low. + */ +static bool twi_master_wait_while_scl_low(void) +{ +#if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0 + uint32_t volatile timeout_counter = TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE; +#endif + + // Pull SCL high just in case if something left it low + TWI_SCL_HIGH(); + TWI_DELAY(); + + while (TWI_SCL_READ() == 0) + { + // If SCL is low, one of the slaves is busy and we must wait + +#if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0 + if (timeout_counter-- == 0) + { + // If timeout_detected, return false + return false; + } +#endif + } + + return true; +} + +/*lint --flb "Leave library region" */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd.c new file mode 100644 index 0000000..1432d9f --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd.c @@ -0,0 +1,2333 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "sdk_common.h" +#if NRF_MODULE_ENABLED(USBD) + +#include "nrf_drv_usbd.h" +#include "nrf.h" +#include "nrf_atomic.h" +#include "app_util_platform.h" +#include "nrf_delay.h" + +#include <stdbool.h> +#include <string.h> +#include <inttypes.h> + +#define NRF_LOG_MODULE_NAME USBD + +#if USBD_CONFIG_LOG_ENABLED +#define NRF_LOG_LEVEL USBD_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR USBD_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR USBD_CONFIG_DEBUG_COLOR +#else //USBD_CONFIG_LOG_ENABLED +#define NRF_LOG_LEVEL 0 +#endif //USBD_CONFIG_LOG_ENABLED +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#ifndef NRF_DRV_USBD_EARLY_DMA_PROCESS +/* Try to process DMA request when endpoint transmission has been detected + * and just after last EasyDMA has been processed. + * It speeds up the transmission a little (about 10% measured) + * with a cost of more CPU power used. + */ +#define NRF_DRV_USBD_EARLY_DMA_PROCESS 1 +#endif + +#ifndef NRF_DRV_USBD_PROTO1_FIX_DEBUG +/* Debug information when events are fixed*/ +#define NRF_DRV_USBD_PROTO1_FIX_DEBUG 1 +#endif + +#define NRF_DRV_USBD_LOG_PROTO1_FIX_PRINTF(...) \ + do{ \ + if (NRF_DRV_USBD_PROTO1_FIX_DEBUG){ NRF_LOG_DEBUG(__VA_ARGS__); }\ + } while (0) + +#ifndef NRF_DRV_USBD_STARTED_EV_ENABLE +#define NRF_DRV_USBD_STARTED_EV_ENABLE 0 +#endif + +#ifndef NRF_USBD_ISO_DEBUG +/* Also generate information about ISOCHRONOUS events and transfers. + * Turn this off if no ISOCHRONOUS transfers are going to be debugged and this + * option generates a lot of useless messages. */ +#define NRF_USBD_ISO_DEBUG 1 +#endif + +#ifndef NRF_USBD_FAILED_TRANSFERS_DEBUG +/* Also generate debug information for failed transfers. + * It might be useful but may generate a lot of useless debug messages + * in some library usages (for example when transfer is generated and the + * result is used to check whatever endpoint was busy. */ +#define NRF_USBD_FAILED_TRANSFERS_DEBUG 1 +#endif + +#ifndef NRF_USBD_DMAREQ_PROCESS_DEBUG +/* Generate additional messages that mark the status inside + * @ref usbd_dmareq_process. + * It is useful to debug library internals but may generate a lot of + * useless debug messages. */ +#define NRF_USBD_DMAREQ_PROCESS_DEBUG 1 +#endif + + +/** + * @defgroup nrf_drv_usbd_int USB Device driver internal part + * @internal + * @ingroup nrf_drv_usbd + * + * This part contains auxiliary internal macros, variables and functions. + * @{ + */ + +/** + * @brief Assert endpoint number validity + * + * Internal macro to be used during program creation in debug mode. + * Generates assertion if endpoint number is not valid. + * + * @param ep Endpoint number to validity check + */ +#define USBD_ASSERT_EP_VALID(ep) ASSERT( \ + ((NRF_USBD_EPIN_CHECK(ep) && (NRF_USBD_EP_NR_GET(ep) < NRF_USBD_EPIN_CNT )) \ + || \ + (NRF_USBD_EPOUT_CHECK(ep) && (NRF_USBD_EP_NR_GET(ep) < NRF_USBD_EPOUT_CNT))) \ +); + +/** + * @brief Lowest position of bit for IN endpoint + * + * The first bit position corresponding to IN endpoint. + * @sa ep2bit bit2ep + */ +#define USBD_EPIN_BITPOS_0 0 + +/** + * @brief Lowest position of bit for OUT endpoint + * + * The first bit position corresponding to OUT endpoint + * @sa ep2bit bit2ep + */ +#define USBD_EPOUT_BITPOS_0 16 + +/** + * @brief Input endpoint bits mask + */ +#define USBD_EPIN_BIT_MASK (0xFFFFU << USBD_EPIN_BITPOS_0) + +/** + * @brief Output endpoint bits mask + */ +#define USBD_EPOUT_BIT_MASK (0xFFFFU << USBD_EPOUT_BITPOS_0) + +/** + * @brief Auxiliary macro to change EP number into bit position + * + * This macro is used by @ref ep2bit function but also for statically check + * the bitpos values integrity during compilation. + * + * @param[in] ep Endpoint number. + * @return Endpoint bit position. + */ +#define USBD_EP_BITPOS(ep) \ + ((NRF_USBD_EPIN_CHECK(ep) ? USBD_EPIN_BITPOS_0 : USBD_EPOUT_BITPOS_0) + NRF_USBD_EP_NR_GET(ep)) + +/** + * @brief Helper macro for creating an endpoint transfer event. + * + * @param[in] name Name of the created transfer event variable. + * @param[in] endpoint Endpoint number. + * @param[in] ep_stat Endpoint state to report. + * + * @return Initialized event constant variable. + */ +#define NRF_DRV_USBD_EP_TRANSFER_EVENT(name, endpont, ep_stat) \ + const nrf_drv_usbd_evt_t name = { \ + NRF_DRV_USBD_EVT_EPTRANSFER, \ + .data = { \ + .eptransfer = { \ + .ep = endpont, \ + .status = ep_stat \ + } \ + } \ + } + +/* Check it the bit positions values match defined DATAEPSTATUS bit positions */ +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPIN1) == USBD_EPDATASTATUS_EPIN1_Pos ); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPIN2) == USBD_EPDATASTATUS_EPIN2_Pos ); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPIN3) == USBD_EPDATASTATUS_EPIN3_Pos ); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPIN4) == USBD_EPDATASTATUS_EPIN4_Pos ); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPIN5) == USBD_EPDATASTATUS_EPIN5_Pos ); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPIN6) == USBD_EPDATASTATUS_EPIN6_Pos ); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPIN7) == USBD_EPDATASTATUS_EPIN7_Pos ); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPOUT1) == USBD_EPDATASTATUS_EPOUT1_Pos); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPOUT2) == USBD_EPDATASTATUS_EPOUT2_Pos); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPOUT3) == USBD_EPDATASTATUS_EPOUT3_Pos); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPOUT4) == USBD_EPDATASTATUS_EPOUT4_Pos); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPOUT5) == USBD_EPDATASTATUS_EPOUT5_Pos); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPOUT6) == USBD_EPDATASTATUS_EPOUT6_Pos); +STATIC_ASSERT(USBD_EP_BITPOS(NRF_DRV_USBD_EPOUT7) == USBD_EPDATASTATUS_EPOUT7_Pos); + + +/** + * @name Internal auxiliary definitions for SETUP packet + * + * Definitions used to take out the information about last SETUP packet direction + * from @c bmRequestType. + * @{ + */ +/** The position of DIR bit in bmRequestType inside SETUP packet */ +#define USBD_DRV_REQUESTTYPE_DIR_BITPOS 7 +/** The mask of DIR bit in bmRequestType inside SETUP packet */ +#define USBD_DRV_REQUESTTYPE_DIR_MASK (1U << USBD_DRV_REQUESTTYPE_DIR_BITPOS) +/** The value of DIR bit for OUT direction (Host -> Device) */ +#define USBD_DRV_REQUESTTYPE_DIR_OUT (0U << USBD_DRV_REQUESTTYPE_DIR_BITPOS) +/** The value of DIR bit for IN direction (Device -> Host) */ +#define USBD_DRV_REQUESTTYPE_DIR_IN (1U << USBD_DRV_REQUESTTYPE_DIR_BITPOS) +/** @} */ + +/** + * @brief Current driver state + */ +static nrfx_drv_state_t m_drv_state = NRFX_DRV_STATE_UNINITIALIZED; + +/** + * @brief Event handler for the library + * + * Event handler that would be called on events. + * + * @note Currently it cannot be null if any interrupt is activated. + */ +static nrf_drv_usbd_event_handler_t m_event_handler; + +/** + * @brief Detected state of the bus + * + * Internal state changed in interrupts handling when + * RESUME or SUSPEND event is processed. + * + * Values: + * - true - bus suspended + * - false - ongoing normal communication on the bus + * + * @note This is only the bus state and does not mean that the peripheral is in suspend state. + */ +static volatile bool m_bus_suspend; + +/** + * @brief Internal constant that contains interrupts disabled in suspend state + * + * Internal constant used in @ref nrf_drv_usbd_suspend_irq_config and @ref nrf_drv_usbd_active_irq_config + * functions. + */ +static const uint32_t m_irq_disabled_in_suspend = + NRF_USBD_INT_ENDEPIN0_MASK | + NRF_USBD_INT_EP0DATADONE_MASK | + NRF_USBD_INT_ENDEPOUT0_MASK | + NRF_USBD_INT_EP0SETUP_MASK | + NRF_USBD_INT_DATAEP_MASK; + +/** + * @brief Direction of last received Setup transfer + * + * This variable is used to redirect internal setup data event + * into selected endpoint (IN or OUT). + */ +static nrf_drv_usbd_ep_t m_last_setup_dir; + +/** + * @brief Mark endpoint readiness for DMA transfer + * + * Bits in this variable are cleared and set in interrupts. + * 1 means that endpoint is ready for DMA transfer. + * 0 means that DMA transfer cannot be performed on selected endpoint. + */ +static uint32_t m_ep_ready; + +/** + * @brief Mark endpoint with prepared data to transfer by DMA + * + * This variable can be from any place in the code (interrupt or main thread). + * It would be cleared only from USBD interrupt. + * + * Mask prepared USBD data for transmission. + * It is cleared when no more data to transmit left. + */ +static uint32_t m_ep_dma_waiting; + +/** + * @brief Current EasyDMA state + * + * Single flag, updated only inside interrupts, that marks current EasyDMA state. + * In USBD there is only one DMA channel working in background, and new transfer + * cannot be started when there is ongoing transfer on any other channel. + */ +static bool m_dma_pending; + +/** + * @brief Simulated data EP status bits required for errata 104 + * + * Marker to delete when not required anymore: >> NRF_DRV_USBD_ERRATA_ENABLE << + */ +static uint32_t m_simulated_dataepstatus; + +/** + * @brief The structure that would hold transfer configuration to every endpoint + * + * The structure that holds all the data required by the endpoint to proceed + * with LIST functionality and generate quick callback directly when data + * buffer is ready. + */ +typedef struct +{ + nrf_drv_usbd_handler_t handler; //!< Handler for current transfer, function pointer + void * p_context; //!< Context for transfer handler + size_t transfer_cnt; //!< Number of transferred bytes in the current transfer + uint16_t max_packet_size; //!< Configured endpoint size + nrf_drv_usbd_ep_status_t status; //!< NRF_SUCCESS or error code, never NRF_ERROR_BUSY - this one is calculated +}usbd_drv_ep_state_t; + +/** + * @brief The array of transfer configurations for the endpoints. + * + * The status of the transfer on each endpoint. + */ +static struct +{ + usbd_drv_ep_state_t ep_out[NRF_USBD_EPOUT_CNT]; //!< Status for OUT endpoints. + usbd_drv_ep_state_t ep_in [NRF_USBD_EPIN_CNT ]; //!< Status for IN endpoints. +}m_ep_state; + +/** + * @brief Status variables for integrated feeders. + * + * Current status for integrated feeders (IN transfers). + * Integrated feeders are used for default transfers: + * 1. Simple RAM transfer + * 2. Simple flash transfer + * 3. RAM transfer with automatic ZLP + * 4. Flash transfer with automatic ZLP + */ +nrf_drv_usbd_transfer_t m_ep_feeder_state[NRF_USBD_EPIN_CNT]; + +/** + * @brief Status variables for integrated consumers + * + * Current status for integrated consumers + * Currently one type of transfer is supported: + * 1. Transfer to RAM + * + * Transfer is finished automatically when received data block is smaller + * than the endpoint buffer or all the required data is received. + */ +nrf_drv_usbd_transfer_t m_ep_consumer_state[NRF_USBD_EPOUT_CNT]; + + +/** + * @brief Buffer used to send data directly from FLASH + * + * This is internal buffer that would be used to emulate the possibility + * to transfer data directly from FLASH. + * We do not have to care about the source of data when calling transfer functions. + * + * We do not need more buffers that one, because only one transfer can be pending + * at once. + */ +static uint32_t m_tx_buffer[CEIL_DIV( + NRF_DRV_USBD_FEEDER_BUFFER_SIZE, sizeof(uint32_t))]; + + +/* Early declaration. Documentation above definition. */ +static void usbd_dmareq_process(void); + + +/** + * @brief Change endpoint number to endpoint event code + * + * @param ep Endpoint number + * + * @return Connected endpoint event code. + * + * Marker to delete when not required anymore: >> NRF_DRV_USBD_ERRATA_ENABLE << + */ +static inline nrf_usbd_event_t nrf_drv_usbd_ep_to_endevent(nrf_drv_usbd_ep_t ep) +{ + USBD_ASSERT_EP_VALID(ep); + + static const nrf_usbd_event_t epin_endev[] = + { + NRF_USBD_EVENT_ENDEPIN0, + NRF_USBD_EVENT_ENDEPIN1, + NRF_USBD_EVENT_ENDEPIN2, + NRF_USBD_EVENT_ENDEPIN3, + NRF_USBD_EVENT_ENDEPIN4, + NRF_USBD_EVENT_ENDEPIN5, + NRF_USBD_EVENT_ENDEPIN6, + NRF_USBD_EVENT_ENDEPIN7, + NRF_USBD_EVENT_ENDISOIN0 + }; + static const nrf_usbd_event_t epout_endev[] = + { + NRF_USBD_EVENT_ENDEPOUT0, + NRF_USBD_EVENT_ENDEPOUT1, + NRF_USBD_EVENT_ENDEPOUT2, + NRF_USBD_EVENT_ENDEPOUT3, + NRF_USBD_EVENT_ENDEPOUT4, + NRF_USBD_EVENT_ENDEPOUT5, + NRF_USBD_EVENT_ENDEPOUT6, + NRF_USBD_EVENT_ENDEPOUT7, + NRF_USBD_EVENT_ENDISOOUT0 + }; + + return (NRF_USBD_EPIN_CHECK(ep) ? epin_endev : epout_endev)[NRF_USBD_EP_NR_GET(ep)]; +} + + +/** + * @brief Get interrupt mask for selected endpoint + * + * @param[in] ep Endpoint number + * + * @return Interrupt mask related to the EasyDMA transfer end for the + * chosen endpoint. + */ +static inline uint32_t nrf_drv_usbd_ep_to_int(nrf_drv_usbd_ep_t ep) +{ + USBD_ASSERT_EP_VALID(ep); + + static const uint8_t epin_bitpos[] = + { + USBD_INTEN_ENDEPIN0_Pos, + USBD_INTEN_ENDEPIN1_Pos, + USBD_INTEN_ENDEPIN2_Pos, + USBD_INTEN_ENDEPIN3_Pos, + USBD_INTEN_ENDEPIN4_Pos, + USBD_INTEN_ENDEPIN5_Pos, + USBD_INTEN_ENDEPIN6_Pos, + USBD_INTEN_ENDEPIN7_Pos, + USBD_INTEN_ENDISOIN_Pos + }; + static const uint8_t epout_bitpos[] = + { + USBD_INTEN_ENDEPOUT0_Pos, + USBD_INTEN_ENDEPOUT1_Pos, + USBD_INTEN_ENDEPOUT2_Pos, + USBD_INTEN_ENDEPOUT3_Pos, + USBD_INTEN_ENDEPOUT4_Pos, + USBD_INTEN_ENDEPOUT5_Pos, + USBD_INTEN_ENDEPOUT6_Pos, + USBD_INTEN_ENDEPOUT7_Pos, + USBD_INTEN_ENDISOOUT_Pos + }; + + return 1UL << (NRF_USBD_EPIN_CHECK(ep) ? epin_bitpos : epout_bitpos)[NRF_USBD_EP_NR_GET(ep)]; +} + +/** + * @name Integrated feeders and consumers + * + * Internal, default functions for transfer processing. + * @{ + */ + +/** + * @brief Integrated consumer to RAM buffer. + * + * @param p_next See @ref nrf_drv_usbd_consumer_t documentation. + * @param p_context See @ref nrf_drv_usbd_consumer_t documentation. + * @param ep_size See @ref nrf_drv_usbd_consumer_t documentation. + * @param data_size See @ref nrf_drv_usbd_consumer_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrf_drv_usbd_consumer( + nrf_drv_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size, + size_t data_size) +{ + nrf_drv_usbd_transfer_t * p_transfer = p_context; + ASSERT(ep_size >= data_size); + ASSERT((p_transfer->p_data.rx == NULL) || + nrfx_is_in_ram((const void*)(p_transfer->p_data.ptr))); + + size_t size = p_transfer->size; + if (size < data_size) + { + NRF_LOG_DEBUG("consumer: buffer too small: r: %u, l: %u", data_size, size); + /* Buffer size to small */ + p_next->size = 0; + p_next->p_data = p_transfer->p_data; + } + else + { + p_next->size = data_size; + p_next->p_data = p_transfer->p_data; + size -= data_size; + p_transfer->size = size; + p_transfer->p_data.ptr += data_size; + } + return (ep_size == data_size) && (size != 0); +} + +/** + * @brief Integrated feeder from RAM source. + * + * @param[out] p_next See @ref nrf_drv_usbd_feeder_t documentation. + * @param[in,out] p_context See @ref nrf_drv_usbd_feeder_t documentation. + * @param[in] ep_size See @ref nrf_drv_usbd_feeder_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrf_drv_usbd_feeder_ram( + nrf_drv_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size) +{ + nrf_drv_usbd_transfer_t * p_transfer = p_context; + ASSERT(nrfx_is_in_ram((const void*)(p_transfer->p_data.ptr))); + + size_t tx_size = p_transfer->size; + if (tx_size > ep_size) + { + tx_size = ep_size; + } + + p_next->p_data = p_transfer->p_data; + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.ptr += tx_size; + + return (p_transfer->size != 0); +} + +/** + * @brief Integrated feeder from RAM source with ZLP. + * + * @param[out] p_next See @ref nrf_drv_usbd_feeder_t documentation. + * @param[in,out] p_context See @ref nrf_drv_usbd_feeder_t documentation. + * @param[in] ep_size See @ref nrf_drv_usbd_feeder_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrf_drv_usbd_feeder_ram_zlp( + nrf_drv_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size) +{ + nrf_drv_usbd_transfer_t * p_transfer = p_context; + ASSERT(nrfx_is_in_ram((const void*)(p_transfer->p_data.ptr))); + + size_t tx_size = p_transfer->size; + if (tx_size > ep_size) + { + tx_size = ep_size; + } + + p_next->p_data.tx = (tx_size == 0) ? NULL : p_transfer->p_data.tx; + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.ptr += tx_size; + + return (tx_size != 0); +} + +/** + * @brief Integrated feeder from a flash source. + * + * @param[out] p_next See @ref nrf_drv_usbd_feeder_t documentation. + * @param[in,out] p_context See @ref nrf_drv_usbd_feeder_t documentation. + * @param[in] ep_size See @ref nrf_drv_usbd_feeder_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrf_drv_usbd_feeder_flash( + nrf_drv_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size) +{ + nrf_drv_usbd_transfer_t * p_transfer = p_context; + ASSERT(!nrfx_is_in_ram((const void*)(p_transfer->p_data.ptr))); + + size_t tx_size = p_transfer->size; + void * p_buffer = nrf_drv_usbd_feeder_buffer_get(); + + if (tx_size > ep_size) + { + tx_size = ep_size; + } + + ASSERT(tx_size <= NRF_DRV_USBD_FEEDER_BUFFER_SIZE); + memcpy(p_buffer, (p_transfer->p_data.tx), tx_size); + + p_next->p_data.tx = p_buffer; + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.ptr += tx_size; + + return (p_transfer->size != 0); +} + +/** + * @brief Integrated feeder from a flash source with ZLP. + * + * @param[out] p_next See @ref nrf_drv_usbd_feeder_t documentation. + * @param[in,out] p_context See @ref nrf_drv_usbd_feeder_t documentation. + * @param[in] ep_size See @ref nrf_drv_usbd_feeder_t documentation. + * + * @retval true Continue transfer. + * @retval false This was the last transfer. + */ +bool nrf_drv_usbd_feeder_flash_zlp( + nrf_drv_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size) +{ + nrf_drv_usbd_transfer_t * p_transfer = p_context; + ASSERT(!nrfx_is_in_ram((const void*)(p_transfer->p_data.ptr))); + + size_t tx_size = p_transfer->size; + void * p_buffer = nrf_drv_usbd_feeder_buffer_get(); + + if (tx_size > ep_size) + { + tx_size = ep_size; + } + + ASSERT(tx_size <= NRF_DRV_USBD_FEEDER_BUFFER_SIZE); + + if (tx_size != 0) + { + memcpy(p_buffer, (p_transfer->p_data.tx), tx_size); + p_next->p_data.tx = p_buffer; + } + else + { + p_next->p_data.tx = NULL; + } + p_next->size = tx_size; + + p_transfer->size -= tx_size; + p_transfer->p_data.ptr += tx_size; + + return (tx_size != 0); +} + +/** @} */ + +/** + * @brief Change Driver endpoint number to HAL endpoint number + * + * @param ep Driver endpoint identifier + * + * @return Endpoint identifier in HAL + * + * @sa nrf_drv_usbd_ep_from_hal + */ +static inline uint8_t ep_to_hal(nrf_drv_usbd_ep_t ep) +{ + USBD_ASSERT_EP_VALID(ep); + return (uint8_t)ep; +} + +/** + * @brief Generate start task number for selected endpoint index + * + * @param ep Endpoint number + * + * @return Task for starting EasyDMA transfer on selected endpoint. + */ +static inline nrf_usbd_task_t task_start_ep(nrf_drv_usbd_ep_t ep) +{ + USBD_ASSERT_EP_VALID(ep); + return (nrf_usbd_task_t)( + (NRF_USBD_EPIN_CHECK(ep) ? NRF_USBD_TASK_STARTEPIN0 : NRF_USBD_TASK_STARTEPOUT0) + + (NRF_USBD_EP_NR_GET(ep) * sizeof(uint32_t))); +} + +/** + * @brief Access selected endpoint state structure + * + * Function used to change or just read the state of selected endpoint. + * It is used for internal transmission state. + * + * @param ep Endpoint number + */ +static inline usbd_drv_ep_state_t* ep_state_access(nrf_drv_usbd_ep_t ep) +{ + USBD_ASSERT_EP_VALID(ep); + return ((NRF_USBD_EPIN_CHECK(ep) ? m_ep_state.ep_in : m_ep_state.ep_out) + + NRF_USBD_EP_NR_GET(ep)); +} + +/** + * @brief Change endpoint number to bit position + * + * Bit positions are defined the same way as they are placed in DATAEPSTATUS register, + * but bits for endpoint 0 are included. + * + * @param ep Endpoint number + * + * @return Bit position related to the given endpoint number + * + * @sa bit2ep + */ +static inline uint8_t ep2bit(nrf_drv_usbd_ep_t ep) +{ + USBD_ASSERT_EP_VALID(ep); + return USBD_EP_BITPOS(ep); +} + +/** + * @brief Change bit position to endpoint number + * + * @param bitpos Bit position + * + * @return Endpoint number corresponding to given bit position. + * + * @sa ep2bit + */ +static inline nrf_drv_usbd_ep_t bit2ep(uint8_t bitpos) +{ + STATIC_ASSERT(USBD_EPOUT_BITPOS_0 > USBD_EPIN_BITPOS_0); + return (nrf_drv_usbd_ep_t)((bitpos >= USBD_EPOUT_BITPOS_0) ? + NRF_USBD_EPOUT(bitpos - USBD_EPOUT_BITPOS_0) : NRF_USBD_EPIN(bitpos)); +} + +/** + * @brief Mark that EasyDMA is working + * + * Internal function to set the flag informing about EasyDMA transfer pending. + * This function is called always just after the EasyDMA transfer is started. + */ +static inline void usbd_dma_pending_set(void) +{ + if (nrf_drv_usb_errata_199()) + { + *((volatile uint32_t *)0x40027C1C) = 0x00000082; + } + m_dma_pending = true; +} + +/** + * @brief Mark that EasyDMA is free + * + * Internal function to clear the flag informing about EasyDMA transfer pending. + * This function is called always just after the finished EasyDMA transfer is detected. + */ +static inline void usbd_dma_pending_clear(void) +{ + if (nrf_drv_usb_errata_199()) + { + *((volatile uint32_t *)0x40027C1C) = 0x00000000; + } + m_dma_pending = false; +} + +/** + * @brief Start selected EasyDMA transmission + * + * This is internal auxiliary function. + * No checking is made if EasyDMA is ready for new transmission. + * + * @param[in] ep Number of endpoint for transmission. + * If it is OUT endpoint transmission would be directed from endpoint to RAM. + * If it is in endpoint transmission would be directed from RAM to endpoint. + */ +static inline void usbd_dma_start(nrf_drv_usbd_ep_t ep) +{ + nrf_usbd_task_trigger(task_start_ep(ep)); +} + +/** + * @brief Abort pending transfer on selected endpoint + * + * @param ep Endpoint number. + * + * @note + * This function locks interrupts that may be costly. + * It is good idea to test if the endpoint is still busy before calling this function: + * @code + (m_ep_dma_waiting & (1U << ep2bit(ep))) + * @endcode + * This function would check it again, but it makes it inside critical section. + */ +static inline void usbd_ep_abort(nrf_drv_usbd_ep_t ep) +{ + CRITICAL_REGION_ENTER(); + + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + + if (NRF_USBD_EPOUT_CHECK(ep)) + { + /* Host -> Device */ + if ((~m_ep_dma_waiting) & (1U << ep2bit(ep))) + { + /* If the bit in m_ep_dma_waiting in cleared - nothing would be + * processed inside transfer processing */ + nrf_drv_usbd_transfer_out_drop(ep); + } + else + { + p_state->handler.consumer = NULL; + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + m_ep_ready &= ~(1U << ep2bit(ep)); + } + /* Aborted */ + p_state->status = NRF_USBD_EP_ABORTED; + } + else + { + if ((m_ep_dma_waiting | (~m_ep_ready)) & (1U << ep2bit(ep))) + { + /* Device -> Host */ + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + m_ep_ready |= 1U << ep2bit(ep) ; + + p_state->handler.feeder = NULL; + p_state->status = NRF_USBD_EP_ABORTED; + NRF_DRV_USBD_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_EP_ABORTED); + m_event_handler(&evt); + } + } + CRITICAL_REGION_EXIT(); +} + +void nrf_drv_usbd_ep_abort(nrf_drv_usbd_ep_t ep) +{ + usbd_ep_abort(ep); +} + + +/** + * @brief Abort all pending endpoints + * + * Function aborts all pending endpoint transfers. + */ +static void usbd_ep_abort_all(void) +{ + uint32_t ep_waiting = m_ep_dma_waiting | (m_ep_ready & USBD_EPOUT_BIT_MASK); + while (0 != ep_waiting) + { + uint8_t bitpos = __CLZ(__RBIT(ep_waiting)); + if(!NRF_USBD_EPISO_CHECK(bit2ep(bitpos))) + { + usbd_ep_abort(bit2ep(bitpos)); + } + ep_waiting &= ~(1U << bitpos); + } + + m_ep_ready = (((1U << NRF_USBD_EPIN_CNT) - 1U) << USBD_EPIN_BITPOS_0); +} + +/** + * @brief Force the USBD interrupt into pending state + * + * This function is used to force USBD interrupt to be processed right now. + * It makes it possible to process all EasyDMA access on one thread priority level. + */ +static inline void usbd_int_rise(void) +{ + NVIC_SetPendingIRQ(USBD_IRQn); +} + +/** + * @name USBD interrupt runtimes + * + * Interrupt runtimes that would be vectorized using @ref m_ivec_isr + * @{ + */ + +static void ev_usbreset_handler(void) +{ + m_bus_suspend = false; + m_last_setup_dir = NRF_DRV_USBD_EPOUT0; + + const nrf_drv_usbd_evt_t evt = { + .type = NRF_DRV_USBD_EVT_RESET + }; + + m_event_handler(&evt); +} + +static void ev_started_handler(void) +{ +#if NRF_DRV_USBD_STARTED_EV_ENABLE + uint32_t epstatus = nrf_usbd_epstatus_get_and_clear(); + + /* All finished endpoint have to be marked as busy */ + // #warning Check this one + // ASSERT(epstatus == ((~m_ep_ready) & epstatus)); + while (epstatus) + { + uint8_t bitpos = __CLZ(__RBIT(epstatus)); + nrf_drv_usbd_ep_t ep = bit2ep(bitpos); + epstatus &= ~(1UL << bitpos); + + UNUSED_VARIABLE(ep); + } +#endif +} + +/** + * @brief Handler for EasyDMA event without endpoint clearing. + * + * This handler would be called when EasyDMA transfer for endpoints that does not require clearing. + * All in endpoints are cleared automatically when new EasyDMA transfer is initialized. + * For endpoint 0 see @ref nrf_usbd_ep0out_dma_handler + * + * @param[in] ep Endpoint number + */ +static inline void nrf_usbd_ep0in_dma_handler(void) +{ + const nrf_drv_usbd_ep_t ep = NRF_DRV_USBD_EPIN0; + NRF_LOG_DEBUG("USB event: DMA ready IN0"); + usbd_dma_pending_clear(); + + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + if (NRF_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.feeder == NULL) + { + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else + { + /* Nothing to do */ + } +} + +/** + * @brief Handler for EasyDMA event without endpoint clearing. + * + * This handler would be called when EasyDMA transfer for endpoints that does not require clearing. + * All in endpoints are cleared automatically when new EasyDMA transfer is initialized. + * For endpoint 0 see @ref nrf_usbd_ep0out_dma_handler + * + * @param[in] ep Endpoint number + */ +static inline void nrf_usbd_epin_dma_handler(nrf_drv_usbd_ep_t ep) +{ + + NRF_LOG_DEBUG("USB event: DMA ready IN: %x", ep); + ASSERT(NRF_USBD_EPIN_CHECK(ep)); + ASSERT(!NRF_USBD_EPISO_CHECK(ep)); + ASSERT(NRF_USBD_EP_NR_GET(ep) > 0); + usbd_dma_pending_clear(); + + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + if (NRF_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.feeder == NULL) + { + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else + { + /* Nothing to do */ + } +} + +/** + * @brief Handler for EasyDMA event from in isochronous endpoint + * + * @todo RK documentation + */ +static inline void nrf_usbd_epiniso_dma_handler(nrf_drv_usbd_ep_t ep) +{ + if (NRF_USBD_ISO_DEBUG) + { + NRF_LOG_DEBUG("USB event: DMA ready ISOIN: %x", ep); + } + ASSERT(NRF_USBD_EPIN_CHECK(ep)); + ASSERT(NRF_USBD_EPISO_CHECK(ep)); + usbd_dma_pending_clear(); + + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + if (NRF_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.feeder == NULL) + { + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + /* Send event to the user - for an ISO IN endpoint, the whole transfer is finished in this moment */ + NRF_DRV_USBD_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_EP_OK); + m_event_handler(&evt); + } + else + { + /* Nothing to do */ + } +} + +/** + * @brief Handler for EasyDMA event for OUT endpoint 0. + * + * EP0 OUT have to be cleared automatically in special way - only in the middle of the transfer. + * It cannot be cleared when required transfer is finished because it means the same that accepting the comment. + */ +static inline void nrf_usbd_ep0out_dma_handler(void) +{ + const nrf_drv_usbd_ep_t ep = NRF_DRV_USBD_EPOUT0; + NRF_LOG_DEBUG("USB event: DMA ready OUT0"); + usbd_dma_pending_clear(); + + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + if (NRF_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.consumer == NULL) + { + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + /* Send event to the user - for an OUT endpoint, the whole transfer is finished in this moment */ + NRF_DRV_USBD_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_EP_OK); + m_event_handler(&evt); + } + else + { + nrf_drv_usbd_setup_data_clear(); + } +} + +/** + * @brief Handler for EasyDMA event from endpoinpoint that requires clearing. + * + * This handler would be called when EasyDMA transfer for OUT endpoint has been finished. + * + * @param[in] ep Endpoint number + * + */ +static inline void nrf_usbd_epout_dma_handler(nrf_drv_usbd_ep_t ep) +{ + NRF_LOG_DEBUG("USB drv: DMA ready OUT: %x", ep); + ASSERT(NRF_USBD_EPOUT_CHECK(ep)); + ASSERT(!NRF_USBD_EPISO_CHECK(ep)); + ASSERT(NRF_USBD_EP_NR_GET(ep) > 0); + usbd_dma_pending_clear(); + + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + if (NRF_USBD_EP_ABORTED == p_state->status) + { + /* Clear transfer information just in case */ + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + } + else if (p_state->handler.consumer == NULL) + { + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + /* Send event to the user - for an OUT endpoint, the whole transfer is finished in this moment */ + NRF_DRV_USBD_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_EP_OK); + m_event_handler(&evt); + } + else + { + /* Nothing to do */ + } + +#if NRF_DRV_USBD_EARLY_DMA_PROCESS + /* Speed up */ + usbd_dmareq_process(); +#endif +} + +/** + * @brief Handler for EasyDMA event from out isochronous endpoint + * + * @todo RK documentation + */ + +static inline void nrf_usbd_epoutiso_dma_handler(nrf_drv_usbd_ep_t ep) +{ + if (NRF_USBD_ISO_DEBUG) + { + NRF_LOG_DEBUG("USB drv: DMA ready ISOOUT: %x", ep); + } + ASSERT(NRF_USBD_EPISO_CHECK(ep)); + usbd_dma_pending_clear(); + + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + if (NRF_USBD_EP_ABORTED == p_state->status) + { + /* Nothing to do - just ignore */ + } + else if (p_state->handler.consumer == NULL) + { + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << ep2bit(ep)))); + /* Send event to the user - for an OUT endpoint, the whole transfer is finished in this moment */ + NRF_DRV_USBD_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_EP_OK); + m_event_handler(&evt); + } + else + { + /* Nothing to do */ + } +} + + +static void ev_dma_epin0_handler(void) { nrf_usbd_ep0in_dma_handler(); } +static void ev_dma_epin1_handler(void) { nrf_usbd_epin_dma_handler(NRF_DRV_USBD_EPIN1 ); } +static void ev_dma_epin2_handler(void) { nrf_usbd_epin_dma_handler(NRF_DRV_USBD_EPIN2 ); } +static void ev_dma_epin3_handler(void) { nrf_usbd_epin_dma_handler(NRF_DRV_USBD_EPIN3 ); } +static void ev_dma_epin4_handler(void) { nrf_usbd_epin_dma_handler(NRF_DRV_USBD_EPIN4 ); } +static void ev_dma_epin5_handler(void) { nrf_usbd_epin_dma_handler(NRF_DRV_USBD_EPIN5 ); } +static void ev_dma_epin6_handler(void) { nrf_usbd_epin_dma_handler(NRF_DRV_USBD_EPIN6 ); } +static void ev_dma_epin7_handler(void) { nrf_usbd_epin_dma_handler(NRF_DRV_USBD_EPIN7 ); } +static void ev_dma_epin8_handler(void) { nrf_usbd_epiniso_dma_handler(NRF_DRV_USBD_EPIN8 ); } + +static void ev_dma_epout0_handler(void) { nrf_usbd_ep0out_dma_handler(); } +static void ev_dma_epout1_handler(void) { nrf_usbd_epout_dma_handler(NRF_DRV_USBD_EPOUT1); } +static void ev_dma_epout2_handler(void) { nrf_usbd_epout_dma_handler(NRF_DRV_USBD_EPOUT2); } +static void ev_dma_epout3_handler(void) { nrf_usbd_epout_dma_handler(NRF_DRV_USBD_EPOUT3); } +static void ev_dma_epout4_handler(void) { nrf_usbd_epout_dma_handler(NRF_DRV_USBD_EPOUT4); } +static void ev_dma_epout5_handler(void) { nrf_usbd_epout_dma_handler(NRF_DRV_USBD_EPOUT5); } +static void ev_dma_epout6_handler(void) { nrf_usbd_epout_dma_handler(NRF_DRV_USBD_EPOUT6); } +static void ev_dma_epout7_handler(void) { nrf_usbd_epout_dma_handler(NRF_DRV_USBD_EPOUT7); } +static void ev_dma_epout8_handler(void) { nrf_usbd_epoutiso_dma_handler(NRF_DRV_USBD_EPOUT8); } + +static void ev_sof_handler(void) +{ + nrf_drv_usbd_evt_t evt = { + NRF_DRV_USBD_EVT_SOF, + .data = { .sof = { .framecnt = nrf_usbd_framecntr_get() }} + }; + + /* Process isochronous endpoints */ + m_ep_ready |= + (1U << ep2bit(NRF_DRV_USBD_EPIN8 )) | + (1U << ep2bit(NRF_DRV_USBD_EPOUT8)); + + m_event_handler(&evt); +} + +/** + * @brief React on data transfer finished + * + * Auxiliary internal function. + * @param ep Endpoint number + * @param bitpos Bit position for selected endpoint number + */ +static void usbd_ep_data_handler(nrf_drv_usbd_ep_t ep, uint8_t bitpos) +{ + NRF_LOG_DEBUG("USBD event: EndpointData: %x", ep); + /* Mark endpoint ready for next DMA access */ + m_ep_ready |= (1U << bitpos); + + if (NRF_USBD_EPIN_CHECK(ep)) + { + /* IN endpoint (Device -> Host) */ + if (0 == (m_ep_dma_waiting & (1U << bitpos))) + { + NRF_LOG_DEBUG("USBD event: EndpointData: In finished"); + /* No more data to be send - transmission finished */ + NRF_DRV_USBD_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_EP_OK); + m_event_handler(&evt); + } + } + else + { + /* OUT endpoint (Host -> Device) */ + if (0 == (m_ep_dma_waiting & (1U << bitpos))) + { + NRF_LOG_DEBUG("USBD event: EndpointData: Out waiting"); + /* No buffer prepared - send event to the application */ + NRF_DRV_USBD_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_EP_WAITING); + m_event_handler(&evt); + } + } +} + +static void ev_setup_data_handler(void) +{ + usbd_ep_data_handler(m_last_setup_dir, ep2bit(m_last_setup_dir)); +} + +static void ev_setup_handler(void) +{ + NRF_LOG_DEBUG("USBD event: Setup (rt:%.2x r:%.2x v:%.4x i:%.4x l:%u )", + nrf_usbd_setup_bmrequesttype_get(), + nrf_usbd_setup_brequest_get(), + nrf_usbd_setup_wvalue_get(), + nrf_usbd_setup_windex_get(), + nrf_usbd_setup_wlength_get()); + uint8_t bmRequestType = nrf_usbd_setup_bmrequesttype_get(); + + + if ((m_ep_dma_waiting | ((~m_ep_ready) & USBD_EPIN_BIT_MASK)) & (1U <<ep2bit(m_last_setup_dir))) + { + NRF_LOG_DEBUG("USBD drv: Trying to abort last transfer on EP0"); + usbd_ep_abort(m_last_setup_dir); + } + + m_last_setup_dir = + ((bmRequestType & USBD_DRV_REQUESTTYPE_DIR_MASK) == USBD_DRV_REQUESTTYPE_DIR_OUT) ? + NRF_DRV_USBD_EPOUT0 : NRF_DRV_USBD_EPIN0; + + UNUSED_RETURN_VALUE(nrf_atomic_u32_and( + &m_ep_dma_waiting, + ~((1U << ep2bit(NRF_DRV_USBD_EPOUT0)) | (1U << ep2bit(NRF_DRV_USBD_EPIN0))))); + m_ep_ready |= 1U << ep2bit(NRF_DRV_USBD_EPIN0); + + + const nrf_drv_usbd_evt_t evt = { + .type = NRF_DRV_USBD_EVT_SETUP + }; + m_event_handler(&evt); +} + +static void ev_usbevent_handler(void) +{ + uint32_t event = nrf_usbd_eventcause_get_and_clear(); + + if (event & NRF_USBD_EVENTCAUSE_ISOOUTCRC_MASK) + { + /* Currently no support */ + } + if (event & NRF_USBD_EVENTCAUSE_SUSPEND_MASK) + { + m_bus_suspend = true; + const nrf_drv_usbd_evt_t evt = { + .type = NRF_DRV_USBD_EVT_SUSPEND + }; + m_event_handler(&evt); + } + if (event & NRF_USBD_EVENTCAUSE_RESUME_MASK) + { + m_bus_suspend = false; + const nrf_drv_usbd_evt_t evt = { + .type = NRF_DRV_USBD_EVT_RESUME + }; + m_event_handler(&evt); + } + if (event & NRF_USBD_EVENTCAUSE_WUREQ_MASK) + { + if (m_bus_suspend) + { + ASSERT(!nrf_usbd_lowpower_check()); + m_bus_suspend = false; + + nrf_usbd_dpdmvalue_set(NRF_USBD_DPDMVALUE_RESUME); + nrf_usbd_task_trigger(NRF_USBD_TASK_DRIVEDPDM); + + const nrf_drv_usbd_evt_t evt = { + .type = NRF_DRV_USBD_EVT_WUREQ + }; + m_event_handler(&evt); + } + } +} + +static void ev_epdata_handler(void) +{ + /* Get all endpoints that have acknowledged transfer */ + uint32_t dataepstatus = nrf_usbd_epdatastatus_get_and_clear(); + if (nrf_drv_usbd_errata_104()) + { + dataepstatus |= (m_simulated_dataepstatus & + ~((1U << USBD_EPOUT_BITPOS_0) | (1U << USBD_EPIN_BITPOS_0))); + m_simulated_dataepstatus &= + ((1U << USBD_EPOUT_BITPOS_0) | (1U << USBD_EPIN_BITPOS_0)); + } + NRF_LOG_DEBUG("USBD event: EndpointEPStatus: %x", dataepstatus); + + /* All finished endpoint have to be marked as busy */ + while (dataepstatus) + { + uint8_t bitpos = __CLZ(__RBIT(dataepstatus)); + nrf_drv_usbd_ep_t ep = bit2ep(bitpos); + dataepstatus &= ~(1UL << bitpos); + + UNUSED_RETURN_VALUE(usbd_ep_data_handler(ep, bitpos)); + } + if (NRF_DRV_USBD_EARLY_DMA_PROCESS) + { + /* Speed up */ + usbd_dmareq_process(); + } +} + +/** + * @brief Function to select the endpoint to start + * + * Function that realizes algorithm to schedule right channel for EasyDMA transfer. + * It gets a variable with flags for the endpoints currently requiring transfer. + * + * @param[in] req Bit flags for channels currently requiring transfer. + * Bits 0...8 used for IN endpoints. + * Bits 16...24 used for OUT endpoints. + * @note + * This function would be never called with 0 as a @c req argument. + * @return The bit number of the endpoint that should be processed now. + */ +static uint8_t usbd_dma_scheduler_algorithm(uint32_t req) +{ + /* Only prioritized scheduling mode is supported */ + STATIC_ASSERT(USBD_CONFIG_DMASCHEDULER_MODE == NRF_DRV_USBD_DMASCHEDULER_PRIORITIZED); + return __CLZ(__RBIT(req)); +} + +/** + * @brief Get the size of isochronous endpoint + * + * The size of isochronous endpoint is configurable. + * This function returns the size of isochronous buffer taking into account + * current configuration. + * + * @param[in] ep Endpoint number. + * + * @return The size of endpoint buffer. + */ +static inline size_t usbd_ep_iso_capacity(nrf_drv_usbd_ep_t ep) +{ + UNUSED_PARAMETER(ep); + nrf_usbd_isosplit_t split = nrf_usbd_isosplit_get(); + if (NRF_USBD_ISOSPLIT_Half == split) + { + return NRF_DRV_USBD_ISOSIZE / 2; + } + return NRF_DRV_USBD_ISOSIZE; +} + +/** + * @brief Process all DMA requests + * + * Function that have to be called from USBD interrupt handler. + * It have to be called when all the interrupts connected with endpoints transfer + * and DMA transfer are already handled. + */ +static void usbd_dmareq_process(void) +{ + if (!m_dma_pending) + { + uint32_t req; + while (0 != (req = m_ep_dma_waiting & m_ep_ready)) + { + uint8_t pos = usbd_dma_scheduler_algorithm(req); + nrf_drv_usbd_ep_t ep = bit2ep(pos); + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + + nrf_drv_usbd_ep_transfer_t transfer; + bool continue_transfer; + + STATIC_ASSERT(offsetof(usbd_drv_ep_state_t, handler.feeder) == + offsetof(usbd_drv_ep_state_t, handler.consumer)); + ASSERT((p_state->handler.feeder) != NULL); + + if (NRF_USBD_EPIN_CHECK(ep)) + { + /* Device -> Host */ + continue_transfer = p_state->handler.feeder( + &transfer, + p_state->p_context, + p_state->max_packet_size); + + if (!continue_transfer) + { + p_state->handler.feeder = NULL; + } + } + else + { + /* Host -> Device */ + const size_t rx_size = nrf_drv_usbd_epout_size_get(ep); + continue_transfer = p_state->handler.consumer( + &transfer, + p_state->p_context, + p_state->max_packet_size, + rx_size); + + if (transfer.p_data.rx == NULL) + { + /* Dropping transfer - allow processing */ + ASSERT(transfer.size == 0); + } + else if (transfer.size < rx_size) + { + NRF_LOG_DEBUG("Endpoint %x overload (r: %u, e: %u)", ep, rx_size, transfer.size); + p_state->status = NRF_USBD_EP_OVERLOAD; + UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&m_ep_dma_waiting, ~(1U << pos))); + NRF_DRV_USBD_EP_TRANSFER_EVENT(evt, ep, NRF_USBD_EP_OVERLOAD); + m_event_handler(&evt); + /* This endpoint will not be transmitted now, repeat the loop */ + continue; + } + else + { + /* Nothing to do - only check integrity if assertions are enabled */ + ASSERT(transfer.size == rx_size); + } + + if (!continue_transfer) + { + p_state->handler.consumer = NULL; + } + } + + usbd_dma_pending_set(); + m_ep_ready &= ~(1U << pos); + if (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRF_LOG_DEBUG( + "USB DMA process: Starting transfer on EP: %x, size: %u", + ep, + transfer.size); + } + /* Update number of currently transferred bytes */ + p_state->transfer_cnt += transfer.size; + /* Start transfer to the endpoint buffer */ + nrf_usbd_ep_easydma_set(ep, transfer.p_data.ptr, (uint32_t)transfer.size); + + if (nrf_drv_usbd_errata_104()) + { + uint32_t cnt_end = (uint32_t)(-1); + do + { + uint32_t cnt = (uint32_t)(-1); + do + { + nrf_usbd_event_clear(NRF_USBD_EVENT_STARTED); + usbd_dma_start(ep); + nrf_delay_us(2); + ++cnt; + }while (!nrf_usbd_event_check(NRF_USBD_EVENT_STARTED)); + if (cnt) + { + NRF_DRV_USBD_LOG_PROTO1_FIX_PRINTF(" DMA restarted: %u times", cnt); + } + + nrf_delay_us(30); + while (0 == (0x20 & *((volatile uint32_t *)(NRF_USBD_BASE + 0x474)))) + { + nrf_delay_us(2); + } + nrf_delay_us(1); + + ++cnt_end; + } while (!nrf_usbd_event_check(nrf_drv_usbd_ep_to_endevent(ep))); + if (cnt_end) + { + NRF_DRV_USBD_LOG_PROTO1_FIX_PRINTF(" DMA fully restarted: %u times", cnt_end); + } + } + else + { + usbd_dma_start(ep); + /* There is a lot of USBD registers that cannot be accessed during EasyDMA transfer. + * This is quick fix to maintain stability of the stack. + * It cost some performance but makes stack stable. */ + while (!nrf_usbd_event_check(nrf_drv_usbd_ep_to_endevent(ep))) + { + /* Empty */ + } + } + + if (NRF_USBD_DMAREQ_PROCESS_DEBUG) + { + NRF_LOG_DEBUG("USB DMA process - finishing"); + } + /* Transfer started - exit the loop */ + break; + } + } + else + { + if (NRF_USBD_DMAREQ_PROCESS_DEBUG) + { + NRF_LOG_DEBUG("USB DMA process - EasyDMA busy"); + } + } +} +/** @} */ + +typedef void (*nrf_drv_usbd_isr_t)(void); + +/** + * @brief USBD interrupt service runtimes + * + */ +static const nrf_drv_usbd_isr_t m_isr[] = +{ + [USBD_INTEN_USBRESET_Pos ] = ev_usbreset_handler, + [USBD_INTEN_STARTED_Pos ] = ev_started_handler, + [USBD_INTEN_ENDEPIN0_Pos ] = ev_dma_epin0_handler, + [USBD_INTEN_ENDEPIN1_Pos ] = ev_dma_epin1_handler, + [USBD_INTEN_ENDEPIN2_Pos ] = ev_dma_epin2_handler, + [USBD_INTEN_ENDEPIN3_Pos ] = ev_dma_epin3_handler, + [USBD_INTEN_ENDEPIN4_Pos ] = ev_dma_epin4_handler, + [USBD_INTEN_ENDEPIN5_Pos ] = ev_dma_epin5_handler, + [USBD_INTEN_ENDEPIN6_Pos ] = ev_dma_epin6_handler, + [USBD_INTEN_ENDEPIN7_Pos ] = ev_dma_epin7_handler, + [USBD_INTEN_EP0DATADONE_Pos] = ev_setup_data_handler, + [USBD_INTEN_ENDISOIN_Pos ] = ev_dma_epin8_handler, + [USBD_INTEN_ENDEPOUT0_Pos ] = ev_dma_epout0_handler, + [USBD_INTEN_ENDEPOUT1_Pos ] = ev_dma_epout1_handler, + [USBD_INTEN_ENDEPOUT2_Pos ] = ev_dma_epout2_handler, + [USBD_INTEN_ENDEPOUT3_Pos ] = ev_dma_epout3_handler, + [USBD_INTEN_ENDEPOUT4_Pos ] = ev_dma_epout4_handler, + [USBD_INTEN_ENDEPOUT5_Pos ] = ev_dma_epout5_handler, + [USBD_INTEN_ENDEPOUT6_Pos ] = ev_dma_epout6_handler, + [USBD_INTEN_ENDEPOUT7_Pos ] = ev_dma_epout7_handler, + [USBD_INTEN_ENDISOOUT_Pos ] = ev_dma_epout8_handler, + [USBD_INTEN_SOF_Pos ] = ev_sof_handler, + [USBD_INTEN_USBEVENT_Pos ] = ev_usbevent_handler, + [USBD_INTEN_EP0SETUP_Pos ] = ev_setup_handler, + [USBD_INTEN_EPDATA_Pos ] = ev_epdata_handler +}; + +/** + * @name Interrupt handlers + * + * @{ + */ +void USBD_IRQHandler(void) +{ + const uint32_t enabled = nrf_usbd_int_enable_get(); + uint32_t to_process = enabled; + uint32_t active = 0; + + /* Check all enabled interrupts */ + while (to_process) + { + uint8_t event_nr = __CLZ(__RBIT(to_process)); + if (nrf_usbd_event_get_and_clear((nrf_usbd_event_t)nrfx_bitpos_to_event(event_nr))) + { + active |= 1UL << event_nr; + } + to_process &= ~(1UL << event_nr); + } + + if (nrf_drv_usbd_errata_104()) + { + /* Event correcting */ + if ((!m_dma_pending) && (0 != (active & (USBD_INTEN_SOF_Msk)))) + { + uint8_t usbi, uoi, uii; + /* Testing */ + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7A9; + uii = (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + if (0 != uii) + { + uii &= (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + } + + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AA; + uoi = (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + if (0 != uoi) + { + uoi &= (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + } + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AB; + usbi = (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + if (0 != usbi) + { + usbi &= (uint8_t)(*((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + } + /* Processing */ + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AC; + uii &= (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + if (0 != uii) + { + uint8_t rb; + m_simulated_dataepstatus |= ((uint32_t)uii) << USBD_EPIN_BITPOS_0; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7A9; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = uii; + rb = (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + NRF_DRV_USBD_LOG_PROTO1_FIX_PRINTF(" uii: 0x%.2x (0x%.2x)", uii, rb); + } + + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AD; + uoi &= (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + if (0 != uoi) + { + uint8_t rb; + m_simulated_dataepstatus |= ((uint32_t)uoi) << USBD_EPOUT_BITPOS_0; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AA; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = uoi; + rb = (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + NRF_DRV_USBD_LOG_PROTO1_FIX_PRINTF(" uoi: 0x%.2u (0x%.2x)", uoi, rb); + } + + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AE; + usbi &= (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + if (0 != usbi) + { + uint8_t rb; + if (usbi & 0x01) + { + active |= USBD_INTEN_EP0SETUP_Msk; + } + if (usbi & 0x10) + { + active |= USBD_INTEN_USBRESET_Msk; + } + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7AB; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = usbi; + rb = (uint8_t)*((volatile uint32_t *)(NRF_USBD_BASE + 0x804)); + NRF_DRV_USBD_LOG_PROTO1_FIX_PRINTF(" usbi: 0x%.2u (0x%.2x)", usbi, rb); + } + + if (0 != (m_simulated_dataepstatus & + ~((1U << USBD_EPOUT_BITPOS_0) | (1U << USBD_EPIN_BITPOS_0)))) + { + active |= enabled & NRF_USBD_INT_DATAEP_MASK; + } + if (0 != (m_simulated_dataepstatus & + ((1U << USBD_EPOUT_BITPOS_0) | (1U << USBD_EPIN_BITPOS_0)))) + { + if (0 != (enabled & NRF_USBD_INT_EP0DATADONE_MASK)) + { + m_simulated_dataepstatus &= + ~((1U << USBD_EPOUT_BITPOS_0) | (1U << USBD_EPIN_BITPOS_0)); + active |= NRF_USBD_INT_EP0DATADONE_MASK; + } + } + } + } + + /* Process the active interrupts */ + bool setup_active = 0 != (active & NRF_USBD_INT_EP0SETUP_MASK); + active &= ~NRF_USBD_INT_EP0SETUP_MASK; + + while (active) + { + uint8_t event_nr = __CLZ(__RBIT(active)); + m_isr[event_nr](); + active &= ~(1UL << event_nr); + } + usbd_dmareq_process(); + + if (setup_active) + { + m_isr[USBD_INTEN_EP0SETUP_Pos](); + } +} + +/** @} */ +/** @} */ + +ret_code_t nrf_drv_usbd_init(nrf_drv_usbd_event_handler_t const event_handler) +{ + if (NULL == event_handler) + { + return NRF_ERROR_INVALID_PARAM; + } + if ( m_drv_state != NRFX_DRV_STATE_UNINITIALIZED) + { + return NRF_ERROR_INVALID_STATE; + } + + m_event_handler = event_handler; + m_drv_state = NRFX_DRV_STATE_INITIALIZED; + + uint8_t n; + for (n=0; n<NRF_USBD_EPIN_CNT; ++n) + { + nrf_drv_usbd_ep_t ep = NRF_DRV_USBD_EPIN(n); + nrf_drv_usbd_ep_max_packet_size_set(ep, NRF_USBD_EPISO_CHECK(ep) ? + (NRF_DRV_USBD_ISOSIZE / 2) : NRF_DRV_USBD_EPSIZE); + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + p_state->status = NRF_USBD_EP_OK; + p_state->handler.feeder = NULL; + p_state->transfer_cnt = 0; + } + for (n=0; n<NRF_USBD_EPOUT_CNT; ++n) + { + nrf_drv_usbd_ep_t ep = NRF_DRV_USBD_EPOUT(n); + nrf_drv_usbd_ep_max_packet_size_set(ep, NRF_USBD_EPISO_CHECK(ep) ? + (NRF_DRV_USBD_ISOSIZE / 2) : NRF_DRV_USBD_EPSIZE); + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + p_state->status = NRF_USBD_EP_OK; + p_state->handler.consumer = NULL; + p_state->transfer_cnt = 0; + } + + return NRF_SUCCESS; +} + +ret_code_t nrf_drv_usbd_uninit(void) +{ + if (m_drv_state != NRFX_DRV_STATE_INITIALIZED) + { + return NRF_ERROR_INVALID_STATE; + } + + m_event_handler = NULL; + m_drv_state = NRFX_DRV_STATE_UNINITIALIZED; + return NRF_SUCCESS; +} + +void nrf_drv_usbd_enable(void) +{ + ASSERT(m_drv_state == NRFX_DRV_STATE_INITIALIZED); + + /* Prepare for READY event receiving */ + nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK); + + if (nrf_drv_usbd_errata_187()) + { + CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006ED14)) = 0x00000003; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006ED14)) = 0x00000003; + } + CRITICAL_REGION_EXIT(); + } + + if (nrf_drv_usbd_errata_171()) + { + CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + } + CRITICAL_REGION_EXIT(); + } + + /* Enable the peripheral */ + nrf_usbd_enable(); + /* Waiting for peripheral to enable, this should take a few us */ + while (0 == (NRF_USBD_EVENTCAUSE_READY_MASK & nrf_usbd_eventcause_get())) + { + /* Empty loop */ + } + nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK); + + if (nrf_drv_usbd_errata_171()) + { + CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + } + + CRITICAL_REGION_EXIT(); + } + + if (nrf_drv_usbd_errata_187()) + { + CRITICAL_REGION_ENTER(); + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006ED14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006ED14)) = 0x00000000; + } + CRITICAL_REGION_EXIT(); + } + + if (nrf_drv_usbd_errata_166()) + { + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7E3; + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = 0x40; + __ISB(); + __DSB(); + } + + nrf_usbd_isosplit_set(NRF_USBD_ISOSPLIT_Half); + + m_ep_ready = (((1U << NRF_USBD_EPIN_CNT) - 1U) << USBD_EPIN_BITPOS_0); + m_ep_dma_waiting = 0; + usbd_dma_pending_clear(); + m_last_setup_dir = NRF_DRV_USBD_EPOUT0; + + m_drv_state = NRFX_DRV_STATE_POWERED_ON; +} + +void nrf_drv_usbd_disable(void) +{ + ASSERT(m_drv_state != NRFX_DRV_STATE_UNINITIALIZED); + + /* Stop just in case */ + nrf_drv_usbd_stop(); + + /* Disable all parts */ + nrf_usbd_int_disable(nrf_usbd_int_enable_get()); + nrf_usbd_disable(); + usbd_dma_pending_clear(); + m_drv_state = NRFX_DRV_STATE_INITIALIZED; +} + +void nrf_drv_usbd_start(bool enable_sof) +{ + ASSERT(m_drv_state == NRFX_DRV_STATE_POWERED_ON); + m_bus_suspend = false; + + uint32_t ints_to_enable = + NRF_USBD_INT_USBRESET_MASK | + NRF_USBD_INT_STARTED_MASK | + NRF_USBD_INT_ENDEPIN0_MASK | + NRF_USBD_INT_EP0DATADONE_MASK | + NRF_USBD_INT_ENDEPOUT0_MASK | + NRF_USBD_INT_USBEVENT_MASK | + NRF_USBD_INT_EP0SETUP_MASK | + NRF_USBD_INT_DATAEP_MASK; + + if (enable_sof || nrf_drv_usbd_errata_104()) + { + ints_to_enable |= NRF_USBD_INT_SOF_MASK; + } + + /* Enable all required interrupts */ + nrf_usbd_int_enable(ints_to_enable); + + /* Enable interrupt globally */ + NRFX_IRQ_PRIORITY_SET(USBD_IRQn, USBD_CONFIG_IRQ_PRIORITY); + NRFX_IRQ_ENABLE(USBD_IRQn); + + /* Enable pullups */ + nrf_usbd_pullup_enable(); +} + +void nrf_drv_usbd_stop(void) +{ + ASSERT(m_drv_state == NRFX_DRV_STATE_POWERED_ON); + + if(NRFX_IRQ_IS_ENABLED(USBD_IRQn)) + { + /* Abort transfers */ + usbd_ep_abort_all(); + + /* Disable pullups */ + nrf_usbd_pullup_disable(); + + /* Disable interrupt globally */ + NRFX_IRQ_DISABLE(USBD_IRQn); + + /* Disable all interrupts */ + nrf_usbd_int_disable(~0U); + } +} + +bool nrf_drv_usbd_is_initialized(void) +{ + return (m_drv_state >= NRFX_DRV_STATE_INITIALIZED); +} + +bool nrf_drv_usbd_is_enabled(void) +{ + return (m_drv_state >= NRFX_DRV_STATE_POWERED_ON); +} + +bool nrf_drv_usbd_is_started(void) +{ + return (nrf_drv_usbd_is_enabled() && NRFX_IRQ_IS_ENABLED(USBD_IRQn)); +} + +bool nrf_drv_usbd_suspend(void) +{ + bool suspended = false; + + CRITICAL_REGION_ENTER(); + if (m_bus_suspend) + { + usbd_ep_abort_all(); + + if (!(nrf_usbd_eventcause_get() & NRF_USBD_EVENTCAUSE_RESUME_MASK)) + { + nrf_usbd_lowpower_enable(); + if (nrf_usbd_eventcause_get() & NRF_USBD_EVENTCAUSE_RESUME_MASK) + { + nrf_usbd_lowpower_disable(); + } + else + { + suspended = true; + + if (nrf_drv_usbd_errata_171()) + { + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x00000000; + } + } + } + } + } + CRITICAL_REGION_EXIT(); + + return suspended; +} + +bool nrf_drv_usbd_wakeup_req(void) +{ + bool started = false; + + CRITICAL_REGION_ENTER(); + if (m_bus_suspend && nrf_usbd_lowpower_check()) + { + nrf_usbd_lowpower_disable(); + started = true; + + if (nrf_drv_usbd_errata_171()) + { + if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000) + { + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + *((volatile uint32_t *)(0x4006EC00)) = 0x00009375; + } + else + { + *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0; + } + + } + } + CRITICAL_REGION_EXIT(); + + return started; +} + +bool nrf_drv_usbd_suspend_check(void) +{ + return nrf_usbd_lowpower_check(); +} + +void nrf_drv_usbd_suspend_irq_config(void) +{ + nrf_usbd_int_disable(m_irq_disabled_in_suspend); +} + +void nrf_drv_usbd_active_irq_config(void) +{ + nrf_usbd_int_enable(m_irq_disabled_in_suspend); +} + +bool nrf_drv_usbd_bus_suspend_check(void) +{ + return m_bus_suspend; +} + +void nrf_drv_usbd_ep_max_packet_size_set(nrf_drv_usbd_ep_t ep, uint16_t size) +{ + /* Only power of 2 size allowed */ + ASSERT((size != 0) && (size & (size - 1)) == 0); + /* Packet size cannot be higher than maximum buffer size */ + ASSERT( ( NRF_USBD_EPISO_CHECK(ep) && (size <= usbd_ep_iso_capacity(ep))) + || + ((!NRF_USBD_EPISO_CHECK(ep)) && (size <= NRF_DRV_USBD_EPSIZE))); + + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + p_state->max_packet_size = size; +} + +uint16_t nrf_drv_usbd_ep_max_packet_size_get(nrf_drv_usbd_ep_t ep) +{ + usbd_drv_ep_state_t const * p_state = ep_state_access(ep); + return p_state->max_packet_size; +} + +bool nrf_drv_usbd_ep_enable_check(nrf_drv_usbd_ep_t ep) +{ + return nrf_usbd_ep_enable_check(ep_to_hal(ep)); +} + +void nrf_drv_usbd_ep_enable(nrf_drv_usbd_ep_t ep) +{ + nrf_usbd_int_enable(nrf_drv_usbd_ep_to_int(ep)); + + if(nrf_usbd_ep_enable_check(ep)) + { + return; + } + nrf_usbd_ep_enable(ep_to_hal(ep)); + if ((NRF_USBD_EP_NR_GET(ep) != 0) && NRF_USBD_EPOUT_CHECK(ep) && (!NRF_USBD_EPISO_CHECK(ep))) + { + CRITICAL_REGION_ENTER(); + nrf_drv_usbd_transfer_out_drop(ep); + m_ep_dma_waiting &= ~(1U << ep2bit(ep)); + CRITICAL_REGION_EXIT(); + } +} + +void nrf_drv_usbd_ep_disable(nrf_drv_usbd_ep_t ep) +{ + usbd_ep_abort(ep); + nrf_usbd_ep_disable(ep_to_hal(ep)); + nrf_usbd_int_disable(nrf_drv_usbd_ep_to_int(ep)); +} + +void nrf_drv_usbd_ep_default_config(void) +{ + nrf_usbd_int_disable( + NRF_USBD_INT_ENDEPIN1_MASK | + NRF_USBD_INT_ENDEPIN2_MASK | + NRF_USBD_INT_ENDEPIN3_MASK | + NRF_USBD_INT_ENDEPIN4_MASK | + NRF_USBD_INT_ENDEPIN5_MASK | + NRF_USBD_INT_ENDEPIN6_MASK | + NRF_USBD_INT_ENDEPIN7_MASK | + NRF_USBD_INT_ENDISOIN0_MASK | + NRF_USBD_INT_ENDEPOUT1_MASK | + NRF_USBD_INT_ENDEPOUT2_MASK | + NRF_USBD_INT_ENDEPOUT3_MASK | + NRF_USBD_INT_ENDEPOUT4_MASK | + NRF_USBD_INT_ENDEPOUT5_MASK | + NRF_USBD_INT_ENDEPOUT6_MASK | + NRF_USBD_INT_ENDEPOUT7_MASK | + NRF_USBD_INT_ENDISOOUT0_MASK + ); + nrf_usbd_int_enable(NRF_USBD_INT_ENDEPIN0_MASK | NRF_USBD_INT_ENDEPOUT0_MASK); + nrf_usbd_ep_all_disable(); +} + +ret_code_t nrf_drv_usbd_ep_transfer( + nrf_drv_usbd_ep_t ep, + nrf_drv_usbd_transfer_t const * const p_transfer) +{ + ret_code_t ret; + const uint8_t ep_bitpos = ep2bit(ep); + ASSERT(NULL != p_transfer); + + CRITICAL_REGION_ENTER(); + /* Setup data transaction can go only in one direction at a time */ + if ((NRF_USBD_EP_NR_GET(ep) == 0) && (ep != m_last_setup_dir)) + { + ret = NRF_ERROR_INVALID_ADDR; + if (NRF_USBD_FAILED_TRANSFERS_DEBUG && (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep)))) + { + NRF_LOG_DEBUG("USB driver: Transfer failed: Invalid EPr\n"); + } + } + else if ((m_ep_dma_waiting | ((~m_ep_ready) & USBD_EPIN_BIT_MASK)) & (1U << ep_bitpos)) + { + /* IN (Device -> Host) transfer has to be transmitted out to allow new transmission */ + ret = NRF_ERROR_BUSY; + if (NRF_USBD_FAILED_TRANSFERS_DEBUG) + { + NRF_LOG_DEBUG("USB driver: Transfer failed: EP is busy"); + } + } + else + { + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + /* Prepare transfer context and handler description */ + nrf_drv_usbd_transfer_t * p_context; + if (NRF_USBD_EPIN_CHECK(ep)) + { + p_context = m_ep_feeder_state + NRF_USBD_EP_NR_GET(ep); + if (nrfx_is_in_ram(p_transfer->p_data.tx)) + { + /* RAM */ + if (0 == (p_transfer->flags & NRF_DRV_USBD_TRANSFER_ZLP_FLAG)) + { + p_state->handler.feeder = nrf_drv_usbd_feeder_ram; + if (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRF_LOG_DEBUG( + "USB driver: Transfer called on endpoint %x, size: %u, mode: " + "RAM", + ep, + p_transfer->size); + } + } + else + { + p_state->handler.feeder = nrf_drv_usbd_feeder_ram_zlp; + if (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRF_LOG_DEBUG( + "USB driver: Transfer called on endpoint %x, size: %u, mode: " + "RAM_ZLP", + ep, + p_transfer->size); + } + } + } + else + { + /* Flash */ + if (0 == (p_transfer->flags & NRF_DRV_USBD_TRANSFER_ZLP_FLAG)) + { + p_state->handler.feeder = nrf_drv_usbd_feeder_flash; + if (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRF_LOG_DEBUG( + "USB driver: Transfer called on endpoint %x, size: %u, mode: " + "FLASH", + ep, + p_transfer->size); + } + } + else + { + p_state->handler.feeder = nrf_drv_usbd_feeder_flash_zlp; + if (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRF_LOG_DEBUG( + "USB driver: Transfer called on endpoint %x, size: %u, mode: " + "FLASH_ZLP", + ep, + p_transfer->size); + } + } + } + } + else + { + p_context = m_ep_consumer_state + NRF_USBD_EP_NR_GET(ep); + ASSERT((p_transfer->p_data.rx == NULL) || (nrfx_is_in_ram(p_transfer->p_data.rx))); + p_state->handler.consumer = nrf_drv_usbd_consumer; + } + *p_context = *p_transfer; + p_state->p_context = p_context; + + p_state->transfer_cnt = 0; + p_state->status = NRF_USBD_EP_OK; + m_ep_dma_waiting |= 1U << ep_bitpos; + ret = NRF_SUCCESS; + usbd_int_rise(); + } + CRITICAL_REGION_EXIT(); + return ret; +} + +ret_code_t nrf_drv_usbd_ep_handled_transfer( + nrf_drv_usbd_ep_t ep, + nrf_drv_usbd_handler_desc_t const * const p_handler) +{ + ret_code_t ret; + const uint8_t ep_bitpos = ep2bit(ep); + ASSERT(NULL != p_handler); + + CRITICAL_REGION_ENTER(); + /* Setup data transaction can go only in one direction at a time */ + if ((NRF_USBD_EP_NR_GET(ep) == 0) && (ep != m_last_setup_dir)) + { + ret = NRF_ERROR_INVALID_ADDR; + if (NRF_USBD_FAILED_TRANSFERS_DEBUG && (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep)))) + { + NRF_LOG_DEBUG("USB driver: Transfer failed: Invalid EP"); + } + } + else if ((m_ep_dma_waiting | ((~m_ep_ready) & USBD_EPIN_BIT_MASK)) & (1U << ep_bitpos)) + { + /* IN (Device -> Host) transfer has to be transmitted out to allow a new transmission */ + ret = NRF_ERROR_BUSY; + if (NRF_USBD_FAILED_TRANSFERS_DEBUG && (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep)))) + { + NRF_LOG_DEBUG("USB driver: Transfer failed: EP is busy");\ + } + } + else + { + /* Transfer can be configured now */ + usbd_drv_ep_state_t * p_state = ep_state_access(ep); + + p_state->transfer_cnt = 0; + p_state->handler = p_handler->handler; + p_state->p_context = p_handler->p_context; + p_state->status = NRF_USBD_EP_OK; + m_ep_dma_waiting |= 1U << ep_bitpos; + + ret = NRF_SUCCESS; + if (NRF_USBD_ISO_DEBUG || (!NRF_USBD_EPISO_CHECK(ep))) + { + NRF_LOG_DEBUG("USB driver: Transfer called on endpoint %x, mode: Handler", ep); + } + usbd_int_rise(); + } + CRITICAL_REGION_EXIT(); + return ret; +} + +void * nrf_drv_usbd_feeder_buffer_get(void) +{ + return m_tx_buffer; +} + +ret_code_t nrf_drv_usbd_ep_status_get(nrf_drv_usbd_ep_t ep, size_t * p_size) +{ + ret_code_t ret; + + usbd_drv_ep_state_t const * p_state = ep_state_access(ep); + CRITICAL_REGION_ENTER(); + *p_size = p_state->transfer_cnt; + ret = (p_state->handler.consumer == NULL) ? p_state->status : NRF_ERROR_BUSY; + CRITICAL_REGION_EXIT(); + return ret; +} + +size_t nrf_drv_usbd_epout_size_get(nrf_drv_usbd_ep_t ep) +{ + return nrf_usbd_epout_size_get(ep_to_hal(ep)); +} + +bool nrf_drv_usbd_ep_is_busy(nrf_drv_usbd_ep_t ep) +{ + return (0 != ((m_ep_dma_waiting | ((~m_ep_ready) & USBD_EPIN_BIT_MASK)) & (1U << ep2bit(ep)))); +} + +void nrf_drv_usbd_ep_stall(nrf_drv_usbd_ep_t ep) +{ + NRF_LOG_DEBUG("USB: EP %x stalled.", ep); + nrf_usbd_ep_stall(ep_to_hal(ep)); +} + +void nrf_drv_usbd_ep_stall_clear(nrf_drv_usbd_ep_t ep) +{ + nrf_usbd_ep_unstall(ep_to_hal(ep)); +} + +bool nrf_drv_usbd_ep_stall_check(nrf_drv_usbd_ep_t ep) +{ + return nrf_usbd_ep_is_stall(ep_to_hal(ep)); +} + +void nrf_drv_usbd_ep_dtoggle_clear(nrf_drv_usbd_ep_t ep) +{ + nrf_usbd_dtoggle_set(ep, NRF_USBD_DTOGGLE_DATA0); +} + +void nrf_drv_usbd_setup_get(nrf_drv_usbd_setup_t * const p_setup) +{ + memset(p_setup, 0, sizeof(nrf_drv_usbd_setup_t)); + p_setup->bmRequestType = nrf_usbd_setup_bmrequesttype_get(); + p_setup->bmRequest = nrf_usbd_setup_brequest_get(); + p_setup->wValue = nrf_usbd_setup_wvalue_get(); + p_setup->wIndex = nrf_usbd_setup_windex_get(); + p_setup->wLength = nrf_usbd_setup_wlength_get(); +} + +void nrf_drv_usbd_setup_data_clear(void) +{ + if (nrf_drv_usbd_errata_104()) + { + /* For this fix to work properly, it must be ensured that the task is + * executed twice one after another - blocking ISR. This is however a temporary + * solution to be used only before production version of the chip. */ + uint32_t primask_copy = __get_PRIMASK(); + __disable_irq(); + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0RCVOUT); + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0RCVOUT); + __set_PRIMASK(primask_copy); + } + else + { + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0RCVOUT); + } +} + +void nrf_drv_usbd_setup_clear(void) +{ + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS); +} + +void nrf_drv_usbd_setup_stall(void) +{ + NRF_LOG_DEBUG("Setup stalled."); + nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STALL); +} + +nrf_drv_usbd_ep_t nrf_drv_usbd_last_setup_dir_get(void) +{ + return m_last_setup_dir; +} + +void nrf_drv_usbd_transfer_out_drop(nrf_drv_usbd_ep_t ep) +{ + ASSERT(NRF_USBD_EPOUT_CHECK(ep)); + + if (nrf_drv_usbd_errata_sizeepout_rw()) + { + CRITICAL_REGION_ENTER(); + m_ep_ready &= ~(1U << ep2bit(ep)); + *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7C5 + (2u * NRF_USBD_EP_NR_GET(ep)); + *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = 0; + UNUSED_VARIABLE(((volatile uint32_t *)(NRF_USBD_BASE + 0x804))); + CRITICAL_REGION_EXIT(); + } + else + { + CRITICAL_REGION_ENTER(); + m_ep_ready &= ~(1U << ep2bit(ep)); + if (!NRF_USBD_EPISO_CHECK(ep)) + { + nrf_usbd_epout_clear(ep); + } + CRITICAL_REGION_EXIT(); + } +} + +#endif // NRF_MODULE_ENABLED(USBD) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd.h new file mode 100644 index 0000000..24a14f4 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd.h @@ -0,0 +1,943 @@ +/** + * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NRF_DRV_USBD_H__ +#define NRF_DRV_USBD_H__ + +#include "sdk_errors.h" +#include "nrf_usbd.h" +#include <stdint.h> +#include <stdbool.h> +#include "app_util.h" +#include "nrf_drv_usbd_errata.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup nrf_drv_usbd USB Device HAL and driver + * @ingroup nrf_drivers + * @brief @tagAPI52840 USB Device APIs. + * @details The USB Device HAL provides basic APIs for accessing + * the registers of the USBD. + * The USB Device driver provides APIs on a higher level. + * + * @{ + */ + +/** + * @name Possible schemes of DMA scheduling + * + * Definition of available configuration constants used by DMA scheduler + * @{ + */ + /** + * @brief Highly prioritized access + * + * Endpoint with lower number has always higher priority and its data would + * be transfered first. + * OUT endpoints ale processed before IN endpoints + */ + #define NRF_DRV_USBD_DMASCHEDULER_PRIORITIZED 0 + + /** + * @brief Round robin scheme + * + * All endpoints are processed in round-robin scheme. + * It means that when one endpoint is processed next in order would be + * the nearest with lower number. + * When no endpoints with lower number requires processing - then + * all endpoints from 0 are tested. + */ + #define NRF_DRV_USBD_DMASCHEDULER_ROUNDROBIN 1 + +/** @} */ + +/** + * @brief Number of bytes in the endpoint + * + * Constant that informs about endpoint size + */ +#define NRF_DRV_USBD_EPSIZE 64 + +/** + * @brief Number of bytes for isochronous endpoints + * + * Number of bytes for isochronous endpoints in total. + * This number would be shared between IN and OUT endpoint. + * It may be also assigned totaly to one endpoint. + * @sa nrf_usbd_isosplit_set + * @sa nrf_usbd_isosplit_get + */ +#define NRF_DRV_USBD_ISOSIZE 1024 + +/** + * @brief The size of internal feeder buffer. + * + * @sa nrf_drv_usbd_feeder_buffer_get + */ +#define NRF_DRV_USBD_FEEDER_BUFFER_SIZE NRF_DRV_USBD_EPSIZE + +/** + * @name Macros for creating endpoint identifiers + * + * Auxiliary macros to be used to create Endpoint identifier that is compatible + * with USB specification. + * @{ + */ + + /** + * @brief Create identifier for IN endpoint + * + * Simple macro to create IN endpoint identifier for given endpoint number. + * + * @param[in] n Endpoint number. + * + * @return Endpoint identifier that connects endpoint number and endpoint direction. + */ + #define NRF_DRV_USBD_EPIN(n) ((nrf_drv_usbd_ep_t)NRF_USBD_EPIN(n)) + /** + * @brief Create identifier for OUT endpoint + * + * Simple macro to create OUT endpoint identifier for given endpoint number. + * + * @param[in] n Endpoint number. + * + * @return Endpoint identifier that connects endpoint number and endpoint direction. + */ + #define NRF_DRV_USBD_EPOUT(n) ((nrf_drv_usbd_ep_t)NRF_USBD_EPOUT(n)) + +/** @} */ + +/** + * @brief Endpoint identifier + * + * Endpoint identifier used in the driver. + * This endpoint number is consistent with USB 2.0 specification. + */ +typedef enum +{ + NRF_DRV_USBD_EPOUT0 = NRF_USBD_EPOUT(0), /**< Endpoint OUT 0 */ + NRF_DRV_USBD_EPOUT1 = NRF_USBD_EPOUT(1), /**< Endpoint OUT 1 */ + NRF_DRV_USBD_EPOUT2 = NRF_USBD_EPOUT(2), /**< Endpoint OUT 2 */ + NRF_DRV_USBD_EPOUT3 = NRF_USBD_EPOUT(3), /**< Endpoint OUT 3 */ + NRF_DRV_USBD_EPOUT4 = NRF_USBD_EPOUT(4), /**< Endpoint OUT 4 */ + NRF_DRV_USBD_EPOUT5 = NRF_USBD_EPOUT(5), /**< Endpoint OUT 5 */ + NRF_DRV_USBD_EPOUT6 = NRF_USBD_EPOUT(6), /**< Endpoint OUT 6 */ + NRF_DRV_USBD_EPOUT7 = NRF_USBD_EPOUT(7), /**< Endpoint OUT 7 */ + NRF_DRV_USBD_EPOUT8 = NRF_USBD_EPOUT(8), /**< Endpoint OUT 8 */ + + NRF_DRV_USBD_EPIN0 = NRF_USBD_EPIN(0), /**< Endpoint IN 0 */ + NRF_DRV_USBD_EPIN1 = NRF_USBD_EPIN(1), /**< Endpoint IN 1 */ + NRF_DRV_USBD_EPIN2 = NRF_USBD_EPIN(2), /**< Endpoint IN 2 */ + NRF_DRV_USBD_EPIN3 = NRF_USBD_EPIN(3), /**< Endpoint IN 3 */ + NRF_DRV_USBD_EPIN4 = NRF_USBD_EPIN(4), /**< Endpoint IN 4 */ + NRF_DRV_USBD_EPIN5 = NRF_USBD_EPIN(5), /**< Endpoint IN 5 */ + NRF_DRV_USBD_EPIN6 = NRF_USBD_EPIN(6), /**< Endpoint IN 6 */ + NRF_DRV_USBD_EPIN7 = NRF_USBD_EPIN(7), /**< Endpoint IN 7 */ + NRF_DRV_USBD_EPIN8 = NRF_USBD_EPIN(8), /**< Endpoint IN 8 */ +}nrf_drv_usbd_ep_t; + +/** + * @brief Events generated by the library + * + * Enumeration of possible events that may be generated by the library. + */ +typedef enum +{ + NRF_DRV_USBD_EVT_SOF, /**< Start Of Frame event on USB bus detected */ + NRF_DRV_USBD_EVT_RESET, /**< Reset condition on USB bus detected */ + NRF_DRV_USBD_EVT_SUSPEND, /**< This device should go to suspend mode now */ + NRF_DRV_USBD_EVT_RESUME, /**< This device should resume from suspend now */ + NRF_DRV_USBD_EVT_WUREQ, /**< Wakeup request - the USBD peripheral is ready to generate WAKEUP signal after exiting low power mode. */ + NRF_DRV_USBD_EVT_SETUP, /**< Setup frame received and decoded */ + NRF_DRV_USBD_EVT_EPTRANSFER, /**< + * For Rx (OUT: Host->Device): + * 1. The packet has been received but there is no buffer prepared for transfer already. + * 2. Whole transfer has been finished + * + * For Tx (IN: Device->Host): + * The last packet from requested transfer has been transfered over USB bus and acknowledged + */ + NRF_DRV_USBD_EVT_CNT /**< Number of defined events */ +}nrf_drv_usbd_event_type_t; + +/** + * @brief Possible endpoint error codes + * + * Error codes that may be returned with @ref NRF_DRV_USBD_EVT_EPTRANSFER + */ +typedef enum +{ + NRF_USBD_EP_OK, /**< No error */ + NRF_USBD_EP_WAITING, /**< Data received, no buffer prepared already - waiting for configured transfer */ + NRF_USBD_EP_OVERLOAD, /**< Received number of bytes cannot fit given buffer + * This error would also be returned when next_transfer function has been defined + * but currently received data cannot fit completely in current buffer. + * No data split from single endpoint transmission is supported. + * + * When this error is reported - data is left inside endpoint buffer. + * Clear endpoint or prepare new buffer and read it. + */ + NRF_USBD_EP_ABORTED, /**< EP0 transfer can be aborted when new setup comes. + * Any other transfer can be aborted by USB reset or library stopping. + */ +}nrf_drv_usbd_ep_status_t; + + +/** + * @brief Event structure + * + * Structure passed to event handler + */ +typedef struct +{ + nrf_drv_usbd_event_type_t type; + union + { + struct{ + uint16_t framecnt; //!< Current value of frame counter + }sof; //!< Data aviable for @ref NRF_DRV_USBD_EVT_SOF + struct{ + nrf_drv_usbd_ep_t ep; //!< Endpoint number + }isocrc; + struct{ + nrf_drv_usbd_ep_t ep; //!< Endpoint number + nrf_drv_usbd_ep_status_t status; //!< Status for the endpoint + }eptransfer; + }data; +}nrf_drv_usbd_evt_t; + +/** + * @brief USBD event callback function type. + * + * @param[in] p_event Event information structure. + */ +typedef void (*nrf_drv_usbd_event_handler_t)(nrf_drv_usbd_evt_t const * const p_event); + +/** + * @brief Universal data pointer. + * + * Universal data pointer that can be used for any type of transfer. + */ +typedef union +{ + void const * tx; //!< Constant TX buffer pointer. + void * rx; //!< Writable RX buffer pointer. + uint32_t ptr; //!< Numeric value used internally by the library. +}nrf_drv_usbd_data_ptr_t; + +/** + * @brief Structure to be filled with information about the next transfer. + * + * This is used mainly for transfer feeders and consumers. + * It describes a single endpoint transfer and therefore the size of the buffer + * can never be higher than the endpoint size. + */ +typedef struct +{ + nrf_drv_usbd_data_ptr_t p_data; //!< Union with available data pointers used by the library. + size_t size; //!< Size of the requested transfer. +}nrf_drv_usbd_ep_transfer_t; + +/** + * @brief Flags for the current transfer. + * + * Flags configured for the transfer that can be merged using the bitwise 'or' operator (|). + */ +typedef enum +{ + NRF_DRV_USBD_TRANSFER_ZLP_FLAG = 1U << 0, //!< Add a zero-length packet. +}nrf_drv_usbd_transfer_flags_t; + +/** + * @brief Total transfer configuration. + * + * This structure is used to configure total transfer information. + * It is used by internal built-in feeders and consumers. + */ +typedef struct +{ + nrf_drv_usbd_data_ptr_t p_data; //!< Union with available data pointers used by the library. + size_t size; //!< Total size of the requested transfer. + uint32_t flags; //!< Transfer flags. + /**< Use the @ref nrf_drv_usbd_transfer_flags_t values. */ +}nrf_drv_usbd_transfer_t; + + +/** + * @brief Auxiliary macro for declaring IN transfer description with flags. + * + * The base macro for creating transfers with any configuration option. + * + * @param name Instance name. + * @param tx_buff Buffer to transfer. + * @param tx_size Transfer size. + * @param tx_flags Flags for the transfer (see @ref nrf_drv_usbd_transfer_flags_t). + * + * @return Configured variable with total transfer description. + */ +#define NRF_DRV_USBD_TRANSFER_IN_FLAGS(name, tx_buff, tx_size, tx_flags) \ + const nrf_drv_usbd_transfer_t name = { \ + .p_data = { .tx = (tx_buff) }, \ + .size = (tx_size), \ + .flags = (tx_flags) \ + } + +/** + * @brief Helper macro for declaring IN transfer description + * + * Normal transfer mode, no ZLP would be automatically generated. + * + * @sa nrf_drv_usbd_transfer_t + * @sa NRF_DRV_USBD_TRANSFER_IN_ZLP + * + * @param name Instance name + * @param tx_buff Buffer to transfer + * @param tx_size Transfer size + * + * @return Configured variable with total transfer description + * + */ +#define NRF_DRV_USBD_TRANSFER_IN(name, tx_buff, tx_size) \ + NRF_DRV_USBD_TRANSFER_IN_FLAGS(name, tx_buff, tx_size, 0) + +/** + * @brief Helper macro for declaring IN transfer description + * + * ZLP mode - Zero Length Packet would be generated on the end of the transfer + * (always!). + * + * @sa nrf_drv_usbd_transfer_t + * @sa NRF_DRV_USBD_TRANSFER_IN + * + * @param name Instance name + * @param tx_buff Buffer to transfer + * @param tx_size Transfer size + * + * @return Configured variable with total transfer description + */ +#define NRF_DRV_USBD_TRANSFER_IN_ZLP(name, tx_buff, tx_size) \ + NRF_DRV_USBD_TRANSFER_IN_FLAGS( \ + name, \ + tx_buff, \ + tx_size, \ + NRF_DRV_USBD_TRANSFER_ZLP_FLAG) + +/** + * @brief Helper macro for declaring OUT transfer item (@ref nrf_drv_usbd_transfer_t) + * + * @param name Instance name + * @param rx_buff Buffer to transfer + * @param rx_size Transfer size + * */ +#define NRF_DRV_USBD_TRANSFER_OUT(name, rx_buff, rx_size) \ + const nrf_drv_usbd_transfer_t name = { \ + .p_data = { .rx = (rx_buff) }, \ + .size = (rx_size), \ + .flags = 0 \ + } + +/** + * @brief USBD transfer feeder. + * + * Pointer for a transfer feeder. + * Transfer feeder is a feedback function used to prepare a single + * TX (Device->Host) endpoint transfer. + * + * The transfers provided by the feeder must be simple: + * - The size of the transfer provided by this function is limited to a single endpoint buffer. + * Bigger transfers are not handled automatically in this case. + * - Flash transfers are not automatically supported- you must copy them to the RAM buffer before. + * + * @note + * This function may use @ref nrf_drv_usbd_feeder_buffer_get to gain a temporary buffer + * that can be used to prepare transfer. + * + * @param[out] p_next Structure with the data for the next transfer to be filled. + * Required only if the function returns true. + * @param[in,out] p_context Context variable configured with the transfer. + * @param[in] ep_size The endpoint size. + * + * @retval false The current transfer is the last one - you do not need to call + * the function again. + * @retval true There is more data to be prepared and when the current transfer + * finishes, the feeder function is expected to be called again. + */ +typedef bool (*nrf_drv_usbd_feeder_t)( + nrf_drv_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size); + +/** + * @brief USBD transfer consumer. + * + * Pointer for a transfer consumer. + * Transfer consumer is a feedback function used to prepare a single + * RX (Host->Device) endpoint transfer. + * + * The transfer must provide a buffer big enough to fit the whole data from the endpoint. + * Otherwise, the NRF_USBD_EP_OVERLOAD event is generated. + * + * @param[out] p_next Structure with the data for the next transfer to be filled. + * Required only if the function returns true. + * @param[in,out] p_context Context variable configured with the transfer. + * @param[in] ep_size The endpoint size. + * @param[in] data_size Number of received bytes in the endpoint buffer. + * + * @retval false Current transfer is the last one - you do not need to call + * the function again. + * @retval true There is more data to be prepared and when current transfer + * finishes, the feeder function is expected to be called again. + */ +typedef bool (*nrf_drv_usbd_consumer_t)( + nrf_drv_usbd_ep_transfer_t * p_next, + void * p_context, + size_t ep_size, + size_t data_size); + +/** + * @brief Universal transfer handler. + * + * Union with feeder and consumer function pointer. + */ +typedef union +{ + nrf_drv_usbd_feeder_t feeder; //!< Feeder function pointer. + nrf_drv_usbd_consumer_t consumer; //!< Consumer function pointer. +}nrf_drv_usbd_handler_t; + +/** + * @brief USBD transfer descriptor. + * + * Universal structure that may hold the setup for callback configuration for + * IN or OUT type of the transfer. + */ +typedef struct +{ + nrf_drv_usbd_handler_t handler; //!< Handler for the current transfer, function pointer. + void * p_context; //!< Context for the transfer handler. +}nrf_drv_usbd_handler_desc_t; + +/** + * @brief Setup packet structure + * + * Structure that contains interpreted SETUP packet. + */ +typedef struct +{ + uint8_t bmRequestType; //!< byte 0 + uint8_t bmRequest; //!< byte 1 + uint16_t wValue; //!< byte 2 + uint16_t wIndex; //!< byte 4, 5 + uint16_t wLength; //!< byte 6, 7 +}nrf_drv_usbd_setup_t; + +/** + * @brief Library initialization + * + * @param[in] event_handler Event handler provided by the user. + */ +ret_code_t nrf_drv_usbd_init(nrf_drv_usbd_event_handler_t const event_handler); + +/** + * @brief Library deinitialization + */ +ret_code_t nrf_drv_usbd_uninit(void); + +/** + * @brief Enable the USBD port + * + * After calling this function USBD peripheral would be enabled. + * The USB LDO would be enabled. + * Enabled USBD peripheral would request HFCLK. + * This function does not enable external oscillator, so if it is not enabled by other part of the + * program after enabling USBD driver HFINT would be used for the USBD peripheral. + * It is perfectly fine until USBD is started. See @ref nrf_drv_usbd_start. + * + * In normal situation this function should be called in reaction to USBDETECTED + * event from POWER peripheral. + * + * Interrupts and USB pins pull-up would stay disabled until @ref nrf_drv_usbd_start + * function is called. + */ +void nrf_drv_usbd_enable(void); + +/** + * @brief Disable the USBD port + * + * After calling this function USBD peripheral would be disabled. + * No events would be detected or processed by the library. + * Clock for the peripheral would be disconnected. + */ +void nrf_drv_usbd_disable(void); + +/** + * @brief Start USB functionality + * + * After calling this function USBD peripheral should be fully functional + * and all new incoming events / interrupts would be processed by the library. + * + * Also only after calling this function host sees new connected device. + * + * Call this function when USBD power LDO regulator is ready - on USBPWRRDY event + * from POWER peripheral. + * + * Before USBD interrupts are enabled, external HFXO is requested. + * + * @param enable_sof The flag that is used to enable SOF processing. + * If it is false, SOF interrupt is left disabled and will not be generated. + * This improves power saving if SOF is not required. + * + * @note If the isochronous endpoints are going to be used, + * it is required to enable the SOF. + * In other case any isochronous endpoint would stay busy + * after first transmission. + */ +void nrf_drv_usbd_start(bool enable_sof); + +/** + * @brief Stop USB functionality + * + * This function disables USBD pull-up and interrupts. + * + * The HFXO request is released in this function. + * + * @note + * This function can also be used to logically disconnect USB from the HOST that + * would force it to enumerate device after calling @ref nrf_drv_usbd_start. + */ +void nrf_drv_usbd_stop(void); + +/** + * @brief Check if driver is initialized + * + * @retval false Driver is not initialized + * @retval true Driver is initialized + */ +bool nrf_drv_usbd_is_initialized(void); + +/** + * @brief Check if driver is enabled + * + * @retval false Driver is disabled + * @retval true Driver is enabled + */ +bool nrf_drv_usbd_is_enabled(void); + +/** + * @brief Check if driver is started + * + * @retval false Driver is not started + * @retval true Driver is started (fully functional) + * @note The USBD peripheral interrupt state is checked + */ +bool nrf_drv_usbd_is_started(void); + +/** + * @brief Suspend USBD operation + * + * The USBD peripheral is forced to go into the low power mode. + * The function has to be called in the reaction to @ref NRF_DRV_USBD_EVT_SUSPEND event + * when the firmware is ready. + * + * After successful call of this function most of the USBD registers would be unavailable. + * + * @note Check returned value for the feedback if suspending was successful. + * + * @retval true USBD peripheral successfully suspended + * @retval false USBD peripheral was not suspended due to resume detection. + * + */ +bool nrf_drv_usbd_suspend(void); + +/** + * @brief Start wake up procedure + * + * The USBD peripheral is forced to quit the low power mode. + * After calling this function all the USBD registers would be available. + * + * The hardware starts measuring time when wake up is possible. + * This may take 0-5 ms depending on how long the SUSPEND state was kept on the USB line. + + * When NRF_DRV_USBD_EVT_WUREQ event is generated it means that Wake Up signaling has just been + * started on the USB lines. + * + * @note Do not expect only @ref NRF_DRV_USBD_EVT_WUREQ event. + * There always may appear @ref NRF_DRV_USBD_EVT_RESUME event. + * @note NRF_DRV_USBD_EVT_WUREQ event means that Remote WakeUp signal + * has just begun to be generated. + * This may take up to 20 ms for the bus to become active. + * + * @retval true WakeUp procedure started. + * @retval false No WakeUp procedure started - bus is already active. + */ +bool nrf_drv_usbd_wakeup_req(void); + +/** + * @brief Check if USBD is in SUSPEND mode + * + * @note This is the information about peripheral itself, not about the bus state. + * + * @retval true USBD peripheral is suspended + * @retval false USBD peripheral is active + */ +bool nrf_drv_usbd_suspend_check(void); + +/** + * @brief Enable only interrupts that should be processed in SUSPEND mode + * + * Auxiliary function to help with SUSPEND mode integration. + * It enables only the interrupts that can be properly processed without stable HFCLK. + * + * Normally all the interrupts are enabled. + * Use this function to suspend interrupt processing that may require stable HFCLK until the + * clock is enabled. + * + * @sa nrf_drv_usbd_active_irq_config + */ +void nrf_drv_usbd_suspend_irq_config(void); + +/** + * @brief Default active interrupt configuration + * + * Default interrupt configuration. + * Use in a pair with @ref nrf_drv_usbd_active_irq_config. + * + * @sa nrf_drv_usbd_suspend_irq_config + */ +void nrf_drv_usbd_active_irq_config(void); + +/** + * @brief Check the bus state + * + * This function checks if the bus state is suspended + * + * @note The value returned by this function changes on SUSPEND and RESUME event processing. + * + * @retval true USBD bus is suspended + * @retval false USBD bus is active + */ +bool nrf_drv_usbd_bus_suspend_check(void); + +/** + * @brief Configure packet size that should be supported by the endpoint + * + * The real endpoint buffer size is always the same. + * This value sets max packet size that would be transmitted over the endpoint. + * This is required by the library + * + * @param[in] ep Endpoint number + * @param[in] size Required maximum packet size + * + * @note Endpoint size is always set to @ref NRF_DRV_USBD_EPSIZE or @ref NRF_DRV_USBD_ISOSIZE / 2 + * when @ref nrf_drv_usbd_ep_enable function is called. + */ +void nrf_drv_usbd_ep_max_packet_size_set(nrf_drv_usbd_ep_t ep, uint16_t size); + +/** + * @brief Get configured endpoint packet size + * + * Function to get configured endpoint size on the buffer. + * + * @param[in] ep Endpoint number + * + * @return Maximum pocket size configured on selected endpoint + */ +uint16_t nrf_drv_usbd_ep_max_packet_size_get(nrf_drv_usbd_ep_t ep); + +/** + * @brief Check if the selected endpoint is enabled. + * + * @param ep Endpoint number to check. + * + * @retval true Endpoint is enabled. + * @retval false Endpoint is disabled. + */ +bool nrf_drv_usbd_ep_enable_check(nrf_drv_usbd_ep_t ep); + +/** + * @brief Enable selected endpoint + * + * This function enables endpoint itself and its interrupts. + * @param ep Endpoint number to enable + * + * @note + * Max packet size is set to endpoint default maximum value. + * + * @sa nrf_drv_usbd_ep_max_packet_size_set + */ +void nrf_drv_usbd_ep_enable(nrf_drv_usbd_ep_t ep); + +/** + * @brief Disable selected endpoint + * + * This function disables endpoint itself and its interrupts. + * @param ep Endpoint number to disable + */ +void nrf_drv_usbd_ep_disable(nrf_drv_usbd_ep_t ep); + +/** + * @brief Disable all endpoints except for EP0 + * + * Disable all endpoints that can be disabled in USB device while it is still active. + */ +void nrf_drv_usbd_ep_default_config(void); + +/** + * @brief Start sending data over endpoint + * + * Function initializes endpoint transmission. + * This is asynchronous function - it finishes immediately after configuration + * for transmission is prepared. + * + * @note Data buffer pointed by p_data have to be kept active till + * @ref NRF_DRV_USBD_EVT_EPTRANSFER event is generated. + * + * @param[in] ep Endpoint number. + * For IN endpoint sending would be initiated. + * For OUT endpoint receiving would be initiated. + * @param[in] p_transfer + * + * @retval NRF_ERROR_BUSY Selected endpoint is pending. + * @retval NRF_ERROR_INVALID_ADDR Unexpected transfer on EPIN0 or EPOUT0. + * @retval NRF_ERROR_FORBIDDEN Endpoint stalled. + * @retval NRF_SUCCESS Transfer queued or started. + */ +ret_code_t nrf_drv_usbd_ep_transfer( + nrf_drv_usbd_ep_t ep, + nrf_drv_usbd_transfer_t const * const p_transfer); + +/** + * @brief Start sending data over the endpoint using the transfer handler function. + * + * This function initializes an endpoint transmission. + * Just before data is transmitted, the transfer handler + * is called and it prepares a data chunk. + * + * @param[in] ep Endpoint number. + * For an IN endpoint, sending is initiated. + * For an OUT endpoint, receiving is initiated. + * @param p_handler Transfer handler - feeder for IN direction and consumer for + * OUT direction. + * + * @retval NRF_ERROR_BUSY Selected endpoint is pending. + * @retval NRF_ERROR_INVALID_ADDR Unexpected transfer on EPIN0 or EPOUT0. + * @retval NRF_ERROR_FORBIDDEN Endpoint stalled. + * @retval NRF_SUCCESS Transfer queued or started. + */ +ret_code_t nrf_drv_usbd_ep_handled_transfer( + nrf_drv_usbd_ep_t ep, + nrf_drv_usbd_handler_desc_t const * const p_handler); + +/** + * @brief Get the temporary buffer to be used by the feeder. + * + * This buffer is used for TX transfers and it can be reused automatically + * when the transfer is finished. + * Use it for transfer preparation. + * + * May be used inside the feeder configured in @ref nrf_drv_usbd_ep_handled_transfer. + * + * @return Pointer to the buffer that can be used temporarily. + * + * @sa NRF_DRV_USBD_FEEDER_BUFFER_SIZE + */ +void * nrf_drv_usbd_feeder_buffer_get(void); + +/** + * @brief Get the information about last finished or current transfer + * + * Function returns the status of the last buffer set for transfer on selected endpoint. + * The status considers last buffer set by @ref nrf_drv_usbd_ep_transfer function or + * by transfer callback function. + * + * @param[in] ep Endpoint number. + * @param[out] p_size Information about the current/last transfer size. + * + * @retval NRF_SUCCESS Transfer already finished + * @retval NRF_ERROR_BUSY Ongoing transfer + * @retval NRF_ERROR_DATA_SIZE Too much of data received that cannot fit into buffer and cannot be splited into chunks. + * This may happen if buffer size is not a multiplication of endpoint buffer size. + */ +ret_code_t nrf_drv_usbd_ep_status_get(nrf_drv_usbd_ep_t ep, size_t * p_size); + +/** + * @brief Get number of received bytes + * + * Get the number of received bytes. + * The function behavior is undefined when called on IN endpoint. + * + * @param ep Endpoint number. + * + * @return Number of received bytes + */ +size_t nrf_drv_usbd_epout_size_get(nrf_drv_usbd_ep_t ep); + +/** + * @brief Check if endpoint buffer is ready or is under USB IP control + * + * Function to test if endpoint is busy. + * Endpoint that is busy cannot be accessed by MCU. + * It means that: + * - OUT (TX) endpoint: Last uploaded data is still in endpoint and is waiting + * to be received by the host. + * - IN (RX) endpoint: Endpoint is ready to receive data from the host + * and the endpoint does not have any data. + * When endpoint is not busy: + * - OUT (TX) endpoint: New data can be uploaded. + * - IN (RX) endpoint: New data can be downloaded using @ref nrf_drv_usbd_ep_transfer + * function. + */ +bool nrf_drv_usbd_ep_is_busy(nrf_drv_usbd_ep_t ep); + +/** + * @brief Stall endpoint + * + * Stall endpoit to send error information during next transfer request from + * the host. + * + * @note To stall endpoint it is safer to use @ref nrf_drv_usbd_setup_stall + * @note Stalled endpoint would not be cleared when DMA transfer finishes. + * + * @param ep Endpoint number to stall + * + */ +void nrf_drv_usbd_ep_stall(nrf_drv_usbd_ep_t ep); + +/** + * @brief Clear stall flag on endpoint + * + * This function clears endpoint that is stalled. + * @note + * If it is OUT endpoint (receiving) it would be also prepared for reception. + * It means that busy flag would be set. + * @note + * In endpoint (transmitting) would not be cleared - it gives possibility to + * write new data before transmitting. + */ +void nrf_drv_usbd_ep_stall_clear(nrf_drv_usbd_ep_t ep); + +/** + * @brief Check if endpoint is stalled + * + * This function gets stall state of selected endpoint + * + * @param ep Endpoint number to check + */ +bool nrf_drv_usbd_ep_stall_check(nrf_drv_usbd_ep_t ep); + +/** + * @brief Clear current endpoint data toggle + * + * @param ep Endpoint number to clear + */ +void nrf_drv_usbd_ep_dtoggle_clear(nrf_drv_usbd_ep_t ep); + +/** + * @brief Get parsed setup data + * + * Function fills the parsed setup data structure. + * + * @param[out] p_setup Pointer to data structure that would be filled by + * parsed data. + */ +void nrf_drv_usbd_setup_get(nrf_drv_usbd_setup_t * const p_setup); + +/** + * @brief Clear only for data transmission on setup endpoint + * + * This function may be called if any more data in control write transfer is expected. + * Clears only OUT endpoint to be able to take another OUT data token. + * It does not allow STATUS stage. + * @sa nrf_drv_usbd_setup_clear + */ +void nrf_drv_usbd_setup_data_clear(void); + +/** + * @brief Clear setup endpoint + * + * This function acknowledges setup when SETUP command was received and processed. + * It has to be called if no data respond for the SETUP command is sent. + */ +void nrf_drv_usbd_setup_clear(void); + +/** + * @brief Stall setup endpoint + * + * Mark and error on setup endpoint. + */ +void nrf_drv_usbd_setup_stall(void); + +/** +* @note +* This function locks interrupts that may be costly. +* It is good idea to test if the endpoint is still busy before calling this function: +* @code + (m_ep_dma_waiting & (1U << ep2bit(ep))) +* @endcode +* This function would check it again, but it makes it inside critical section. +*/ +void nrf_drv_usbd_ep_abort(nrf_drv_usbd_ep_t ep); + +/** + * @brief Get the information about expected transfer SETUP data direction + * + * Function returns the information about last expected transfer direction. + * + * @retval NRF_DRV_USBD_EPOUT0 Expecting OUT (Host->Device) direction or no data + * @retval NRF_DRV_USBD_EPIN0 Expecting IN (Device->Host) direction + */ +nrf_drv_usbd_ep_t nrf_drv_usbd_last_setup_dir_get(void); + +/** + * @brief Drop transfer on OUT endpoint + * + * @param[in] ep OUT endpoint ID + */ +void nrf_drv_usbd_transfer_out_drop(nrf_drv_usbd_ep_t ep); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* NRF_DRV_USBD_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd_errata.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd_errata.h new file mode 100644 index 0000000..ad24f3c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/drivers_nrf/usbd/nrf_drv_usbd_errata.h @@ -0,0 +1,193 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NRF_DRV_USBD_ERRATA_H__ +#define NRF_DRV_USBD_ERRATA_H__ + +#include <stdbool.h> +/** + * @defgroup nrf_drv_usbd_errata Functions to check if selected PAN is present in current chip + * @{ + * @ingroup nrf_drv_usbd + * + * Functions here are checking the presence of an error in current chip. + * The checking is done at runtime based on the microcontroller version. + * This file is subject to removal when nRF51840 prototype support is removed. + */ + +#ifndef NRF_DRV_USBD_ERRATA_ENABLE +/** + * @brief The constant that informs if errata should be enabled at all + * + * If this constant is set to 0, all the Errata bug fixes will be automatically disabled. + */ +#define NRF_DRV_USBD_ERRATA_ENABLE 1 +#endif + +/** + * @brief Internal auxiliary function to check if the program is running on NRF52840 chip + * @retval true It is NRF52480 chip + * @retval false It is other chip + */ +static inline bool nrf_drv_usbd_errata_type_52840(void) +{ + return ((((*(uint32_t *)0xF0000FE0) & 0xFF) == 0x08) && + (((*(uint32_t *)0xF0000FE4) & 0x0F) == 0x0)); +} + +/** + * @brief Internal auxiliary function to check if the program is running on first sample of + * NRF52840 chip + * @retval true It is NRF52480 chip and it is first sample version + * @retval false It is other chip + */ +static inline bool nrf_drv_usbd_errata_type_52840_proto1(void) +{ + return ( nrf_drv_usbd_errata_type_52840() && + ( ((*(uint32_t *)0xF0000FE8) & 0xF0) == 0x00 ) && + ( ((*(uint32_t *)0xF0000FEC) & 0xF0) == 0x00 ) ); +} + +/** + * @brief Internal auxiliary function to check if the program is running on first final product of + * NRF52840 chip + * @retval true It is NRF52480 chip and it is first final product + * @retval false It is other chip + */ +static inline bool nrf_drv_usbd_errata_type_52840_fp1(void) +{ + return ( nrf_drv_usbd_errata_type_52840() && + ( ((*(uint32_t *)0xF0000FE8) & 0xF0) == 0x10 ) && + ( ((*(uint32_t *)0xF0000FEC) & 0xF0) == 0x00 ) ); +} + +/** + * @brief Function to check if chip requires errata 104 + * + * Errata: USBD: EPDATA event is not always generated. + * + * @retval true Errata should be implemented + * @retval false Errata should not be implemented + */ +static inline bool nrf_drv_usbd_errata_104(void) +{ + return NRF_DRV_USBD_ERRATA_ENABLE && nrf_drv_usbd_errata_type_52840_proto1(); +} + +/** + * @brief Function to check if chip requires errata 154 + * + * Errata: During setup read/write transfer USBD acknowledges setup stage without SETUP task. + * + * @retval true Errata should be implemented + * @retval false Errata should not be implemented + */ +static inline bool nrf_drv_usbd_errata_154(void) +{ + return NRF_DRV_USBD_ERRATA_ENABLE && nrf_drv_usbd_errata_type_52840_proto1(); +} + +/** + * @brief Function to check if chip requires errata 166 + * + * Errata: ISO double buffering not functional + * + * @retval true Errata should be implemented + * @retval false Errata should not be implemented + */ +static inline bool nrf_drv_usbd_errata_166(void) +{ + return NRF_DRV_USBD_ERRATA_ENABLE && true; +} + +/** + * @brief Function to check if chip requires errata 171 + * + * Errata: USBD might not reach its active state. + * + * @retval true Errata should be implemented + * @retval false Errata should not be implemented + */ +static inline bool nrf_drv_usbd_errata_171(void) +{ + return NRF_DRV_USBD_ERRATA_ENABLE && true; +} + +/** + * @brief Function to check if chip requires errata 187 + * + * Errata: USB cannot be enabled + * + * @retval true Errata should be implemented + * @retval false Errata should not be implemented + */ +static inline bool nrf_drv_usbd_errata_187(void) +{ + return NRF_DRV_USBD_ERRATA_ENABLE && nrf_drv_usbd_errata_type_52840_fp1(); +} + +/** + * @brief Function to check if chip requires errata ??? + * + * Errata: SIZE.EPOUT not writable + * + * @retval true Errata should be implemented + * @retval false Errata should not be implemented + */ +static inline bool nrf_drv_usbd_errata_sizeepout_rw(void) +{ + return NRF_DRV_USBD_ERRATA_ENABLE && nrf_drv_usbd_errata_type_52840_proto1(); +} + +/** + * @brief Function to check if chip requires errata 199 + * + * Errata: USBD cannot receive tasks during DMA + * + * @retval true Errata should be implemented + * @retval false Errata should not be implemented + */ +static inline bool nrf_drv_usb_errata_199(void) +{ + return NRF_DRV_USBD_ERRATA_ENABLE && true; +} + +/** @} */ +#endif /* NRF_DRV_USBD_ERRATA_H__ */ |