/** * Copyright (c) 2009 - 2018, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** @file * @addtogroup nrf_radio_test_example_main * @{ */ #include "radio_test.h" #include #include "nrf.h" static uint8_t packet[256]; static uint8_t mode_; static uint8_t txpower_; static uint8_t channel_start_; static uint8_t channel_end_; static uint8_t channel_; static bool sweep_tx_; /** * @brief Function for initializing Timer 0 in 24 bit timer mode with 1 us resolution. */ static void timer0_init(uint8_t delayms) { NRF_TIMER0->TASKS_STOP = 1; // Create an Event-Task shortcut to clear Timer 1 on COMPARE[0] event. NRF_TIMER0->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos); NRF_TIMER0->MODE = TIMER_MODE_MODE_Timer; NRF_TIMER0->BITMODE = (TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos); NRF_TIMER0->PRESCALER = 4; // 1us resolution NRF_TIMER0->INTENSET = (TIMER_INTENSET_COMPARE0_Set << TIMER_INTENSET_COMPARE0_Pos); // Sample update needs to happen as soon as possible. The earliest possible moment is MAX_SAMPLE_LEVELS // ticks before changing the output duty cycle. NRF_TIMER0->CC[0] = (uint32_t)delayms * 1000; NRF_TIMER0->TASKS_START = 1; } /** * @brief Function for generating an 8 bit random number using the internal random generator. */ static uint32_t rnd8(void) { NRF_RNG->EVENTS_VALRDY = 0; while (NRF_RNG->EVENTS_VALRDY == 0) { // Do nothing. } return NRF_RNG->VALUE; } /** * @brief Function for generating a 32 bit random number using the internal random generator. */ static uint32_t rnd32(void) { uint8_t i; uint32_t val = 0; for (i=0; i<4; i++) { val <<= 8; val |= rnd8(); } return val; } /** * @brief Function for configuring the radio to use a random address and a 254 byte random payload. * The S0 and S1 fields are not used. */ static void generate_modulated_rf_packet(void) { uint8_t i; NRF_RADIO->PREFIX0 = rnd8(); NRF_RADIO->BASE0 = rnd32(); // Packet configuration: // S1 size = 0 bits, S0 size = 0 bytes, payload length size = 8 bits NRF_RADIO->PCNF0 = (0UL << RADIO_PCNF0_S1LEN_Pos) | (0UL << RADIO_PCNF0_S0LEN_Pos) | (8UL << RADIO_PCNF0_LFLEN_Pos); // Packet configuration: // Bit 25: 1 Whitening enabled // Bit 24: 1 Big endian, // 4 byte base address length (5 byte full address length), // 0 byte static length, max 255 byte payload . NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Enabled << RADIO_PCNF1_WHITEEN_Pos) | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | (4UL << RADIO_PCNF1_BALEN_Pos) | (0UL << RADIO_PCNF1_STATLEN_Pos) | (255UL << RADIO_PCNF1_MAXLEN_Pos); NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Disabled << RADIO_CRCCNF_LEN_Pos); packet[0] = 254; // 254 byte payload. // Fill payload with random data. for (i = 0; i < 254; i++) { packet[i + 1] = rnd8(); } NRF_RADIO->PACKETPTR = (uint32_t)packet; } static void radio_disable(void) { NRF_RADIO->SHORTS = 0; NRF_RADIO->EVENTS_DISABLED = 0; #ifdef NRF51 NRF_RADIO->TEST = 0; #endif NRF_RADIO->TASKS_DISABLE = 1; while (NRF_RADIO->EVENTS_DISABLED == 0) { // Do nothing. } NRF_RADIO->EVENTS_DISABLED = 0; } /** * @brief Function for stopping Timer 0. */ void radio_sweep_end(void) { NRF_TIMER0->TASKS_STOP = 1; radio_disable(); } /** * @brief Function for turning on the TX carrier test mode. */ void radio_tx_carrier(uint8_t txpower, uint8_t mode, uint8_t channel) { radio_disable(); NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; NRF_RADIO->TXPOWER = (txpower << RADIO_TXPOWER_TXPOWER_Pos); NRF_RADIO->MODE = (mode << RADIO_MODE_MODE_Pos); NRF_RADIO->FREQUENCY = channel; #ifdef NRF51 NRF_RADIO->TEST = (RADIO_TEST_CONST_CARRIER_Enabled << RADIO_TEST_CONST_CARRIER_Pos) \ | (RADIO_TEST_PLL_LOCK_Enabled << RADIO_TEST_PLL_LOCK_Pos); #endif NRF_RADIO->TASKS_TXEN = 1; } /** * @brief Function for starting modulated TX carrier by repeatedly sending a packet with random address and * random payload. */ void radio_modulated_tx_carrier(uint8_t txpower, uint8_t mode, uint8_t channel) { radio_disable(); generate_modulated_rf_packet(); NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk | \ RADIO_SHORTS_DISABLED_TXEN_Msk; NRF_RADIO->TXPOWER = (txpower << RADIO_TXPOWER_TXPOWER_Pos); NRF_RADIO->MODE = (mode << RADIO_MODE_MODE_Pos); NRF_RADIO->FREQUENCY = channel; NRF_RADIO->TASKS_TXEN = 1; } /** * @brief Function for turning on RX carrier. */ void radio_rx_carrier(uint8_t mode, uint8_t channel) { radio_disable(); NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; NRF_RADIO->FREQUENCY = channel; NRF_RADIO->TASKS_RXEN = 1; } /** * @brief Function for turning on TX carrier sweep. This test uses Timer 0 to restart the TX carrier at different channels. */ void radio_tx_sweep_start(uint8_t txpower, uint8_t mode, uint8_t channel_start, uint8_t channel_end, uint8_t delayms) { txpower_ = txpower; mode_ = mode; channel_start_ = channel_start; channel_ = channel_start; channel_end_ = channel_end; sweep_tx_ = true; timer0_init(delayms); } /** * @brief Function for turning on RX carrier sweep. This test uses Timer 0 to restart the RX carrier at different channels. */ void radio_rx_sweep_start(uint8_t mode, uint8_t channel_start, uint8_t channel_end, uint8_t delayms) { mode_ = mode; channel_start_ = channel_start; channel_ = channel_start; channel_end_ = channel_end; sweep_tx_ = false; timer0_init(delayms); } /** * @brief Function for handling the Timer 0 interrupt used for TX/RX sweep. The carrier is started with the new channel, * and the channel is incremented for the next interrupt. */ void TIMER0_IRQHandler(void) { if (sweep_tx_) { radio_tx_carrier(txpower_, mode_, channel_); } else { radio_rx_carrier(mode_, channel_); } channel_++; if (channel_ > channel_end_) { channel_ = channel_start_; } NRF_TIMER0->EVENTS_COMPARE[0] = 0; } /** * @} */