49 #include "sys/int-master.h" 50 #include "sys/critical.h" 54 #include "nrf_radio.h" 56 #include "nrf_timer.h" 57 #include "nrf_clock.h" 75 #define LOG_MODULE "nRF52840 IEEE" 76 #define LOG_LEVEL LOG_LEVEL_ERR 78 #define NRF52840_CCA_BUSY 0 79 #define NRF52840_CCA_CLEAR 1 81 #define NRF52840_RECEIVING_NO 0 82 #define NRF52840_RECEIVING_YES 1 84 #define NRF52840_PENDING_NO 0 85 #define NRF52840_PENDING_YES 1 87 #define NRF52840_COMMAND_ERR 0 88 #define NRF52840_COMMAND_OK 1 90 #define NRF52840_CHANNEL_MIN 11 91 #define NRF52840_CHANNEL_MAX 26 93 #define ED_RSSISCALE 4 102 #define MAX_PAYLOAD_LEN (MPDU_LEN - FCS_LEN) 104 #define ACK_MPDU_MIN_LEN 5 105 #define ACK_PAYLOAD_MIN_LEN (ACK_MPDU_MIN_LEN - FCS_LEN) 116 static int8_t last_rssi;
117 static uint8_t last_lqi;
119 PROCESS(nrf52840_ieee_rf_process,
"nRF52840 IEEE RF driver");
121 #ifndef NRF52840_CCA_MODE 122 #define NRF52840_CCA_MODE RADIO_CCACTRL_CCAMODE_CarrierAndEdMode 125 #ifndef NRF52840_CCA_ED_THRESHOLD 126 #define NRF52840_CCA_ED_THRESHOLD 0x14 129 #ifndef NRF52840_CCA_CORR_THRESHOLD 130 #define NRF52840_CCA_CORR_THRESHOLD 0x14 133 #ifndef NRF52840_CCA_CORR_COUNT 134 #define NRF52840_CCA_CORR_COUNT 0x02 145 #define CRC_IEEE802154_LEN 2 146 #define CRC_IEEE802154_POLY 0x11021 147 #define CRC_IEEE802154_INIT 0 149 #define SYMBOL_DURATION_USEC 16 150 #define SYMBOL_DURATION_RTIMER 1 151 #define BYTE_DURATION_RTIMER (SYMBOL_DURATION_RTIMER * 2) 152 #define TXRU_DURATION_TIMER 3 154 typedef struct timestamps_s {
156 rtimer_clock_t framestart;
158 rtimer_clock_t mpdu_duration;
162 static volatile timestamps_t timestamps;
164 typedef struct tx_buf_s {
166 uint8_t mpdu[MAX_PAYLOAD_LEN];
169 static tx_buf_t tx_buf;
171 typedef struct rx_buf_s {
173 uint8_t mpdu[MPDU_LEN];
177 static rx_buf_t rx_buf;
179 typedef struct rf_cfg_s {
181 nrf_radio_txpower_t txpower;
185 uint8_t cca_corr_threshold;
186 uint8_t cca_corr_count;
187 uint8_t ed_threshold;
190 static volatile rf_cfg_t rf_config = {
192 .txpower = NRF_RADIO_TXPOWER_0DBM,
195 .cca_mode = NRF52840_CCA_MODE,
196 .cca_corr_threshold = NRF52840_CCA_CORR_THRESHOLD,
197 .cca_corr_count = NRF52840_CCA_CORR_COUNT,
198 .ed_threshold = NRF52840_CCA_ED_THRESHOLD,
202 phr_is_valid(uint8_t phr)
204 if(phr < ACK_MPDU_MIN_LEN || phr > MPDU_LEN) {
211 radio_is_powered(
void)
213 return NRF_RADIO->POWER == 0 ? false :
true;
219 return NRF_RADIO->FREQUENCY / 5 + 10;
225 NRF_RADIO->FREQUENCY = 5 * (channel - 10);
229 cca_reconfigure(
void)
233 ccactrl = rf_config.cca_mode;
234 ccactrl |= rf_config.ed_threshold << RADIO_CCACTRL_CCAEDTHRES_Pos;
235 ccactrl |= rf_config.cca_corr_count << RADIO_CCACTRL_CCACORRCNT_Pos;
236 ccactrl |= rf_config.cca_corr_threshold << RADIO_CCACTRL_CCACORRTHRES_Pos;
238 NRF_RADIO->CCACTRL = ccactrl;
250 nrf_radio_crc_configure(CRC_IEEE802154_LEN, NRF_RADIO_CRC_ADDR_IEEE802154,
251 CRC_IEEE802154_POLY);
253 nrf_radio_crcinit_set(CRC_IEEE802154_INIT);
260 nrf_radio_packet_conf_t conf;
262 memset(&conf, 0,
sizeof(conf));
266 conf.plen = NRF_RADIO_PREAMBLE_LENGTH_32BIT_ZERO;
268 conf.big_endian =
false;
269 conf.whiteen =
false;
270 conf.maxlen = MPDU_LEN;
272 nrf_radio_packet_configure(&conf);
276 setup_interrupts(
void)
279 nrf_radio_int_mask_t interrupts = 0;
283 if(!rf_config.poll_mode) {
284 nrf_radio_event_clear(NRF_RADIO_EVENT_CRCOK);
285 nrf_radio_event_clear(NRF_RADIO_EVENT_CRCERROR);
286 interrupts |= NRF_RADIO_INT_CRCOK_MASK | NRF_RADIO_INT_CRCERROR_MASK;
290 nrf_radio_int_disable(0xFFFFFFFF);
291 NVIC_ClearPendingIRQ(RADIO_IRQn);
294 nrf_radio_int_enable(interrupts);
295 NVIC_EnableIRQ(RADIO_IRQn);
298 NVIC_DisableIRQ(RADIO_IRQn);
310 setup_ppi_timestamping(
void)
312 nrf_ppi_channel_endpoint_setup(
314 (uint32_t)nrf_radio_event_address_get(NRF_RADIO_EVENT_FRAMESTART),
315 (uint32_t)nrf_timer_task_address_get(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3));
316 nrf_ppi_channel_enable(NRF_PPI_CHANNEL0);
317 nrf_ppi_channel_enable(NRF_PPI_CHANNEL27);
321 set_poll_mode(
bool enable)
323 rf_config.poll_mode = enable;
330 memset(&rx_buf, 0,
sizeof(rx_buf));
336 nrf_radio_event_clear(NRF_RADIO_EVENT_FRAMESTART);
337 nrf_radio_event_clear(NRF_RADIO_EVENT_END);
338 nrf_radio_event_clear(NRF_RADIO_EVENT_CRCERROR);
339 nrf_radio_event_clear(NRF_RADIO_EVENT_CRCOK);
350 nrf_radio_mode_set(NRF_RADIO_MODE_IEEE802154_250KBIT);
366 nrf_radio_modecnf0_set(
true, RADIO_MODECNF0_DTX_Center);
370 power_on_and_configure(
void)
372 nrf_radio_power_set(
true);
390 nrf_radio_state_t curr_state = nrf_radio_state_get();
392 LOG_DBG(
"Enter RX, state=%u", curr_state);
395 if(curr_state == NRF_RADIO_STATE_RX) {
396 LOG_DBG_(
". Was in RX");
402 nrf_radio_packetptr_set(&rx_buf);
405 setup_ppi_timestamping();
410 nrf_radio_shorts_enable(NRF_RADIO_SHORT_ADDRESS_RSSISTART_MASK);
411 nrf_radio_shorts_enable(NRF_RADIO_SHORT_RXREADY_START_MASK);
413 if(curr_state != NRF_RADIO_STATE_RXIDLE) {
415 nrf_radio_event_clear(NRF_RADIO_EVENT_RXREADY);
416 nrf_radio_task_trigger(NRF_RADIO_TASK_RXEN);
419 nrf_radio_task_trigger(NRF_RADIO_TASK_START);
422 LOG_DBG_(
"--->%u\n", nrf_radio_state_get());
424 LOG_DBG(
"PACKETPTR=0x%08lx (rx_buf @ 0x%08lx)\n",
425 (uint32_t)nrf_radio_packetptr_get(), (uint32_t)&rx_buf);
434 nrf_radio_task_trigger(NRF_RADIO_TASK_RSSISTART);
436 while(nrf_radio_event_check(NRF_RADIO_EVENT_RSSIEND) ==
false);
437 nrf_radio_event_clear(NRF_RADIO_EVENT_RSSIEND);
439 rssi_sample = nrf_radio_rssi_sample_get();
441 return -((int8_t)rssi_sample);
449 lqi_convert_to_802154_scale(uint8_t lqi_hw)
451 return (uint8_t)lqi_hw > 63 ? 255 : lqi_hw * ED_RSSISCALE;
461 if(radio_is_powered() ==
false) {
462 LOG_DBG(
"Not powered\n");
463 power_on_and_configure();
468 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
469 return NRF52840_COMMAND_OK;
477 LOG_DBG(
"channel_clear\n");
482 nrf_radio_event_clear(NRF_RADIO_EVENT_CCABUSY);
483 nrf_radio_event_clear(NRF_RADIO_EVENT_CCAIDLE);
484 nrf_radio_event_clear(NRF_RADIO_EVENT_CCASTOPPED);
486 LOG_DBG(
"channel_clear: CCACTRL=0x%08lx\n", NRF_RADIO->CCACTRL);
489 nrf_radio_task_trigger(NRF_RADIO_TASK_CCASTART);
491 while((nrf_radio_event_check(NRF_RADIO_EVENT_CCABUSY) ==
false) &&
492 (nrf_radio_event_check(NRF_RADIO_EVENT_CCAIDLE) ==
false));
494 busy = nrf_radio_event_check(NRF_RADIO_EVENT_CCABUSY);
495 idle = nrf_radio_event_check(NRF_RADIO_EVENT_CCAIDLE);
497 LOG_DBG(
"channel_clear: I=%u, B=%u\n", idle, busy);
500 return NRF52840_CCA_BUSY;
503 return NRF52840_CCA_CLEAR;
515 timestamps.framestart = 0;
517 timestamps.mpdu_duration = 0;
521 nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
522 nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
523 while(!nrf_clock_event_check(NRF_CLOCK_EVENT_HFCLKSTARTED));
524 nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
533 power_on_and_configure();
536 set_poll_mode(rf_config.poll_mode);
542 prepare(
const void *payload,
unsigned short payload_len)
544 LOG_DBG(
"Prepare %u bytes\n", payload_len);
546 if(payload_len > MAX_PAYLOAD_LEN) {
547 LOG_ERR(
"Too long: %u bytes, max %u\n", payload_len, MAX_PAYLOAD_LEN);
552 tx_buf.phr = (uint8_t)payload_len + FCS_LEN;
555 memcpy(tx_buf.mpdu, payload, payload_len);
561 transmit(
unsigned short transmit_len)
565 LOG_DBG(
"TX %u bytes + FCS, channel=%u\n", transmit_len,
get_channel());
567 if(transmit_len > MAX_PAYLOAD_LEN) {
568 LOG_ERR(
"TX: too long (%u bytes)\n", transmit_len);
574 if(rf_config.send_on_cca) {
575 if(channel_clear() == NRF52840_CCA_BUSY) {
576 LOG_DBG(
"TX: Busy\n");
581 nrf_radio_txpower_set(rf_config.txpower);
584 nrf_radio_task_trigger(NRF_RADIO_TASK_STOP);
585 while(nrf_radio_state_get() != NRF_RADIO_STATE_RXIDLE);
587 LOG_DBG(
"Transmit: %u bytes=000000", tx_buf.phr);
588 for(i = 0; i < tx_buf.phr - 2; i++) {
589 LOG_DBG_(
" %02x", tx_buf.mpdu[i]);
593 LOG_DBG(
"TX Start. State %u", nrf_radio_state_get());
596 nrf_radio_packetptr_set(&tx_buf);
599 nrf_radio_event_clear(NRF_RADIO_EVENT_END);
600 nrf_radio_event_clear(NRF_RADIO_EVENT_PHYEND);
601 nrf_radio_event_clear(NRF_RADIO_EVENT_TXREADY);
604 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
607 nrf_radio_shorts_enable(NRF_RADIO_SHORT_TXREADY_START_MASK);
608 nrf_radio_task_trigger(NRF_RADIO_TASK_TXEN);
617 LOG_DBG_(
"--->%u\n", nrf_radio_state_get());
620 while(nrf_radio_state_get() == NRF_RADIO_STATE_TX);
622 LOG_DBG(
"TX: Done\n");
633 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
639 send(
const void *payload,
unsigned short payload_len)
641 prepare(payload, payload_len);
642 return transmit(payload_len);
646 read_frame(
void *buf,
unsigned short bufsize)
653 payload_len = rx_buf.phr - FCS_LEN;
655 if(phr_is_valid(rx_buf.phr) ==
false) {
656 LOG_DBG(
"Incorrect length: %d\n", payload_len);
662 memcpy(buf, rx_buf.mpdu, payload_len);
663 last_lqi = lqi_convert_to_802154_scale(rx_buf.mpdu[payload_len]);
664 last_rssi = -(nrf_radio_rssi_sample_get());
666 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, last_rssi);
667 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, last_lqi);
670 timestamps.phr = rx_buf.phr;
671 timestamps.framestart = nrf_timer_cc_read(NRF_TIMER0, NRF_TIMER_CC_CHANNEL3);
672 timestamps.end = nrf_timer_cc_read(NRF_TIMER0, NRF_TIMER_CC_CHANNEL2);
673 timestamps.mpdu_duration = rx_buf.phr * BYTE_DURATION_RTIMER;
680 timestamps.sfd = timestamps.framestart - BYTE_DURATION_RTIMER;
682 LOG_DBG(
"Read frame: len=%d, RSSI=%d, LQI=0x%02x\n", payload_len, last_rssi,
692 receiving_packet(
void)
695 if(radio_is_powered() ==
false) {
696 return NRF52840_RECEIVING_NO;
700 if(nrf_radio_state_get() != NRF_RADIO_STATE_RX) {
701 return NRF52840_RECEIVING_NO;
704 if(rf_config.poll_mode) {
706 if(phr_is_valid(rx_buf.phr) ==
false) {
707 return NRF52840_RECEIVING_NO;
714 if((nrf_radio_event_check(NRF_RADIO_EVENT_CRCOK) ==
false) &&
715 (nrf_radio_event_check(NRF_RADIO_EVENT_CRCERROR) ==
false)) {
716 return NRF52840_RECEIVING_YES;
719 return NRF52840_RECEIVING_NO;
726 if(phr_is_valid(rx_buf.phr) ==
true && rx_buf.full ==
false) {
727 return NRF52840_RECEIVING_YES;
729 return NRF52840_RECEIVING_NO;
739 if(phr_is_valid(rx_buf.phr) ==
false) {
740 return NRF52840_PENDING_NO;
750 if((nrf_radio_event_check(NRF_RADIO_EVENT_CRCOK) ==
true) ||
751 (rx_buf.full ==
true)) {
752 return NRF52840_PENDING_YES;
755 return NRF52840_PENDING_NO;
761 nrf_radio_power_set(
false);
763 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
765 return NRF52840_COMMAND_OK;
783 if(rf_config.poll_mode) {
789 if(rf_config.send_on_cca) {
835 case RADIO_CONST_MAX_PAYLOAD_LEN:
860 if(value < NRF52840_CHANNEL_MIN ||
861 value > NRF52840_CHANNEL_MAX) {
864 rf_config.channel = value;
867 if(radio_is_powered()) {
891 rf_config.txpower = value;
893 if(radio_is_powered()) {
894 nrf_radio_txpower_set(value);
898 rf_config.cca_corr_threshold = value;
900 if(radio_is_powered()) {
914 get_object(radio_param_t param,
void *dest,
size_t size)
917 if(size !=
sizeof(rtimer_clock_t) || !dest) {
920 *(rtimer_clock_t *)dest = timestamps.sfd;
924 #if MAC_CONF_WITH_TSCH 925 if(param == RADIO_CONST_TSCH_TIMING) {
926 if(size !=
sizeof(uint16_t *) || !dest) {
940 set_object(radio_param_t param,
const void *src,
size_t size)
979 NETSTACK_MAC.
input();
980 LOG_DBG(
"last frame (%u bytes) timestamps:\n", timestamps.phr);
981 LOG_DBG(
" SFD=%lu (Derived)\n", timestamps.sfd);
982 LOG_DBG(
" PHY=%lu (PPI)\n", timestamps.framestart);
983 LOG_DBG(
" MPDU=%lu (Duration)\n", timestamps.mpdu_duration);
984 LOG_DBG(
" END=%lu (PPI)\n", timestamps.end);
985 LOG_DBG(
" Expected=%lu + %u + %lu = %lu\n", timestamps.sfd,
986 BYTE_DURATION_RTIMER, timestamps.mpdu_duration,
987 timestamps.sfd + BYTE_DURATION_RTIMER + timestamps.mpdu_duration);
996 RADIO_IRQHandler(
void)
998 if(!rf_config.poll_mode) {
999 if(nrf_radio_event_check(NRF_RADIO_EVENT_CRCOK)) {
1000 nrf_radio_event_clear(NRF_RADIO_EVENT_CRCOK);
1003 }
else if(nrf_radio_event_check(NRF_RADIO_EVENT_CRCERROR)) {
1004 nrf_radio_event_clear(NRF_RADIO_EVENT_CRCERROR);
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
The delay in usec between turning on the radio and it being actually listening (able to hear a preamb...
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
#define PROCESS(name, strname)
Declare a process.
The parameter is not supported.
void packetbuf_clear(void)
Clear and reset the packetbuf.
Header file for the energy estimation mechanism
TX failed due to a collision.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Header file for the radio API
#define PROCESS_BEGIN()
Define the beginning of a process.
The delay in usec between a call to the radio API's transmit function and the end of SFD transmission...
The maximum transmission power in dBm.
static void critical_exit(int_master_status_t status)
Exit a critical section and restore the master interrupt.
#define PROCESS_END()
Define the end of a process.
Received signal strength indicator in dBm.
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
The short address (16 bits) for the radio, which is used by the h/w filter.
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
int(* pending_packet)(void)
Check if a packet has been received and is available in the radio driver's buffers.
The structure of a Contiki-NG radio device driver.
static void set_channel(uint8_t channel)
Set the current operating channel.
Channel used for radio communication.
For enabling and disabling the SHR search.
The value argument was incorrect.
The parameter was set/read successfully.
int(* channel_clear)(void)
Perform a Clear-Channel Assessment (CCA) to find out if there is a packet in the air or not...
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio...
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
#define IEEE802154_DEFAULT_CHANNEL
The default channel for IEEE 802.15.4 networks.
static int_master_status_t critical_enter()
Enter a critical section.
The RSSI value of the last received packet.
The physical layer header (PHR) + MAC layer footer (MFR) overhead in bytes.
Clear channel assessment threshold in dBm.
INT_MASTER_STATUS_DATATYPE int_master_status_t
Master interrupt state representation data type.
void(* input)(void)
Callback for getting notified of incoming packet.
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
void process_poll(struct process *p)
Request a process to be polled.
int(* off)(void)
Turn the radio off.
The personal area network identifier (PAN ID), which is used by the h/w frame filtering functionality...
The lowest radio channel number.
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
The highest radio channel number.
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
The air time of one byte in usec, e.g.
Main API declarations for TSCH.
#define RADIO_RX_MODE_ADDRESS_FILTER
Enable address-based frame filtering.
When getting the value of this parameter, the radio driver should indicate whether the radio is on or...
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
#define RADIO_RX_MODE_AUTOACK
Enable automatic transmission of ACK frames.
int(* init)(void)
Initialise the radio hardware.
The delay in usec between the end of SFD reception for an incoming frame and the radio API starting t...
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
Link quality indicator of the last received packet.
The minimum transmission power in dBm.
Radio powered on and able to receive frames.
Transmission power in dBm.
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
void watchdog_periodic(void)
Writes the WDT clear sequence.
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Last packet timestamp, of type rtimer_clock_t.
An error occurred during transmission.
Header file for the logging system
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
Radio powered off and in the lowest possible power consumption state.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
TX was successful and where an ACK was requested one was received.
const tsch_timeslot_timing_usec tsch_timeslot_timing_us_10000
TSCH timing attributes and description.
int(* on)(void)
Turn the radio on.
#define RTIMER_BUSYWAIT(duration)
Busy-wait for a fixed duration.
void process_start(struct process *p, process_data_t data)
Start a process.
static uint8_t get_channel()
Get the current operating channel.