[nRF52] Here is tested and working "proprietary" radio demo code
Posted: Sun Oct 21, 2018 12:53 pm
It is written entirely in micropython, and it works on both nRF52832 and nRF52840. In brief: the transmitter sends a packet with a different one-byte payload about once every second, and the receiver displays the content of the payload as well as an ongoing count of the number of packets received.
In this case "proprietary" simply means Nordic's proprietary radio mode. Anyone can use it. It's very similar to the frames sent by the nRF24L01+. It does not rely on bluetooth.
Here is the receiver code:
and here is the transmitter code:
Load the code into a file named main.py. I used ampy to put the file onto the board (in my case I used an nRF52840-DK as the transmitter and an nRF52832-DK as the receiver). Then, reset the board, which loads the code. Then open a putty window (or similar serial terminal) to the board and type
at the ">>>" REPL prompt to execute the code. You could, of course, have it start itself, but then I found it difficult to regain control over the board if I did it that way (e.g. to upload a new program). This way you regain control by just resetting the board.
Presently the transmitter is sending packets faster than one a second (viewtopic.php?f=12&t=5417), but for demo purposes that doesn't matter. The receiver has no problem keeping up with it.
With this as a starting point, you can easily extend the code to do whatever you want.
Enjoy!
In this case "proprietary" simply means Nordic's proprietary radio mode. Anyone can use it. It's very similar to the frames sent by the nRF24L01+. It does not rely on bluetooth.
Here is the receiver code:
Code: Select all
# This program for an nRF52832 receives a packet with a one byte payload
from micropython import const
import machine # so can peek and poke different registers on the nRF5x
import uctypes
import utime
radioBuffer = bytearray(100) # allocate IO buffer for use by nRF5x radio
radioBuffer_address = uctypes.addressof(radioBuffer)
my_prefixAddress = const(0xAA)
my_baseAddress = const(0xDEADBEEF)
NRF_POWER = const(0x40000000)
DCDCEN = const(0x578)
NRF_POWER___DCDCEN = const(NRF_POWER + DCDCEN)
NRF_CLOCK = const(0x40000000)
TASKS_HFCLKSTART = const(0)
EVENTS_HFCLKSTARTED = const(0x100)
NRF_CLOCK___TASKS_HFCLKSTART = const(NRF_CLOCK + TASKS_HFCLKSTART)
NRF_CLOCK___EVENTS_HFCLKSTARTED = const(NRF_CLOCK + EVENTS_HFCLKSTARTED)
NRF_RADIO = const(0x40001000)
BASE0 = const(0x51C)
PREFIX0 = const(0x524)
FREQUENCY = const(0x508)
PCNF1 = const(0x518)
PCNF0 = const(0x514)
MODE = const(0x510)
MODECNF0 = const(0x650)
CRCCNF = const(0x534)
PACKETPTR = const(0x504)
RXADDRESSES = const(0x530)
TXPOWER = const(0x50C)
TASKS_DISABLE = const(0x010)
STATE = const(0x550)
TASKS_TXEN = const(0)
TASKS_RXEN = const(0x004)
EVENTS_READY = const(0x100)
TASKS_START = const(0x008)
NRF_RADIO___BASE0 = const(NRF_RADIO + BASE0)
NRF_RADIO___PREFIX0 = const(NRF_RADIO + PREFIX0)
NRF_RADIO___FREQUENCY = const(NRF_RADIO + FREQUENCY)
NRF_RADIO___PCNF1 = const(NRF_RADIO + PCNF1)
NRF_RADIO___PCNF0 = const(NRF_RADIO + PCNF0)
NRF_RADIO___MODE = const(NRF_RADIO + MODE)
NRF_RADIO___MODECNF0 = const(NRF_RADIO + MODECNF0)
NRF_RADIO___CRCCNF = const(NRF_RADIO + CRCCNF)
NRF_RADIO___PACKETPTR = const(NRF_RADIO + PACKETPTR)
NRF_RADIO___RXADDRESSES = const(NRF_RADIO + RXADDRESSES)
NRF_RADIO___TXPOWER = const(NRF_RADIO + TXPOWER)
NRF_RADIO___TASKS_DISABLE = const(NRF_RADIO + TASKS_DISABLE)
NRF_RADIO___STATE = const(NRF_RADIO + STATE)
NRF_RADIO___TASKS_TXEN = const(NRF_RADIO + TASKS_TXEN)
NRF_RADIO___TASKS_RXEN = const(NRF_RADIO + TASKS_RXEN)
NRF_RADIO___EVENTS_READY = const(NRF_RADIO + EVENTS_READY)
NRF_RADIO___TASKS_START = const(NRF_RADIO + TASKS_START)
def initializeSerialOutput():
print("Starting...")
def initializeHardware(): # enable the DCDC voltage regulator
machine.mem32[NRF_POWER___DCDCEN] = 1 # NRF_POWER->DCDCEN=1;
def initializeClocks(): # activate the high frequency crystal oscillator
# NRF_CLOCK->TASKS_HFCLKSTART=1;
machine.mem32[NRF_CLOCK___TASKS_HFCLKSTART] = 1
# wait until high frequency clock start is confirmed
# while (NRF_CLOCK->EVENTS_HFCLKSTARTED==0) {};
while (machine.mem32[NRF_CLOCK___EVENTS_HFCLKSTARTED] == 0):
True
def initializeRadio():
# print this node's address in hexadecimal
print("My address is 0x{:02X}".format(my_prefixAddress) + "{:08X}".format(my_baseAddress))
machine.mem32[NRF_RADIO___BASE0] = my_baseAddress
machine.mem32[NRF_RADIO___PREFIX0] = my_prefixAddress
# value must be between 0 and 100
machine.mem32[NRF_RADIO___FREQUENCY] = 98 # 2498Mhz.
# base address is 4 bytes long (possible range is 2 to 4) and
# max size of payload is 1,and 1 bytes of static length payload
machine.mem32[NRF_RADIO___PCNF1] = 0x40101
# S0,LENGTH, and S1 are all zero bits long.
machine.mem32[NRF_RADIO___PCNF0] = 0
machine.mem32[NRF_RADIO___MODE] = 1 # set 2Mbps datarate.
machine.mem32[NRF_RADIO___MODECNF0] = 1 # enable fast ramp-up of radio from DISABLED state.
machine.mem32[NRF_RADIO___CRCCNF] = 3 # CRC will be 3 bytes and is computed including the address field
machine.mem32[NRF_RADIO___PACKETPTR] = radioBuffer_address # pointer to the payload in radioBuffer
machine.mem32[NRF_RADIO___RXADDRESSES] = 1 # receive on logical address 0. Not important for transmitting.
machine.mem32[NRF_RADIO___TXPOWER] = 4 # set to 4db transmit power, which is the maximum. max for nRF52840 is 8db
machine.mem32[NRF_RADIO___TASKS_DISABLE] = 1 # DISABLE the radio to establish a known state.
while (machine.mem32[NRF_RADIO___STATE] != 0): # wait until radio is DISABLED (i.e. STATE=0);
True
machine.mem32[NRF_RADIO___TASKS_RXEN] = 1 # turn on the radio receiver and shift into RXIDLE.
while (machine.mem32[NRF_RADIO___EVENTS_READY] == 0): # Busy-wait. After event READY, radio shall be in state RXIDLE.
True
machine.mem32[NRF_RADIO___TASKS_START] = 1 # Move from RXIDLE mode into RX mode.
def start():
# Main setup
initializeSerialOutput()
initializeHardware()
initializeClocks()
initializeRadio()
# Main loop
packetCounter = 0
while (True):
if (machine.mem32[NRF_RADIO___STATE] != 3): # if radio no longer in RX state, then it must have received a packet
packetCounter = packetCounter + 1
payload = ((machine.mem32[radioBuffer_address]) % 256)
print(packetCounter, "Payload received:", payload)
machine.mem32[NRF_RADIO___TASKS_START] = 1 # Move from RXIDLE mode into RX mode to receive another packet
Code: Select all
# This program for an nRF52840 sends a one byte payload in a
# packet once every second.
from micropython import const
import machine # so can peek and poke different registers on the nRF5x
import uctypes
import utime
radioBuffer = bytearray(100) # allocate IO buffer for use by nRF5x radio
radioBuffer_address = uctypes.addressof(radioBuffer)
target_prefixAddress = const(0xAA)
target_baseAddress = const(0xDEADBEEF)
NRF_POWER = const(0x40000000)
DCDCEN = const(0x578)
NRF_POWER___DCDCEN = const(NRF_POWER + DCDCEN)
NRF_CLOCK = const(0x40000000)
TASKS_HFCLKSTART = const(0)
EVENTS_HFCLKSTARTED = const(0x100)
NRF_CLOCK___TASKS_HFCLKSTART = const(NRF_CLOCK + TASKS_HFCLKSTART)
NRF_CLOCK___EVENTS_HFCLKSTARTED = const(NRF_CLOCK + EVENTS_HFCLKSTARTED)
NRF_RADIO = const(0x40001000)
BASE0 = const(0x51C)
PREFIX0 = const(0x524)
FREQUENCY = const(0x508)
PCNF1 = const(0x518)
PCNF0 = const(0x514)
MODE = const(0x510)
MODECNF0 = const(0x650)
CRCCNF = const(0x534)
PACKETPTR = const(0x504)
RXADDRESSES = const(0x530)
TXPOWER = const(0x50C)
TASKS_DISABLE = const(0x010)
STATE = const(0x550)
TASKS_TXEN = const(0)
EVENTS_READY = const(0x100)
TASKS_START = const(0x008)
NRF_RADIO___BASE0 = const(NRF_RADIO + BASE0)
NRF_RADIO___PREFIX0 = const(NRF_RADIO + PREFIX0)
NRF_RADIO___FREQUENCY = const(NRF_RADIO + FREQUENCY)
NRF_RADIO___PCNF1 = const(NRF_RADIO + PCNF1)
NRF_RADIO___PCNF0 = const(NRF_RADIO + PCNF0)
NRF_RADIO___MODE = const(NRF_RADIO + MODE)
NRF_RADIO___MODECNF0 = const(NRF_RADIO + MODECNF0)
NRF_RADIO___CRCCNF = const(NRF_RADIO + CRCCNF)
NRF_RADIO___PACKETPTR = const(NRF_RADIO + PACKETPTR)
NRF_RADIO___RXADDRESSES = const(NRF_RADIO + RXADDRESSES)
NRF_RADIO___TXPOWER = const(NRF_RADIO + TXPOWER)
NRF_RADIO___TASKS_DISABLE = const(NRF_RADIO + TASKS_DISABLE)
NRF_RADIO___STATE = const(NRF_RADIO + STATE)
NRF_RADIO___TASKS_TXEN = const(NRF_RADIO + TASKS_TXEN)
NRF_RADIO___EVENTS_READY = const(NRF_RADIO + EVENTS_READY)
NRF_RADIO___TASKS_START = const(NRF_RADIO + TASKS_START)
def initializeSerialOutput():
print("Starting...")
def initializeHardware(): # enable the DCDC voltage regulator
machine.mem32[NRF_POWER___DCDCEN] = 1 # NRF_POWER->DCDCEN=1;
def initializeClocks(): # activate the high frequency crystal oscillator
# NRF_CLOCK->TASKS_HFCLKSTART=1;
machine.mem32[NRF_CLOCK___TASKS_HFCLKSTART] = 1
# wait until high frequency clock start is confirmed
# while (NRF_CLOCK->EVENTS_HFCLKSTARTED==0) {};
while (machine.mem32[NRF_CLOCK___EVENTS_HFCLKSTARTED] == 0):
True
def initializeRadio():
# print target address in hexadecimal
print("Target address is 0x{:02X}".format(target_prefixAddress)
+ "{:08X}".format(target_baseAddress))
machine.mem32[NRF_RADIO___BASE0] = target_baseAddress
machine.mem32[NRF_RADIO___PREFIX0] = target_prefixAddress
# value must be between 0 and 100
machine.mem32[NRF_RADIO___FREQUENCY] = 98 # 2498Mhz.
# base address is 4 bytes long (possible range is 2 to 4) and
# max size of payload is 1,and 1 bytes of static length payload
machine.mem32[NRF_RADIO___PCNF1] = 0x40101
# S0,LENGTH, and S1 are all zero bits long.
machine.mem32[NRF_RADIO___PCNF0] = 0
machine.mem32[NRF_RADIO___MODE] = 1 # set 2Mbps datarate.
machine.mem32[NRF_RADIO___MODECNF0] = 1 # enable fast ramp-up of radio from DISABLED state.
machine.mem32[NRF_RADIO___CRCCNF] = 3 # CRC will be 3 bytes and is computed including the address field
machine.mem32[NRF_RADIO___PACKETPTR] = radioBuffer_address # pointer to the payload in radioBuffer
machine.mem32[NRF_RADIO___RXADDRESSES] = 1 # receive on logical address 0. Not important for transmitting.
machine.mem32[NRF_RADIO___TXPOWER] = 4 # set to 4db transmit power, which is the maximum. max for nRF52840 is 8db
machine.mem32[NRF_RADIO___TASKS_DISABLE] = 1 # DISABLE the radio to establish a known state.
while (machine.mem32[NRF_RADIO___STATE] != 0): # wait until radio is DISABLED (i.e. STATE=0);
True
machine.mem32[NRF_RADIO___TASKS_TXEN] = 1 # turn on the radio transmitter and shift into TXIDLE.
while (machine.mem32[NRF_RADIO___EVENTS_READY] == 0): # Busy-wait. After event READY, radio shall be in state TXIDLE.
True
machine.mem32[const(NRF_RADIO___TASKS_START)] = 1 # Move from TXIDLE mode into TX mode.
def start():
# Main setup
initializeSerialOutput()
initializeHardware()
initializeClocks()
initializeRadio()
# Main loop
while (True):
if (machine.mem32[NRF_RADIO___STATE] != 11): # if radio no longer in TX state, then it must have sent a packet
utime.sleep_ms(1000) # wait one second before sending next packet
machine.mem32[radioBuffer_address] = ((machine.mem32[radioBuffer_address] + 1) % 256) # increment the payload value to send something different
machine.mem32[NRF_RADIO___TASKS_START] = 1 # Move from TXIDLE mode into TX mode to transmit another packet
Code: Select all
start()
Presently the transmitter is sending packets faster than one a second (viewtopic.php?f=12&t=5417), but for demo purposes that doesn't matter. The receiver has no problem keeping up with it.
With this as a starting point, you can easily extend the code to do whatever you want.
Enjoy!