560 lines
21 KiB
C
560 lines
21 KiB
C
|
/**
|
||
|
* Copyright (c) 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 "nrf21540.h"
|
||
|
#include "nrf_assert.h"
|
||
|
#include "nrf21540_defs.h"
|
||
|
#include "nrf21540_macro.h"
|
||
|
#include "nrf_radio.h"
|
||
|
#include "nrf_ppi.h"
|
||
|
#include "nrf_gpiote.h"
|
||
|
#include "nrf_timer.h"
|
||
|
#include "boards.h"
|
||
|
#if NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
|
||
|
#include "nrf_egu.h"
|
||
|
#endif
|
||
|
|
||
|
#define NRF21540_BUSY_CHECK(mode) \
|
||
|
if (mode == NRF21540_EXEC_MODE_BLOCKING) \
|
||
|
{ \
|
||
|
while(is_driver_busy()) \
|
||
|
{ \
|
||
|
\
|
||
|
} \
|
||
|
} \
|
||
|
else if (is_driver_busy()) \
|
||
|
{ \
|
||
|
return NRF_ERROR_BUSY; \
|
||
|
}
|
||
|
|
||
|
#define NRF21540_ERROR_CHECK(invalid_state_condition) \
|
||
|
if (device_state_get() == NRF21540_STATE_ERROR) \
|
||
|
{ \
|
||
|
m_nrf21540_data.busy = false; \
|
||
|
return NRF_ERROR_INTERNAL; \
|
||
|
} \
|
||
|
if (invalid_state_condition) \
|
||
|
{ \
|
||
|
m_nrf21540_data.busy = false; \
|
||
|
return NRF_ERROR_INVALID_STATE; \
|
||
|
}
|
||
|
|
||
|
/**@brief nRF21540 chip state.
|
||
|
*
|
||
|
* @details driver state variable possible values.
|
||
|
*/
|
||
|
typedef enum {
|
||
|
NRF21540_STATE_OFF, ///< Chip inactive, line PDN is low, SPI communication impossible.
|
||
|
NRF21540_STATE_READY, ///< SPI is active, but nether transmit nor receive can be performed.
|
||
|
NRF21540_STATE_TX, ///< Transmit state - chip can perform transmiting data.
|
||
|
NRF21540_STATE_RX, ///< Receive state - chip can receive data.
|
||
|
NRF21540_STATE_ERROR, ///< Invalid state - requires reinit.
|
||
|
} nrf21540_state_t;
|
||
|
|
||
|
/**@brief nRF21540 static data. */
|
||
|
static struct
|
||
|
{
|
||
|
volatile nrf21540_state_t cur_state; ///< driver state variable.
|
||
|
volatile nrf21540_trx_t cur_direction; ///< currently serviced radio communication direction.
|
||
|
volatile bool busy; ///< driver is busy at the moment (during changing state phase).
|
||
|
#if NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
|
||
|
volatile uint32_t shorts;
|
||
|
#endif
|
||
|
} m_nrf21540_data;
|
||
|
|
||
|
/**@brief Function checks if nRF21540 driver is busy now.
|
||
|
*
|
||
|
* @details Based on driver busy variable.
|
||
|
*
|
||
|
* @return true if nRF21540 driver is busy.
|
||
|
*/
|
||
|
static inline bool is_driver_busy(void)
|
||
|
{
|
||
|
return m_nrf21540_data.busy;
|
||
|
}
|
||
|
|
||
|
/**@brief Function checks if nRF21540 is powered down.
|
||
|
*
|
||
|
* @details Based on driver state variable.
|
||
|
*
|
||
|
* @return true if nRF21540 is in power down state.
|
||
|
*/
|
||
|
static inline bool is_device_off(void)
|
||
|
{
|
||
|
return m_nrf21540_data.cur_state == NRF21540_STATE_OFF;
|
||
|
}
|
||
|
|
||
|
/**@brief Function checks if nRF21540 is powered up state.
|
||
|
*
|
||
|
* @details Based on driver state variable.
|
||
|
*
|
||
|
* @return true if nRF21540 is in power up state.
|
||
|
*/
|
||
|
static inline bool is_device_on(void)
|
||
|
{
|
||
|
return m_nrf21540_data.cur_state != NRF21540_STATE_OFF;
|
||
|
}
|
||
|
|
||
|
/**@brief Function checks if nRF21540 can transmit or receive data.
|
||
|
*
|
||
|
* @details Based on driver state variable.
|
||
|
*
|
||
|
* @return true if nRF21540 is in TX or RX mode.
|
||
|
*/
|
||
|
static inline bool is_device_ready_for_transmission(void)
|
||
|
{
|
||
|
return (m_nrf21540_data.cur_state == NRF21540_STATE_TX ||
|
||
|
m_nrf21540_data.cur_state == NRF21540_STATE_RX);
|
||
|
}
|
||
|
|
||
|
/**@brief Function changes driver state.
|
||
|
*
|
||
|
* @details Changes driver state variable value.
|
||
|
*
|
||
|
* @param[in] new_state state that will be store.
|
||
|
*/
|
||
|
static inline void device_state_set(nrf21540_state_t new_state)
|
||
|
{
|
||
|
m_nrf21540_data.cur_state = new_state;
|
||
|
}
|
||
|
|
||
|
/**@brief Function returns driver state variable value.
|
||
|
*
|
||
|
* @details Based on driver state variable.
|
||
|
*
|
||
|
* @return @ref nrf21540_state_t based state variable value.
|
||
|
*/
|
||
|
static inline nrf21540_state_t device_state_get(void)
|
||
|
{
|
||
|
return m_nrf21540_data.cur_state;
|
||
|
}
|
||
|
|
||
|
/**@brief Function returns task related to transmission direction.
|
||
|
*
|
||
|
* @param[in] dir direction of radio transfer. See @nrf21540_trx_t.
|
||
|
*
|
||
|
* @return task corresponding to given transmission direction.
|
||
|
*/
|
||
|
static inline nrf_radio_task_t nrf21540_task_get(nrf21540_trx_t dir)
|
||
|
{
|
||
|
return dir == NRF21540_TX ? NRF_RADIO_TASK_TXEN : NRF_RADIO_TASK_RXEN;
|
||
|
}
|
||
|
|
||
|
/**@brief Function clears and disbles all PPI connections used by nRF21540 driver.
|
||
|
*
|
||
|
* @details Changes driver state variable value.
|
||
|
*/
|
||
|
static void ppi_cleanup(void)
|
||
|
{
|
||
|
nrf_ppi_channel_disable(NRF21540_PDN_PPI_CHANNEL);
|
||
|
nrf_ppi_channel_disable(NRF21540_USER_PPI_CHANNEL);
|
||
|
nrf_ppi_channel_disable(NRF21540_TRX_PPI_CHANNEL);
|
||
|
nrf_ppi_channel_and_fork_endpoint_setup(NRF21540_PDN_PPI_CHANNEL, 0, 0, 0);
|
||
|
nrf_ppi_channel_and_fork_endpoint_setup(NRF21540_USER_PPI_CHANNEL, 0, 0, 0);
|
||
|
nrf_ppi_channel_and_fork_endpoint_setup(NRF21540_TRX_PPI_CHANNEL, 0, 0, 0);
|
||
|
}
|
||
|
|
||
|
/**@brief Function clears nRF21540 driver events. */
|
||
|
static void events_clear()
|
||
|
{
|
||
|
nrf_timer_event_clear(NRF21540_TIMER, NRF21540_TIMER_CC_PD_PG_EVENT);
|
||
|
nrf_timer_event_clear(NRF21540_TIMER, NRF21540_TIMER_CC_START_TO_PDN_UP_EVENT);
|
||
|
NRF21540_RADIO_EVENT_CLEAR(NRF21540_RADIO_EVENT_READY);
|
||
|
NRF21540_RADIO_EVENT_CLEAR(NRF21540_RADIO_EVENT_DISABLED);
|
||
|
}
|
||
|
|
||
|
/**@brief Timer interrupt handler.
|
||
|
*
|
||
|
* @details checking time related events occurences and changing driver state if necessary.
|
||
|
*/
|
||
|
void NRF21540_TIMER_IRQ_HANDLER(void)
|
||
|
{
|
||
|
if (nrf_timer_event_check(NRF21540_TIMER, NRF21540_TIMER_CC_PD_PG_EVENT))
|
||
|
{
|
||
|
nrf_timer_event_clear(NRF21540_TIMER, NRF21540_TIMER_CC_PD_PG_EVENT);
|
||
|
if (is_device_off() && nrf_gpio_pin_read(NRF21540_PDN_PIN) == 1)
|
||
|
{
|
||
|
device_state_set(NRF21540_STATE_READY);
|
||
|
}
|
||
|
else if (is_device_on() && nrf_gpio_pin_read(NRF21540_PDN_PIN) == 0)
|
||
|
{
|
||
|
device_state_set(NRF21540_STATE_OFF);
|
||
|
ppi_cleanup();
|
||
|
m_nrf21540_data.busy = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
device_state_set(NRF21540_STATE_ERROR);
|
||
|
ppi_cleanup();
|
||
|
m_nrf21540_data.busy = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**@brief nRF21540 interrupt handler.
|
||
|
*
|
||
|
* @details checking radio related events occurences and changing driver state if necessary.
|
||
|
*/
|
||
|
void NRF21540_RADIO_IRQ_HANDLER(void)
|
||
|
{
|
||
|
if (NRF21540_RADIO_EVENT_CHECK(NRF21540_RADIO_EVENT_READY))
|
||
|
{
|
||
|
NRF21540_RADIO_EVENT_CLEAR(NRF21540_RADIO_EVENT_READY);
|
||
|
nrf_ppi_channel_disable(NRF21540_USER_PPI_CHANNEL);
|
||
|
#if NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
|
||
|
if (NRF21540_RADIO_SHORTS_ENABLE_CHECK(RADIO_SHORTS_READY_START_Msk))
|
||
|
{
|
||
|
nrf_radio_task_trigger(NRF_RADIO_TASK_START);
|
||
|
}
|
||
|
#endif
|
||
|
if (device_state_get() == NRF21540_STATE_READY)
|
||
|
{
|
||
|
device_state_set(m_nrf21540_data.cur_direction == NRF21540_TX ?
|
||
|
NRF21540_STATE_TX : NRF21540_STATE_RX);
|
||
|
ppi_cleanup();
|
||
|
NRF21540_RADIO_INT_DISABLE(NRF21540_RADIO_READY_Msk);
|
||
|
m_nrf21540_data.busy = false;
|
||
|
}
|
||
|
}
|
||
|
if (NRF21540_RADIO_EVENT_CHECK(NRF21540_RADIO_EVENT_DISABLED))
|
||
|
{
|
||
|
NRF21540_RADIO_EVENT_CLEAR(NRF21540_RADIO_EVENT_DISABLED);
|
||
|
nrf_ppi_channel_disable(NRF21540_USER_PPI_CHANNEL);
|
||
|
nrf_timer_task_trigger(NRF21540_TIMER, NRF_TIMER_TASK_START);
|
||
|
if (is_device_ready_for_transmission())
|
||
|
{
|
||
|
NRF21540_RADIO_INT_DISABLE(NRF21540_RADIO_DISABLED_Msk);
|
||
|
device_state_set(NRF21540_STATE_READY);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**@brief Function resets nRF21540 driver.
|
||
|
*
|
||
|
* @details sets driver state variable to NRF21540_STATE_OFF value,
|
||
|
* cleans all used PPIs and events.
|
||
|
*/
|
||
|
static void driver_reset(void)
|
||
|
{
|
||
|
device_state_set(NRF21540_STATE_OFF);
|
||
|
ppi_cleanup();
|
||
|
events_clear();
|
||
|
NRF21540_RADIO_INT_DISABLE(NRF21540_RADIO_INTERRUPT_MASK);
|
||
|
m_nrf21540_data.busy = false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**@brief Function sets either TX or RX direction.
|
||
|
*
|
||
|
* @details Configuration of all necessarily peripherals to transmit or receive data,
|
||
|
* dependenly on interface used (SPI, or GPIO). Procedure configures nRF21540 chip and
|
||
|
* starts transmitting/receiving. Procedure will be started immediately if
|
||
|
* @ref trigger_event is 0. Otherwise event which address is @ref trigger_event value
|
||
|
* will start procedure.
|
||
|
*
|
||
|
* @param[in] dir RX or TX communication that will be performed.
|
||
|
* @param[in] trigger_event address of event which will trigger the procedure.
|
||
|
* @param[in] mode if NRF21540_EXEC_MODE_BLOCKING the function will wait for tx/rx
|
||
|
* possibility.
|
||
|
* @return NRF_ERROR_INTERNAL when driver is in error state.
|
||
|
* Reinitialization is required.
|
||
|
* NRF_ERROR_INVALID_STATE when nRF21540's state isn't proper
|
||
|
* to perform the operation (@sa nrf21540_state_t).
|
||
|
* NRF_ERROR_BUSY when driver performs another operation at
|
||
|
* the moment.
|
||
|
* NRF_SUCCESS on success.
|
||
|
*/
|
||
|
static ret_code_t trx_set(nrf21540_trx_t dir, uint32_t trigger_event,
|
||
|
nrf21540_execution_mode_t mode)
|
||
|
{
|
||
|
ASSERT(!(mode == NRF21540_EXEC_MODE_BLOCKING && trigger_event != 0));
|
||
|
NRF21540_BUSY_CHECK(mode);
|
||
|
NRF21540_ERROR_CHECK((dir == NRF21540_TX && device_state_get() == NRF21540_STATE_TX) ||
|
||
|
(dir == NRF21540_RX && device_state_get() == NRF21540_STATE_RX));
|
||
|
uint32_t ramp_up_time = nrf_radio_modecnf0_ru_get() ? FAST_RAMP_UP_TIME : RAMP_UP_TIME;
|
||
|
nrf_radio_task_t radio_task_to_start = nrf21540_task_get(dir);
|
||
|
m_nrf21540_data.busy = true;
|
||
|
events_clear();
|
||
|
NRF21540_RADIO_INT_ENABLE(NRF21540_RADIO_READY_Msk);
|
||
|
if (is_device_off())
|
||
|
{
|
||
|
nrf_ppi_channel_endpoint_setup(NRF21540_PDN_PPI_CHANNEL,
|
||
|
(uint32_t)nrf_timer_event_address_get(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_START_TO_PDN_UP_EVENT),
|
||
|
nrf_gpiote_task_addr_get(NRF21540_PDN_GPIOTE_TASK_SET));
|
||
|
nrf_ppi_channel_enable(NRF21540_PDN_PPI_CHANNEL);
|
||
|
nrf_timer_cc_write(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_PD_PG_CHANNEL,
|
||
|
ramp_up_time - NRF21540_PA_PG_TRX_TIME_US);
|
||
|
nrf_timer_cc_write(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_START_TO_PDN_UP_CHANNEL,
|
||
|
ramp_up_time - NRF21540_PA_PG_TRX_TIME_US - NRF21540_PD_PG_TIME_US);
|
||
|
#if NRF21540_USE_GPIO_MANAGEMENT
|
||
|
nrf21540_gpio_trx_enable(dir);
|
||
|
#elif NRF21540_USE_SPI_MANAGEMENT
|
||
|
nrf21540_spim_for_trx_configure(dir, NRF21540_ENABLE);
|
||
|
#endif
|
||
|
nrf_timer_shorts_enable(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_FINISHED_CHANNEL_STOP_MASK |
|
||
|
NRF21540_TIMER_CC_FINISHED_CHANNEL_CLEAR_MASK);
|
||
|
NRF21540_RADIO_SHORTS_ENABLE(RADIO_SHORTS_READY_START_Msk);
|
||
|
if (trigger_event == 0)
|
||
|
{
|
||
|
//start immediately.
|
||
|
nrf_timer_task_trigger(NRF21540_TIMER, NRF_TIMER_TASK_START);
|
||
|
nrf_radio_task_trigger(radio_task_to_start);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//start when user event occurs.
|
||
|
nrf_ppi_channel_and_fork_endpoint_setup(
|
||
|
NRF21540_USER_PPI_CHANNEL,
|
||
|
trigger_event,
|
||
|
(uint32_t) nrf_timer_task_address_get(NRF21540_TIMER, NRF_TIMER_TASK_START),
|
||
|
(uint32_t) nrf_radio_task_address_get(radio_task_to_start));
|
||
|
nrf_ppi_channel_enable(NRF21540_USER_PPI_CHANNEL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// at the moment we are not able to switch direction on the fly.
|
||
|
// @todo switching between RXEN and TXEN.
|
||
|
NRF21540_ERROR_CHECK(device_state_get() == NRF21540_STATE_RX);
|
||
|
if (trigger_event == 0)
|
||
|
{
|
||
|
nrf_radio_task_trigger(radio_task_to_start);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// start when user event occurs
|
||
|
nrf_ppi_channel_endpoint_setup(
|
||
|
NRF21540_USER_PPI_CHANNEL,
|
||
|
trigger_event,
|
||
|
(uint32_t) nrf_radio_task_address_get(radio_task_to_start));
|
||
|
nrf_ppi_channel_enable(NRF21540_USER_PPI_CHANNEL);
|
||
|
}
|
||
|
}
|
||
|
m_nrf21540_data.cur_direction = dir;
|
||
|
if (mode == NRF21540_EXEC_MODE_BLOCKING)
|
||
|
{
|
||
|
while (!is_device_ready_for_transmission());
|
||
|
}
|
||
|
return NRF_SUCCESS;
|
||
|
}
|
||
|
|
||
|
ret_code_t nrf21540_init(void)
|
||
|
{
|
||
|
driver_reset();
|
||
|
// GPIOTE for PDN pin configuration
|
||
|
nrf_gpiote_task_configure(NRF21540_PDN_GPIOTE_CHANNEL_NO,
|
||
|
NRF21540_PDN_PIN,
|
||
|
(nrf_gpiote_polarity_t) GPIOTE_CONFIG_POLARITY_None,
|
||
|
NRF_GPIOTE_INITIAL_VALUE_LOW);
|
||
|
nrf_gpiote_task_enable(NRF21540_PDN_GPIOTE_CHANNEL_NO);
|
||
|
nrf21540_gpio_init();
|
||
|
NVIC_SetPriority(NRF21540_TIMER_IRQn, NRF21540_INTERRUPT_PRIORITY);
|
||
|
NVIC_EnableIRQ(NRF21540_TIMER_IRQn);
|
||
|
nrf_timer_int_enable(NRF21540_TIMER, NRF21540_TIM_INTERRUPT_MASK);
|
||
|
#if NRF21540_USE_SPI_MANAGEMENT
|
||
|
ret_code_t ret = NRF_SUCCESS;
|
||
|
ret = nrf21540_spi_init();
|
||
|
if (ret != NRF_SUCCESS)
|
||
|
{
|
||
|
device_state_set(NRF21540_STATE_ERROR);
|
||
|
return ret;
|
||
|
}
|
||
|
#endif //NRF21540_USE_SPI_MANAGEMENT
|
||
|
#if NRF21540_DO_NOT_USE_NATIVE_RADIO_IRQ_HANDLER
|
||
|
nrf_ppi_channel_endpoint_setup(NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL,
|
||
|
nrf_radio_event_address_get(NRF_RADIO_EVENT_READY),
|
||
|
(uint32_t)nrf_egu_task_address_get(NRF21540_EGU, NRF21540_RADIO_READY_EGU_TASK));
|
||
|
nrf_ppi_channel_enable(NRF21540_RADIO_READY_TO_EGU_PPI_CHANNEL);
|
||
|
nrf_ppi_channel_endpoint_setup(NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL,
|
||
|
nrf_radio_event_address_get(NRF_RADIO_EVENT_DISABLED),
|
||
|
(uint32_t)nrf_egu_task_address_get(NRF21540_EGU, NRF21540_RADIO_DISABLED_EGU_TASK));
|
||
|
nrf_ppi_channel_enable(NRF21540_RADIO_DISABLED_TO_EGU_PPI_CHANNEL);
|
||
|
#endif
|
||
|
NVIC_SetPriority(NRF21540_RADIO_IRQn, NRF21540_INTERRUPT_PRIORITY);
|
||
|
NVIC_EnableIRQ(NRF21540_RADIO_IRQn);
|
||
|
return NRF_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
ret_code_t nrf21540_pdn_drive(bool state, nrf21540_execution_mode_t mode)
|
||
|
{
|
||
|
NRF21540_BUSY_CHECK(mode);
|
||
|
NRF21540_ERROR_CHECK((state == true && is_device_on()) ||
|
||
|
(state == false && is_device_off()));
|
||
|
nrf21540_state_t final_state;
|
||
|
if (state)
|
||
|
{
|
||
|
final_state = NRF21540_STATE_READY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
final_state = NRF21540_STATE_OFF;
|
||
|
}
|
||
|
nrf_timer_cc_write(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_PD_PG_CHANNEL,
|
||
|
state ? NRF21540_PD_PG_TIME_US : 0);
|
||
|
nrf_timer_shorts_enable(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_FINISHED_CHANNEL_STOP_MASK |
|
||
|
NRF21540_TIMER_CC_FINISHED_CHANNEL_CLEAR_MASK);
|
||
|
nrf_timer_event_clear(NRF21540_TIMER, NRF21540_TIMER_CC_PD_PG_EVENT);
|
||
|
nrf_gpiote_task_force(NRF21540_PDN_GPIOTE_CHANNEL_NO,
|
||
|
!state ? NRF_GPIOTE_INITIAL_VALUE_LOW : NRF_GPIOTE_INITIAL_VALUE_HIGH);
|
||
|
nrf_timer_task_trigger(NRF21540_TIMER, NRF_TIMER_TASK_START);
|
||
|
if (mode == NRF21540_EXEC_MODE_BLOCKING)
|
||
|
{
|
||
|
while (device_state_get() != final_state)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
}
|
||
|
return NRF_SUCCESS;
|
||
|
}
|
||
|
|
||
|
ret_code_t nrf21540_tx_set(uint32_t user_trigger_event, nrf21540_execution_mode_t mode)
|
||
|
{
|
||
|
NRF21540_ERROR_CHECK(device_state_get() == NRF21540_STATE_TX);
|
||
|
return trx_set(NRF21540_TX, user_trigger_event, mode);
|
||
|
}
|
||
|
|
||
|
ret_code_t nrf21540_rx_set(uint32_t user_trigger_event, nrf21540_execution_mode_t mode)
|
||
|
{
|
||
|
NRF21540_ERROR_CHECK(device_state_get() == NRF21540_STATE_RX);
|
||
|
return trx_set(NRF21540_RX, user_trigger_event, mode);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool nrf21540_is_error(void)
|
||
|
{
|
||
|
return device_state_get() == NRF21540_STATE_ERROR ? true : false;
|
||
|
}
|
||
|
|
||
|
ret_code_t nrf21540_ant_set(nrf21540_antenna_t antenna)
|
||
|
{
|
||
|
NRF21540_BUSY_CHECK(NRF21540_EXEC_MODE_NON_BLOCKING);
|
||
|
return nrf21540_gpio_ant_set(antenna);
|
||
|
}
|
||
|
|
||
|
|
||
|
ret_code_t nrf21540_pwr_mode_set(nrf21540_pwr_mode_t mode)
|
||
|
{
|
||
|
NRF21540_BUSY_CHECK(NRF21540_EXEC_MODE_NON_BLOCKING);
|
||
|
#if NRF21540_USE_GPIO_MANAGEMENT
|
||
|
return nrf21540_gpio_pwr_mode_set(mode);
|
||
|
#elif NRF21540_USE_SPI_MANAGEMENT
|
||
|
return nrf21540_spi_pwr_mode_set(mode);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
ret_code_t nrf21540_power_down(uint32_t user_trigger_event, nrf21540_execution_mode_t mode)
|
||
|
{
|
||
|
ASSERT(!(mode == NRF21540_EXEC_MODE_BLOCKING && user_trigger_event != 0));
|
||
|
NRF21540_ERROR_CHECK(is_device_off());
|
||
|
NRF21540_BUSY_CHECK(mode);
|
||
|
m_nrf21540_data.busy = true;
|
||
|
events_clear();
|
||
|
NRF21540_RADIO_INT_ENABLE(NRF21540_RADIO_DISABLED_Msk);
|
||
|
if (device_state_get() == NRF21540_STATE_READY)
|
||
|
{
|
||
|
// when device is in ready state we jus driving PDN line down and switch off the radio.
|
||
|
(void)nrf21540_pdn_drive(false, NRF21540_EXEC_MODE_NON_BLOCKING);
|
||
|
nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// When device is in tx/rx state we have to leave it and then drive PDN down.
|
||
|
// Line PDN should be driven low after 5us from triggering TXEN/RXEN.
|
||
|
uint32_t * trx_drv_task_address;
|
||
|
nrf21540_trx_t cur_direction;
|
||
|
if (device_state_get() == NRF21540_STATE_TX)
|
||
|
{
|
||
|
cur_direction = NRF21540_TX;
|
||
|
}
|
||
|
else if (device_state_get() == NRF21540_STATE_RX)
|
||
|
{
|
||
|
cur_direction = NRF21540_RX;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return NRF_ERROR_INTERNAL;
|
||
|
}
|
||
|
nrf_ppi_channel_endpoint_setup(NRF21540_PDN_PPI_CHANNEL,
|
||
|
(uint32_t)nrf_timer_event_address_get(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_TRX_PG_EVENT),
|
||
|
nrf_gpiote_task_addr_get(NRF21540_PDN_GPIOTE_TASK_CLR));
|
||
|
nrf_ppi_channel_enable(NRF21540_PDN_PPI_CHANNEL);
|
||
|
nrf_timer_shorts_enable(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_FINISHED_CHANNEL_STOP_MASK |
|
||
|
NRF21540_TIMER_CC_FINISHED_CHANNEL_CLEAR_MASK);
|
||
|
nrf_timer_cc_write(NRF21540_TIMER,
|
||
|
NRF21540_TIMER_CC_TRX_PG_CHANNEL,
|
||
|
NRF21540_TRX_PG_TIME_US);
|
||
|
#if NRF21540_USE_GPIO_MANAGEMENT
|
||
|
trx_drv_task_address = (uint32_t*) nrf21540_gpio_trx_task_start_address_get(cur_direction,
|
||
|
NRF21540_DISABLE);
|
||
|
#elif NRF21540_USE_SPI_MANAGEMENT
|
||
|
nrf21540_spim_for_trx_configure(cur_direction, NRF21540_DISABLE);
|
||
|
trx_drv_task_address = (uint32_t*) nrf21540_spim_trx_task_start_address_get();
|
||
|
#endif
|
||
|
if (user_trigger_event == 0)
|
||
|
{
|
||
|
*trx_drv_task_address = 1;
|
||
|
nrf_radio_task_trigger(NRF_RADIO_TASK_DISABLE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// start when user event occurs.
|
||
|
nrf_ppi_channel_and_fork_endpoint_setup(
|
||
|
NRF21540_USER_PPI_CHANNEL,
|
||
|
user_trigger_event,
|
||
|
(uint32_t)nrf_radio_task_address_get(NRF_RADIO_TASK_DISABLE),
|
||
|
(uint32_t) trx_drv_task_address);
|
||
|
nrf_ppi_channel_enable(NRF21540_USER_PPI_CHANNEL);
|
||
|
}
|
||
|
if (mode == NRF21540_EXEC_MODE_BLOCKING)
|
||
|
{
|
||
|
while (is_device_on());
|
||
|
}
|
||
|
}
|
||
|
return NRF_SUCCESS;
|
||
|
}
|