nRF52832: Multi node wireless LED synchronization via proprietary radio (nRF5 SDK 12.3.0 on PCA10040)
Summary
This post shares a simple proprietary radio demo that synchronizes LED blink patterns across three or more nRF52 DK boards. Any node can change the blink pattern via Button1; the change propagates hop by hop and all nodes re synchronize. The design relies on a periodic transmit slot with integer multiple receive timing, which naturally aligns nodes over time and allows intermittent RX/TX for low average current. Tested on nRF52832 / nRF52 DK (PCA10040) with nRF5 SDK 12.3.0.
Key ideas / Features
•No parent/child roles and no node IDs: Every radio follows the same behavior; no addressing or topology setup is required.
•Clock drift absorption: Exchanging a simple “sync” counter regularly removes cumulative drift between nodes and aligns
•Intermittent RX/TX for power saving: Nodes wake only on schedule; typical average current is low (see power section).
•Natural multi hop propagation: Nodes do not need to be all within mutual RF range; information will propagate in a “daisy chain” manner as frames travel across neighbors.
How it works
•A node transmits a short frame every 250 ms; nodes receive at intervals that are integer multiples of that period (in this demo: every 10 s = 40× 250 ms). Over time, this shared schedule makes nodes line up and synchronize.
•The frame layout is lightweight: a header @wp1@, a two digit sync counter, a 32 bit RTC timestamp, a pattern byte, and a simple checksum (sum of specific bytes). Receivers validate the checksum and, if conditions are met, align their local sync to the received value.
•Pressing Button1 on any board updates the blink pattern locally; this pattern is included in frames and eventually propagates to other nodes, which re synchronize to the new pattern. For stable behavior, avoid pressing Button1 repeatedly in a short interval; waiting ≥ 60 s between changes is recommended for this demo’s convergence logic.
Hardware / Software
•SoC/Board: nRF52832, nRF52 DK (PCA10040)
•SDK: nRF5 SDK 12.3.0 (legacy; used here for compatibility with prior work)
•Radio: Proprietary mode at 250 kbps, 2450 MHz channel, TX power = −8 dBm in the provided source.
Power (measured conditions)
•TX interval: every 250 ms, on air ~3 ms each time
•RX interval: every 10 s, RX window ~25 ms
•Supply: 3.0 V, DCDC enabled, nRF52 DK
•Average current: ~0.30 mA @ 3.0 V with UART OFF and Tx=+4Bm (UART ON increases current).
Values reflect the intermittent RX/TX schedule above; exact numbers depend on your lab setup and environment.
Build & Run
1.Place the provided main.c under examples/proprietary_rf/esb_prx/ (replace the original) in nRF5 SDK 12.3.0 and build to generate the HEX.
2.Flash three or more nRF52 DK boards with the built HEX.
3.Power the boards. LED3 on each board will converge to synchronized blinking. LED2 and LED4 may also turn on at times for program status indication. Press Button1 on any board to change the blink pattern and observe how it propagates and re synchronizes across nodes.
/**
* Copyright (c) 2014 - 2017, 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.
*
*/
//�����ʐM�����V�X�e���v���O���� 250ms�C���^�[�o��
//Wireless_Sync_Proprietery_Simple_nRF52832_20260210
//nRF52832�p
#define rtc0_count_max_VALUE 40 //0.25s�~40=10s 10�b���Ɏ�M
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "sdk_common.h"
#include "nrf_delay.h"
#include "boards.h"
#include <stdio.h>
volatile unsigned char wlp_ok=0;
volatile unsigned char wlp_ok2=0;
volatile unsigned int rtc0_count=0;
volatile unsigned char time_up2=0;
char s1[200]={""};//UART�o�͂̏o�͕��������\���傫������
volatile unsigned char rcv_ok=0;
volatile unsigned char send_ok=0;
volatile unsigned char send_only=0;//wp���M�̂ݎ�1�Awp�̑��M��M��0
volatile unsigned char uart_disp_mode=0;
volatile unsigned char uart_disp_mode_all=1;//�f�t�H���g�̓I�[���\��
//UART0��M�p
volatile unsigned char read_data[50];
volatile unsigned char data_num_i=0;
volatile unsigned char rcv_buff=0;
volatile unsigned char sync=0;
volatile unsigned char received_sync=96;//�����p�\���J�E���^�[�̎�M�l �����l=96
volatile uint32_t start_rtc_counter=0;
volatile uint32_t received_start_rtc_counter=0;
volatile unsigned char wp_wait_time_up=0;//����I�Ȏ�M���ɁA��M�҂����鎞�Ԃ�ݒ肵�A���Ԍo�ߌ��=1
volatile unsigned char rtc0_wlp_ok_ng=0;//rtc0�̃J�E���g�A�b�v���wlp_ok=1�ɂȂ邩�`�F�b�N���邽�߂̃t���O
volatile unsigned char rtc0_wlp_ng_restart=0;//rtc0�̃J�E���g�A�b�v���wlp_ok=1�ɂȂ�Ȃ�������(rtc0_wlp_ok_ng=1�̎�)rtc0_wlp_ng_restart=1
volatile unsigned char sync_not_equal_count=0;//sync<>received_sync�̉�J�E���g�A���A���ŗ��ҕs��v�ł���Async=received_sync
volatile unsigned char sync_not_equal_count_thresh=1;//��Lsync_not_equal_count�̈��̂���
volatile unsigned char lighting_pattern=0;//�����p�^�[���Ǝ����̐ݒ�l
volatile unsigned char input_lighting_pattern=0;//�����̖����@�ւ̔����p�^�[�����͒l
volatile unsigned char received_lighting_pattern=0;//���̖����@����̔����p�^�[����M�l
volatile unsigned char led_on_flag=0;//=1�̎�LED��ON
volatile unsigned int wp_tx_sum=0;//wp�f�[�^��rf_tx_data[5]�`[11]�̃T���f�[�^(char)wp_check_sum��rf_tx_data[12]�ɑ��
volatile unsigned int wp_rx_sum=0;//��M�f�[�^�̃`�F�b�N�T���m�F�p
volatile unsigned char start_rtc_not_random_send_count=0;
volatile unsigned char input_lighting_pattern_old=0;//�����p�^�[����SW���͕ω�����o���邽�߂̋���SW���͒l
volatile unsigned short receive_error_count=0;
volatile unsigned short pattern_error_count=0;
volatile unsigned int seed_random_number=0;
volatile signed char random_number_start_rtc=0;//start_rtc_counter�ݒ�̃����_���l
volatile signed char random_number_start_rtc2=0;//random_number_start_rtc����ɏC�����������_���l
volatile signed char prev_random_number_start_rtc2=0;//random_number_start_rtc2�̑O��l -1���A������̂�����
volatile unsigned char radio_strength=0xff;
volatile unsigned int rtc0_count_max=40;//rtc0_count_max�l�𗐐��ɂ���Đݒ�
volatile unsigned int seed_rtc0_count_crystal=0;//rtc0_count_max�l�̏����l����߂闐���̃V�[�h�l��16MHz�N���X�^���̃E�F�C�g�l
volatile uint8_t rf_tx_data[64];
volatile uint8_t rf_rx_data[64];
volatile uint8_t rf_tx_data2[72];//rf_tx_data��payload��Length��Pid(PacketID)��lj�����rf_tx_data2����
volatile uint8_t rf_rx_data2[72];//rf_rx_data��payload��Length��Pid(PacketID)��lj�����rf_rx_data2����
void led_on_off_control(unsigned char);
void led_output(void);
void uart_process_init(void);
void uart_data_read_process(void);//void UART0_IRQHandler(void)�ɂČĂ��
void print_version(void);
void read_data_clr(void);//UART��M�p
//UART�\����
void write2(char data3){
NRF_UART0->TXD=data3;
data3=0;
NRF_UART0->TASKS_STARTTX;
while(NRF_UART0->EVENTS_TXDRDY != 1){}
NRF_UART0->EVENTS_TXDRDY = 0;
}
void write_string(char *data2){
while(*data2!=0x00){
write2(*data2++);
}
}
void RADIO_IRQHandler(void){
NVIC_ClearPendingIRQ(RADIO_IRQn);
NVIC_DisableIRQ(RADIO_IRQn);
if(uart_disp_mode==1){
write_string("R");
}
rcv_ok=1;
if((strncmp((const char*)rf_rx_data2+2,"@wp1@",5)==0)){
for(unsigned char ij=0;ij<18;ij++)rf_rx_data[ij]=rf_rx_data2[ij+2];
wp_rx_sum=0;
for(unsigned char jj= 5; jj<=15; jj++){
wp_rx_sum=wp_rx_sum+rf_rx_data[jj];
}
if(rf_rx_data[16]==(char)(wp_rx_sum&0x00ff)){
radio_strength=NRF_RADIO->RSSISAMPLE;//���̂��A�{��M�`�F�b�N�o�[�W�����ł�radio_strength�̒l���������\������Ȃ�
received_start_rtc_counter=((rf_rx_data[7]<<24)|(rf_rx_data[8]<<16)|(rf_rx_data[9]<<8)|(rf_rx_data[10]));
if(received_start_rtc_counter>=start_rtc_counter){
//rand()���̃V�[�h����
if(seed_random_number==0){
seed_random_number=(unsigned int)((start_rtc_counter&0x000000ff)+(received_start_rtc_counter&0x000000ff));
srand(seed_random_number);
}
//�����p�^�[����SW���͕ω����́A��M��=6(10�b�~5=50�b)�ɂȂ�܂ŁA�y��
//�����p�^�[���̓��͂��Ȃ��ꍇ�ł���Z�b�g��A��M��=5(50�b)�ɂȂ�܂�
//=received_start_rtc_counter+3;�Ƃ���
if(++start_rtc_not_random_send_count>=5)start_rtc_not_random_send_count=5;
if(start_rtc_not_random_send_count<5){
random_number_start_rtc=10,random_number_start_rtc2=3;
start_rtc_counter=received_start_rtc_counter+random_number_start_rtc2;//received_start_rtc_counter+3
}
else {
random_number_start_rtc=(-(rand()%5)+3);//��(-(rand()%3)+1);//-1,0,1,2,3��5���
if((random_number_start_rtc>=0)||(prev_random_number_start_rtc2==-1))random_number_start_rtc2=2;
//-1���A������̂�����
else random_number_start_rtc2=-1;
//random_number_start_rtc2��-1��+2��+3��3���
start_rtc_counter=received_start_rtc_counter+random_number_start_rtc2;
prev_random_number_start_rtc2=random_number_start_rtc2;
}
received_sync=(*(rf_rx_data+5)-0x30)*10+(*(rf_rx_data+6)-0x30);
received_lighting_pattern=*(rf_rx_data+11);
wlp_ok=1;
}
}
}
}
void rf_init(void){
NRF_RADIO->BASE0=0xa94b02f6;
NRF_RADIO->BASE1=0x0df61030;
NRF_RADIO->PREFIX1=0;
NRF_RADIO->PREFIX0=0;
NRF_RADIO->PCNF0=0x00000006;
NRF_RADIO->PCNF1=0x00040020;
NRF_RADIO->CRCCNF = 2;//CRC length=2bytes
NRF_RADIO->CRCINIT=0;
NRF_RADIO->CRCPOLY=0x8d;//CRC poly
NRF_RADIO->MODE=2;//Nrf250Kbit �f�[�^���[�g250kbps �@MODE��UART�ɂĕύX�\
NRF_RADIO->TASKS_START=1;//PCNF0,PCNF1,BASE0,BASE1�̐ݒ�l��NRF_RADIO->TASKS_START=1�ɂ���Ĕ��f�����
NVIC_ClearPendingIRQ(RADIO_IRQn);
NVIC_SetPriority(RADIO_IRQn, 1);
NVIC_EnableIRQ(RADIO_IRQn);
}
void rf_start_tx(void){
NRF_RADIO->SHORTS=0x113;
NRF_RADIO->INTENSET=0x10;
NRF_RADIO->TXADDRESS=0;//Logical address=0
NRF_RADIO->RXADDRESSES=0x01;//Logocal address0��Eenabled�@����Disabled
rf_tx_data2[0]=0x20;//Payload.Length
rf_tx_data2[1]=0;
for(unsigned char jj=0;jj<18;jj++)rf_tx_data2[jj+2]=rf_tx_data[jj];
NRF_RADIO->PACKETPTR=(uint32_t)rf_tx_data2;
NVIC_ClearPendingIRQ(RADIO_IRQn);
NVIC_DisableIRQ(RADIO_IRQn);
NRF_RADIO->EVENTS_ADDRESS=0;
NRF_RADIO->EVENTS_PAYLOAD=0;
NRF_RADIO->EVENTS_DISABLED=0;
NRF_RADIO->TASKS_TXEN=1;
}
void rf_start_rx(void){
NRF_RADIO->INTENCLR=0xFFFFFFFF;
NRF_RADIO->EVENTS_DISABLED=0;
NRF_RADIO->SHORTS=0x117;
NRF_RADIO->INTENSET=0x10;
NRF_RADIO->RXADDRESSES=0x01;//Logocal address0��Eenabled�@����Disabled
NRF_RADIO->PACKETPTR=(uint32_t)rf_rx_data2;
NVIC_ClearPendingIRQ(RADIO_IRQn);
NVIC_EnableIRQ(RADIO_IRQn);
NRF_RADIO->EVENTS_ADDRESS=0;
NRF_RADIO->EVENTS_PAYLOAD=0;
NRF_RADIO->EVENTS_DISABLED=0;
NRF_RADIO->TASKS_RXEN=1;
}
void rf_stop(void){
NRF_RADIO->SHORTS=0;
NRF_RADIO->INTENCLR=0xFFFFFFFF;
NRF_RADIO->EVENTS_DISABLED=0;
NRF_RADIO->TASKS_DISABLE=1;
while(NRF_RADIO->EVENTS_DISABLED==0);
}
//RTC����
void RTC0_IRQHandler(void){
if(++start_rtc_counter>=0x01000000)start_rtc_counter=0;
NRF_RTC0->EVENTS_COMPARE[0]=0;//RTC����ɂ����ĕK���K�v�B
//��L���Ȃ���RTC0�C���^���v�g���Ă�܂��A�����C���^���v�g��������
NRF_RTC0->TASKS_CLEAR=1;
NRF_CLOCK->EVENTS_HFCLKSTARTED=0;
NRF_CLOCK->TASKS_HFCLKSTART=1;
while(NRF_CLOCK->EVENTS_HFCLKSTARTED==0);
if(++rtc0_count==rtc0_count_max){
rtc0_count=0;
rtc0_count_max=rtc0_count_max_VALUE+(rand()%3);//rtc0_count_max�̒l�𗐐��ɂ���Đݒ�
NRF_RTC0->CC[0]=50;//5ms�~50=250ms
}
else if(rtc0_count==1)NRF_RTC0->CC[0]=50-4;//5ms�~50-4=230ms
else NRF_RTC0->CC[0]=50;//5ms�~50=250ms
NRF_TIMER0->TASKS_START=1;
wp_wait_time_up=0;
rtc0_wlp_ok_ng=1;
//rtc0�̃J�E���g�A�b�v���wlp_ok=1�ɂȂ邩�`�F�b�N���邽�߂̃t���O
if(++sync>=96)sync=0;
led_on_off_control(lighting_pattern);
led_output();
time_up2=1;
}
//WP�E�F�C�g�^�C�}�[�ݒ�
void TIMER0_IRQHandler(void){
if(NRF_TIMER0->EVENTS_COMPARE[0]!=0){
NRF_TIMER0->EVENTS_COMPARE[0]=0;
NRF_TIMER0->TASKS_CLEAR=1;
NRF_TIMER0->TASKS_STOP=1;
wp_wait_time_up=1;
}
}
//�v�����g�\��/���샂�[�h�ύX�p P07����=H�ɂ��UART0����
void UART0_IRQHandler(void){
if(NRF_UART0->EVENTS_RXDRDY!=0){
NRF_UART0->EVENTS_RXDRDY=0;
rcv_buff=NRF_UART0->RXD;//RXD 8bit
if(data_num_i<50)read_data[data_num_i++]=rcv_buff;
if((rcv_buff=='\r')||(rcv_buff=='\n'))data_num_i=0;
else if(rcv_buff=='@')data_num_i=0,uart_data_read_process();
}
}
void uart_data_read_process(void){
if(uart_disp_mode==1){
if(strncmp((char*)(read_data),"ver@",4)==0){
read_data_clr();
print_version();
}
else if(strncmp((char*)(read_data),"21@",3)==0){
read_data_clr();
write_string("\n\rUART 0x21");
}
else if(strncmp((char*)(read_data),"31@",3)==0){
read_data_clr();
uart_disp_mode_all=1;
write_string("\n\rUART 0x31 uart_disp_mode_all=1");
}
else if(strncmp((char*)(read_data),"30@",3)==0){
read_data_clr();
uart_disp_mode_all=0;
write_string("\n\rUART 0x30 uart_disp_mode_all=0");
}
else if(strncmp((char*)(read_data),"sync_not@",9)==0){
read_data_clr();
sprintf(s1,"\n\rsync_not_thresh=%2x\n\r",sync_not_equal_count_thresh);
write_string(s1);
}
else if((read_data[0]=='s')&&(read_data[1]=='y')&&(read_data[2]=='n')&&(read_data[3]=='c')
&&(read_data[4]=='_')&&(read_data[5]=='n')&&(read_data[6]=='o')&&(read_data[7]=='t')&&(read_data[9]=='@')){
if((read_data[8]>=0x30)&&(read_data[8]<=0x36))sync_not_equal_count_thresh=(read_data[8]-0x30);
sprintf(s1,"\n\rsync_not_thresh=%2x\n\r",sync_not_equal_count_thresh);
write_string(s1);
}
else if(strncmp((char*)(read_data),"mode@",5)==0){
read_data_clr();
sprintf(s1,"\n\rmode=%2x\n\r",NRF_RADIO->MODE);
write_string(s1);
}
else if((read_data[0]=='m')&&(read_data[1]=='o')&&(read_data[2]=='d')&&(read_data[3]=='e')&&(read_data[5]=='@')){
if((read_data[4]>=0x30)&&(read_data[4]<=0x36))NRF_RADIO->MODE=(read_data[4]-0x30);
else if(read_data[4]=='f')NRF_RADIO->MODE=15;
sprintf(s1,"\n\rmode=%2x\n\r",NRF_RADIO->MODE);
write_string(s1);
}
}
}
void print_version(void){
sprintf(s1,"\n\rWireless_Sync_Propritery_Simple_20260210 ");
write_string(s1);
}
void read_data_clr(void){
for(unsigned short i=0;i<50;i++)*(read_data+i)=0x00,data_num_i=0;
}
void ioport(void){
for(unsigned char jx=17;jx<=20;jx++){
NRF_GPIO->PIN_CNF[jx]=0x03;
}
NRF_GPIO->OUT=0x001E0000;//nRF52DK�J��KIT��4��LED����(P17-P20=H)
}
// �{�^���������ꂽ�u�Ԃ̏���
bool button_was_pressed = false;
void button_check(void)
{
bool button_is_pressed = (nrf_gpio_pin_read(BUTTON_1) == 0);
if (button_is_pressed && !button_was_pressed)
{
input_lighting_pattern=lighting_pattern+1;
if(input_lighting_pattern==15)input_lighting_pattern=11;
}
button_was_pressed = button_is_pressed;
}
void buttons_init(void)
{
nrf_gpio_cfg_input(BUTTON_1, NRF_GPIO_PIN_PULLUP);
}
void uart_process_init(void){
uart_disp_mode=0;
//P07���͂ɂ��AUART�\��ON/OFF�̐ݒ�
if(((NRF_GPIO->IN)&0x000080)==0x080){
nrf_delay_us(10);
if(((NRF_GPIO->IN)&0x000080)==0x080){
nrf_delay_us(10);
if(((NRF_GPIO->IN)&0x000080)==0x080){
uart_disp_mode=1;
}
}
}
//UART�I�t���̓|�[�g�ݒ肵�Ȃ�
if(uart_disp_mode==1){
NRF_GPIO->PIN_CNF[8]=0x0E;//LowPower RXD�s����v���A�b�v�@�v���A�b�v�������UART����OK
NRF_GPIO->PIN_CNF[6]=0x01;//TXD �o�̓s���ɐݒ�
//UART0
NRF_UART0->ENABLE=0;
NRF_UART0->PSELTXD=0x00000006;//nRF52DK
NRF_UART0->PSELRXD=0x00000008;//nRF52DK
NRF_UART0->BAUDRATE=0x01D7E000;//115.2kbps
NRF_UART0->CONFIG=0;
NRF_UART0->ENABLE=4;
NRF_UART0->INTENSET= 4;//enable interrupt on RXRDY event
NRF_UART0->TASKS_STARTTX=1;
NRF_UART0->TASKS_STARTRX=1;
NVIC_ClearPendingIRQ(UART0_IRQn);
NVIC_SetPriority(UART0_IRQn, 3);
NVIC_EnableIRQ(UART0_IRQn);
read_data_clr();
}
}
int main(void)
{
ioport();
NRF_GPIO->PIN_CNF[7]=0x04;//pull down�@P07=H�̏ꍇ��UART�\������
NRF_GPIO->PIN_CNF[8]=0x0E;//LowPower RXD�s����v���A�b�v�@�v���A�b�v�������UART����OK
NRF_GPIO->PIN_CNF[6]=0x01;//TXD �o�̓s���ɐݒ�
seed_rtc0_count_crystal=0;//rtc0_count_max�l�̗����̃V�[�h�ݒ�p
// Set 16 MHz crystal as our 16 MHz clock source (as opposed to internal RCOSC)
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
{
// Wait
if(++seed_rtc0_count_crystal>=100)seed_rtc0_count_crystal=0;
//rtc0_count_max�l�̗����̃V�[�h�ݒ�p
}
NRF_CLOCK->LFCLKSRC=1;//32.768kHz crystal oscillator
//TIMER0�ݒ�
NRF_TIMER0->MODE=0;//Timer mode
NRF_TIMER0->BITMODE=3;//32bit
NRF_TIMER0->PRESCALER=9;//2~9/16000000=32us
NRF_TIMER0->CC[0]=8750;//250ms+30ms=280ms//WP�E�F�C�g�^�C�}�[�ݒ�
NVIC_ClearPendingIRQ(TIMER0_IRQn);
NVIC_SetPriority(TIMER0_IRQn, 2);
NVIC_EnableIRQ(TIMER0_IRQn);//wp�E�F�C�g�^�C�}�[�C�l�[�u��
NRF_TIMER0->INTENSET=0x00010000;//Compare0�̃C���^���v�g�C�l�[�u��
NRF_TIMER0->TASKS_STOP=1;
NRF_TIMER0->TASKS_CLEAR=1;
//RTC����
NRF_CLOCK->TASKS_LFCLKSTART=1;//RTC����̂��߂ɂ͐�ΕK�v
NRF_RTC0->PRESCALER=164;//198.6Hz 5.035ms
NRF_RTC0->CC[0]=50;//5ms�~50=250ms
NRF_RTC0->INTENSET=0x00010000;//COMPARE[0]
NRF_RTC0->EVTENSET=0x00010000;//COMPARE[0]
NVIC_ClearPendingIRQ(RTC0_IRQn);
NVIC_SetPriority(RTC0_IRQn,2);
NVIC_EnableIRQ(RTC0_IRQn);
NRF_RTC0->TASKS_CLEAR=1;
NRF_RTC0->TASKS_START=1;
NRF_POWER->TASKS_LOWPWR=1;
//WDT
NRF_WDT->CRV=32768*10;//WDT=10�b<30�b
NRF_WDT->RR[0]=0x6E524635;
NRF_WDT->TASKS_START=1;//WDT�X�^�[�g
uart_process_init();
NRF_POWER->DCDCEN = 1;//DCDCconverterEnabl
rf_init();
NRF_RADIO->FREQUENCY=50;//2450MHz//�ݒ���g��
NRF_RADIO->TXPOWER=0xF8;//-8dbm//�ݒ�o�̓��x��
wlp_ok=0;
wlp_ok2=0;
time_up2=0;
*rf_rx_data=0x00;
send_only=0;
rf_start_rx();
input_lighting_pattern=0;
input_lighting_pattern_old=0;
received_lighting_pattern=0;
lighting_pattern=14;
start_rtc_not_random_send_count=0;
receive_error_count=0;
pattern_error_count=0;
start_rtc_counter=0;
received_start_rtc_counter=0;
input_lighting_pattern_old=input_lighting_pattern;
seed_random_number=0;
srand(seed_rtc0_count_crystal);//rtc0_count_max�̏����l����߂闐���̃V�[�h�l��ݒ�
rtc0_count_max=rtc0_count_max_VALUE +rand()%3;//�����l
radio_strength=0xff;//�����l
if(uart_disp_mode==1){
sprintf(s1,",seed_rtc0_count_crystal=%3d rtc0_count_max=%3d",
seed_rtc0_count_crystal,rtc0_count_max);
write_string(s1),write_string("\r\n");
}
//Initialize buttons
buttons_init();
while (true){
if((wlp_ok==1)||(wp_wait_time_up==1)){
//��M�G���[��3��(�ő�30�b�~3=1.5��+10�b(WDT����))��WDT���Z�b�g����
if(rtc0_wlp_ok_ng==1){
rtc0_wlp_ng_restart=1;
if(++receive_error_count>=6)receive_error_count=6;//30�b�~6=3��
}
else if(rtc0_count==2)receive_error_count=0;
//����I�Ȏ�MNG���ɁA��M�҂����Ԍo�ߌ�ɁA
//�����I��wlp_ok=1�ɂ��鎞�Awp_wait_time_up_restart=1
wp_wait_time_up=0;
wlp_ok=0;
wlp_ok2=1;
if(uart_disp_mode==1){
if((uart_disp_mode_all==1)||((uart_disp_mode_all==0)&&(rtc0_count==2))){
write_string("\r\n");
write_string((char*)rf_rx_data);//��M�f�[�^
sprintf(s1,"%4d%3d%3d %6x%3d%3d%3d%3d%3d %6x %2x %d %d ",rtc0_count,sync,received_sync
,start_rtc_counter,random_number_start_rtc,random_number_start_rtc2,start_rtc_not_random_send_count
,lighting_pattern,received_lighting_pattern,received_start_rtc_counter,radio_strength
,receive_error_count,pattern_error_count);
write_string(s1);
}
}
if((send_only==0)&&(rtc0_wlp_ng_restart!=1))NRF_RTC0->TASKS_CLEAR=1;
rf_stop();
NRF_RADIO->EVENTS_READY=0;//�Ȃ���NG
rf_tx_data[0]='@';
rf_tx_data[1]='w';
rf_tx_data[2]='p';
rf_tx_data[3]='1';
rf_tx_data[4]='@';
rf_tx_data[5]=0x30+(sync/10);
rf_tx_data[6]=0x30+(sync%10);
rf_tx_data[7]=(unsigned char)((start_rtc_counter>>24)&0x000000ff);
rf_tx_data[8]=(unsigned char)((start_rtc_counter>>16)&0x000000ff);
rf_tx_data[9]=(unsigned char)((start_rtc_counter>>8)&0x000000ff);
rf_tx_data[10]=(unsigned char)(start_rtc_counter&0x000000ff);
rf_tx_data[11]=lighting_pattern;
rf_tx_data[12]=0;//���L�f�[�^�̈�
rf_tx_data[13]=0;//���L�f�[�^�̈�
rf_tx_data[14]=0;//���L�f�[�^�̈�
rf_tx_data[15]=0;//���L�f�[�^�̈�
wp_tx_sum=0;
for(unsigned char jj= 5; jj<=15; jj++)wp_tx_sum=wp_tx_sum+rf_tx_data[jj];
rf_tx_data[16]=(char)(wp_tx_sum&0x00ff);
rf_tx_data[17]=0x00;
rf_start_tx();
while(NRF_RADIO->EVENTS_READY!=1);
send_ok=1;
if(uart_disp_mode==1)write_string("S");
nrf_delay_ms(2);
rf_stop();
radio_strength=0xff;
*rf_tx_data=0x00;
*rf_rx_data=0x00;
}
if ((wlp_ok2==1)&&(send_ok==1)){
if(received_sync<96){ //LED��duty=1/8duty�̂��� 96
//�p�����[�^��sync��received_sync�̍��̒l�Ɨ��҂����ȏ�̘A����
if(((sync>received_sync)&&(sync-received_sync>=1))
||((sync+96>received_sync)&&(sync+96-received_sync>=1))
||((received_sync>sync)&&(received_sync-sync>=1))
||((received_sync+96>sync)&&(received_sync+96-sync>=1))){
if(++sync_not_equal_count>=sync_not_equal_count_thresh){
sync_not_equal_count=sync_not_equal_count_thresh,sync=received_sync;
}
}
else if(received_sync==sync)sync_not_equal_count=0,sync=received_sync;
received_sync=96;
}
button_check(); // �{�^���̏��
if(input_lighting_pattern==0){
if(received_lighting_pattern!=0)lighting_pattern=received_lighting_pattern;
}
else lighting_pattern=input_lighting_pattern;
if(input_lighting_pattern!=0){
if(received_lighting_pattern!=input_lighting_pattern){
if(++pattern_error_count>=(12*rtc0_count_max))pattern_error_count=(12*rtc0_count_max);
}
else{
input_lighting_pattern=0;
pattern_error_count=0;
}
}
//�����p�^�[����SW���͕ω����o
if((input_lighting_pattern!=0)&&(input_lighting_pattern!=input_lighting_pattern_old)){
start_rtc_not_random_send_count=0;
input_lighting_pattern_old=input_lighting_pattern;
}
rtc0_wlp_ng_restart=0;
//rtc0�̃J�E���g�A�b�v���wlp_ok=1�ɂȂ�Ȃ�������(rtc0_wlp_ok_ng=1�̎�)1
wlp_ok2=0;
rcv_ok=0;
send_ok=0;
//TIMER0�ݒ�
NRF_TIMER0->TASKS_CLEAR=1;
NRF_TIMER0->TASKS_STOP=1;//sleep�������d����
rf_stop();
NRF_CLOCK->TASKS_HFCLKSTOP=1;
do{
__WFE();
__SEV();
__WFE();
}while(time_up2!=1);
rtc0_wlp_ok_ng=0;
if(rtc0_count!=2){
wlp_ok=1;
send_only=1;
}
else {
send_only=0;
rf_start_rx();
}
if(uart_disp_mode==1){
//P07���͂ɂ��AUART�\��ON/OFF�̐ݒ�
if(((NRF_GPIO->IN)&0x000080)!=0x080){
nrf_delay_us(10);
if(((NRF_GPIO->IN)&0x000080)!=0x080){
}
}
else{
//��M�G���[��6����WDT���Z�b�g�������
if((receive_error_count<6)&&(pattern_error_count<(12*rtc0_count_max))){
NRF_WDT->RR[0]=0x6E524635;//���̐ݒ肪�Ȃ���WDT���Z�b�g��������
}
NRF_WDT->CRV=32768*10;//WDT����=10�b
}
}
else{
//P07���͂ɂ��AUART�\��ON/OFF�̐ݒ�
if(((NRF_GPIO->IN)&0x000080)==0x080){
nrf_delay_us(10);
if(((NRF_GPIO->IN)&0x000080)==0x080){
nrf_delay_us(10);
if(((NRF_GPIO->IN)&0x000080)==0x080){
}
}
}
//��M�G���[��3����WDT���Z�b�g�������
else{
if((receive_error_count<6)&&(pattern_error_count<(12*rtc0_count_max))){
NRF_WDT->RR[0]=0x6E524635;//���̐ݒ肪�Ȃ���WDT���Z�b�g��������
}
NRF_WDT->CRV=32768*10;//WDT����=10�b
}
}
}
time_up2=0;
}
}
void led_on_off_control(unsigned char pattern){
switch (pattern){
case 14:
if(sync%2==0)led_on_flag=1;
else led_on_flag=0;
break;
case 13:
if((sync%4==0)||(sync%4==1))led_on_flag=1;
else led_on_flag=0;
break;
case 12:
if((sync%8==0)||(sync%8==1)||(sync%8==2)||(sync%8==3))led_on_flag=1;
else led_on_flag=0;
break;
case 11:
if((sync%16==1)||(sync%16==3)||(sync%16==5))led_on_flag=1;
else led_on_flag=0;
break;
default:
if(sync%2==0)led_on_flag=1;
else led_on_flag=0;
break;
}
}
void led_output(void){
if((led_on_flag)==1){
NRF_GPIO->OUT=NRF_GPIO->OUT&0xFFF7FFEF;//P31=H P30=H P19=L P04=L
NRF_GPIO->OUT=NRF_GPIO->OUT|0xC0000000;//
}
else{
NRF_GPIO->OUT=NRF_GPIO->OUT&0x3FFFFFFF;//P31=L P30=L P19=H P04=H
NRF_GPIO->OUT=NRF_GPIO->OUT|0x00080010;//
}
if(receive_error_count!=0){
NRF_GPIO->OUT=NRF_GPIO->OUT&0xFFEFFFFF;//P20=L
}
else{
NRF_GPIO->OUT=NRF_GPIO->OUT|0x00100000;//P20=H
}
if(random_number_start_rtc2<0){
NRF_GPIO->OUT=NRF_GPIO->OUT&0xFFFBFFFF;//P18=L
}
else{
NRF_GPIO->OUT=NRF_GPIO->OUT|0x00040000;//P18=H
}
}
Wireless Synchronization Demo (nRF52832 / nRF52 DK, nRF5 SDK 12.3.0) 1) Concept and operation - One node transmits a short sync+data frame at a fixed period (250 ms). - Other nodes receive at intervals that are integer multiples of that period (10 s = 40 × 250 ms). - As a result, every node periodically aligns with a transmitting node and receives its data. - Once synchronized, each node also transmits its own data+sync frame periodically. - Applying this across all nodes establishes system-wide synchronization and data sharing. 2) Power behavior - Intermittent communication is a key feature once nodes are synchronized. - TX: every 250 ms, on-air ~3 ms - RX: every 10 s, window ~25 ms - Board: nRF52 DK, SoC: nRF52832, DCDC enabled; radio register in the provided source is configured to a channel around 2450 MHz. - Typical average current: ~0.3 mA at 3.0 V with UART disabled andTx=+4dBm(UART increases current). Typical average current: ~0.25 mA at 3.0 V with UART disabled andTx=-8dBm(UART increases current). Your results may vary depending on setup and instrumentation. 3) How to use - SDK: nRF5 SDK 12.3.0; Board: nRF52 DK (PCA10040). - Build: replace the original main.c at examples/proprietary_rf/esb_prx/ and build the project. - Flash three or more nRF52 DK boards. - LED3 on all boards will converge to synchronized blinking (LED2/LED4 may also turn on for status). - Press Button1 on any board to change the blink pattern; the pattern will propagate and nodes will re synchronize. - For stability, avoid pressing Button1 repeatedly in a short time; wait at least about 60 s between changes. 4) Attachments - Source code (main.c). If needed, a pre built HEX can be provided upon request.
Limitations / Notes
•SDK 12.3.0 is legacy; porting to a newer nRF5 SDK or nRF Connect SDK is left for future work.
Code & License
•The source file contains the original Nordic license header and this demo’s implementation. Keep the header intact and add your preferred license notice for your contributions if needed.