Implement basic radio TX on fixed channel
radio_init() configures RADIO in NRF_1Mbit proprietary mode: 8-bit length field, 4-byte address (BASE0+PREFIX0), 2-byte CRC-16/CCITT, 0 dBm TX power, channel 20 (2420 MHz). READY->START and END->DISABLE shortcuts let radio_tx() trigger the full ramp-up/TX/disable sequence by writing TASKS_TXEN once, then polling EVENTS_END. main.c sends a fixed 4-byte test frame on every button press. FHSS and AES remain compiled but are not called. New bitfield unions in regs.h: radio_pcnf0_t, radio_pcnf1_t, radio_crccnf_t, radio_shorts_t.
This commit is contained in:
@@ -88,3 +88,67 @@ typedef union {
|
|||||||
#define RADIO_MODE_NRF_1MBIT 0u
|
#define RADIO_MODE_NRF_1MBIT 0u
|
||||||
#define RADIO_MODE_NRF_2MBIT 1u
|
#define RADIO_MODE_NRF_2MBIT 1u
|
||||||
#define RADIO_MODE_BLE_1MBIT 4u
|
#define RADIO_MODE_BLE_1MBIT 4u
|
||||||
|
|
||||||
|
/* PCNF0: packet configuration register 0 */
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
uint32_t LFLEN : 4; /* [3:0] length of LENGTH field in bits */
|
||||||
|
uint32_t : 4; /* [7:4] reserved */
|
||||||
|
uint32_t S0LEN : 1; /* [8] length of S0 field in bytes (0 or 1) */
|
||||||
|
uint32_t : 7; /* [15:9] reserved */
|
||||||
|
uint32_t S1LEN : 4; /* [19:16] length of S1 field in bits */
|
||||||
|
uint32_t S1INCL : 1; /* [20] include S1 field in RAM even if zero length */
|
||||||
|
uint32_t : 3; /* [23:21] reserved */
|
||||||
|
uint32_t PLEN : 1; /* [24] 0=8-bit preamble 1=16-bit preamble */
|
||||||
|
uint32_t : 6; /* [30:25] reserved */
|
||||||
|
uint32_t CRCINC : 1; /* [31] include CRC in LENGTH field */
|
||||||
|
} bit;
|
||||||
|
uint32_t reg;
|
||||||
|
} radio_pcnf0_t;
|
||||||
|
|
||||||
|
/* PCNF1: packet configuration register 1 */
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
uint32_t MAXLEN : 8; /* [7:0] maximum payload length in bytes */
|
||||||
|
uint32_t STATLEN : 8; /* [15:8] static length added to payload */
|
||||||
|
uint32_t BALEN : 3; /* [18:16] base address length (2-4 bytes) */
|
||||||
|
uint32_t : 5; /* [23:19] reserved */
|
||||||
|
uint32_t ENDIAN : 1; /* [24] 0=little-endian 1=big-endian */
|
||||||
|
uint32_t WHITEEN : 1; /* [25] 1=enable data whitening */
|
||||||
|
uint32_t : 6; /* [31:26] reserved */
|
||||||
|
} bit;
|
||||||
|
uint32_t reg;
|
||||||
|
} radio_pcnf1_t;
|
||||||
|
|
||||||
|
/* CRCCNF: CRC configuration */
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
uint32_t LEN : 2; /* [1:0] 0=disabled 1=1 byte 2=2 bytes 3=3 bytes */
|
||||||
|
uint32_t : 6; /* [7:2] reserved */
|
||||||
|
uint32_t SKIPADDR : 1; /* [8] 1=skip address field in CRC calculation */
|
||||||
|
uint32_t : 23; /* [31:9] reserved */
|
||||||
|
} bit;
|
||||||
|
uint32_t reg;
|
||||||
|
} radio_crccnf_t;
|
||||||
|
|
||||||
|
#define RADIO_CRCCNF_LEN_DISABLED 0u
|
||||||
|
#define RADIO_CRCCNF_LEN_ONE 1u
|
||||||
|
#define RADIO_CRCCNF_LEN_TWO 2u
|
||||||
|
#define RADIO_CRCCNF_LEN_THREE 3u
|
||||||
|
|
||||||
|
/* SHORTS: shortcut register */
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
uint32_t READY_START : 1; /* [0] READY -> TASKS_START */
|
||||||
|
uint32_t END_DISABLE : 1; /* [1] END -> TASKS_DISABLE */
|
||||||
|
uint32_t DISABLED_TXEN : 1; /* [2] DISABLED -> TASKS_TXEN */
|
||||||
|
uint32_t DISABLED_RXEN : 1; /* [3] DISABLED -> TASKS_RXEN */
|
||||||
|
uint32_t ADDRESS_RSSISTART : 1; /* [4] ADDRESS -> TASKS_RSSISTART */
|
||||||
|
uint32_t END_START : 1; /* [5] END -> TASKS_START */
|
||||||
|
uint32_t ADDRESS_BCSTART : 1; /* [6] ADDRESS -> TASKS_BCSTART */
|
||||||
|
uint32_t : 1; /* [7] reserved */
|
||||||
|
uint32_t DISABLED_RSSISTOP : 1; /* [8] DISABLED -> TASKS_RSSISTOP */
|
||||||
|
uint32_t : 23; /* [31:9] reserved */
|
||||||
|
} bit;
|
||||||
|
uint32_t reg;
|
||||||
|
} radio_shorts_t;
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
#include "fhss.h"
|
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static const uint8_t test_frame[] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
power_init();
|
power_init();
|
||||||
radio_init();
|
radio_init();
|
||||||
fhss_init();
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
power_sleep_until_button();
|
power_sleep_until_button();
|
||||||
radio_tx_burst();
|
radio_tx(test_frame, sizeof(test_frame));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
src/radio.c
83
src/radio.c
@@ -1,11 +1,73 @@
|
|||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
#include "fhss.h"
|
|
||||||
#include "regs.h"
|
#include "regs.h"
|
||||||
#include <nrf52840.h>
|
#include <nrf52840.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packet buffer layout (S0=1B, LENGTH=8-bit, S1=0, payload up to 255B):
|
||||||
|
* [0] LENGTH - payload byte count (written by radio_tx)
|
||||||
|
* [1..1+len] payload - caller-supplied data
|
||||||
|
*
|
||||||
|
* RADIO is configured for NRF_1Mbit proprietary mode, fixed channel,
|
||||||
|
* no data whitening, 2-byte CRC over payload only.
|
||||||
|
* TX is synchronous: function returns after EVENTS_END fires.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_PAYLOAD 255u
|
||||||
|
#define BUF_SIZE (1u + MAX_PAYLOAD)
|
||||||
|
|
||||||
|
static uint8_t pkt_buf[BUF_SIZE];
|
||||||
|
|
||||||
|
/* Logical channel 20 -> 2400 + 20 = 2420 MHz (MAP=0) */
|
||||||
|
#define DEFAULT_CHANNEL 20u
|
||||||
|
|
||||||
|
/* 4-byte base address (3-byte BALEN field means 3+1=4 total address bytes) */
|
||||||
|
#define RADIO_BASE0 0x12345678u
|
||||||
|
#define RADIO_PREFIX0 0xABu /* logical address 0: RADIO_BASE0 + RADIO_PREFIX0[7:0] */
|
||||||
|
|
||||||
void radio_init(void)
|
void radio_init(void)
|
||||||
{
|
{
|
||||||
/* TODO: configure RADIO peripheral (MODE, PCNF0/1, BASE/PREFIX, CRC) */
|
NRF_RADIO->MODE = (radio_mode_t){
|
||||||
|
.bit = { .MODE = RADIO_MODE_NRF_1MBIT }
|
||||||
|
}.reg;
|
||||||
|
|
||||||
|
/* 8-bit LENGTH field, no S0/S1, 8-bit preamble, CRC not part of LENGTH */
|
||||||
|
NRF_RADIO->PCNF0 = (radio_pcnf0_t){
|
||||||
|
.bit = { .LFLEN = 8, .S0LEN = 0, .S1LEN = 0, .PLEN = 0, .CRCINC = 0 }
|
||||||
|
}.reg;
|
||||||
|
|
||||||
|
/* max 255-byte payload, 3-byte base address, little-endian, no whitening */
|
||||||
|
NRF_RADIO->PCNF1 = (radio_pcnf1_t){
|
||||||
|
.bit = { .MAXLEN = MAX_PAYLOAD, .STATLEN = 0, .BALEN = 3,
|
||||||
|
.ENDIAN = 0, .WHITEEN = 0 }
|
||||||
|
}.reg;
|
||||||
|
|
||||||
|
NRF_RADIO->BASE0 = RADIO_BASE0;
|
||||||
|
NRF_RADIO->PREFIX0 = RADIO_PREFIX0;
|
||||||
|
NRF_RADIO->TXADDRESS = 0; /* transmit on logical address 0 */
|
||||||
|
NRF_RADIO->RXADDRESSES = 1; /* receive on logical address 0 */
|
||||||
|
|
||||||
|
/* 2-byte CRC, skip address field */
|
||||||
|
NRF_RADIO->CRCCNF = (radio_crccnf_t){
|
||||||
|
.bit = { .LEN = RADIO_CRCCNF_LEN_TWO, .SKIPADDR = 1 }
|
||||||
|
}.reg;
|
||||||
|
NRF_RADIO->CRCPOLY = 0x11021u; /* CRC-16/CCITT */
|
||||||
|
NRF_RADIO->CRCINIT = 0xFFFFu;
|
||||||
|
|
||||||
|
NRF_RADIO->TXPOWER = (radio_txpower_t){
|
||||||
|
.bit = { .TXPOWER = 0 } /* 0 dBm */
|
||||||
|
}.reg;
|
||||||
|
|
||||||
|
NRF_RADIO->FREQUENCY = (radio_frequency_t){
|
||||||
|
.bit = { .FREQUENCY = DEFAULT_CHANNEL, .MAP = RADIO_MAP_DEFAULT }
|
||||||
|
}.reg;
|
||||||
|
|
||||||
|
/* READY -> START and END -> DISABLE shortcuts so CPU only triggers TXEN */
|
||||||
|
NRF_RADIO->SHORTS = (radio_shorts_t){
|
||||||
|
.bit = { .READY_START = 1, .END_DISABLE = 1 }
|
||||||
|
}.reg;
|
||||||
|
|
||||||
|
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void radio_set_channel(uint8_t ch)
|
void radio_set_channel(uint8_t ch)
|
||||||
@@ -17,11 +79,22 @@ void radio_set_channel(uint8_t ch)
|
|||||||
|
|
||||||
void radio_tx(const uint8_t *data, uint8_t len)
|
void radio_tx(const uint8_t *data, uint8_t len)
|
||||||
{
|
{
|
||||||
(void)data; (void)len;
|
/* len is uint8_t so it cannot exceed MAX_PAYLOAD=255 by type guarantee */
|
||||||
/* TODO: load packet, enable TX, wait for END event, disable */
|
pkt_buf[0] = len;
|
||||||
|
memcpy(&pkt_buf[1], data, len);
|
||||||
|
|
||||||
|
NRF_RADIO->EVENTS_END = 0;
|
||||||
|
NRF_RADIO->TASKS_TXEN = 1;
|
||||||
|
|
||||||
|
/* Busy-wait for END event (ramp-up ~40us + TX time, total <1ms for short frames) */
|
||||||
|
while (!NRF_RADIO->EVENTS_END)
|
||||||
|
;
|
||||||
|
|
||||||
|
NRF_RADIO->EVENTS_END = 0;
|
||||||
|
/* RADIO is now DISABLED via the END_DISABLE shortcut */
|
||||||
}
|
}
|
||||||
|
|
||||||
void radio_tx_burst(void)
|
void radio_tx_burst(void)
|
||||||
{
|
{
|
||||||
/* TODO: hop + TX loop driven by fhss_next_channel() */
|
/* placeholder: FHSS TX loop not yet implemented */
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user