初始版本

This commit is contained in:
xiaozhengsheng
2025-08-19 09:49:41 +08:00
parent 10f1ddf1c1
commit 6df0f7d96e
2974 changed files with 1712873 additions and 54 deletions

View File

@@ -0,0 +1,95 @@
/**
* Copyright (c) 2012 - 2020, 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

View File

@@ -0,0 +1,123 @@
/**
* Copyright (c) 2016 - 2020, 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;
}

View File

@@ -0,0 +1,166 @@
/**
* Copyright (c) 2014 - 2020, 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__ */

View File

@@ -0,0 +1,56 @@
/**
* Copyright (c) 2015 - 2020, 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__

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2014 - 2020, 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;
}

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2014 - 2020, 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__ */

View File

@@ -0,0 +1,188 @@
/**
* Copyright (c) 2009 - 2020, 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
}
}
/**
* @}
*/

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2009 - 2020, 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

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2012 - 2020, 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

View File

@@ -0,0 +1,244 @@
/**
* Copyright (c) 2009 - 2020, 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" */

View File

@@ -0,0 +1,105 @@
/**
* Copyright (c) 2009 - 2020, 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

View File

@@ -0,0 +1,629 @@
/**
* Copyright (c) 2014 - 2020, 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
/** @} */

View File

@@ -0,0 +1,206 @@
/**
* Copyright (c) 2014 - 2020, 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

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2012 - 2020, 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

View File

@@ -0,0 +1,331 @@
/**
* Copyright (c) 2009 - 2020, 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" */

View File

@@ -0,0 +1,137 @@
/**
* Copyright (c) 2009 - 2020, 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

View File

@@ -0,0 +1,519 @@
/**
* Copyright (c) 2009 - 2020, 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" */