Nrf5 improvements (#938)

* Fix NRF5_ESB_readMessage, allways enable radio

* NRF5: fixes and improvements

- Compiles with arduino core for nRF52 (primo)
  MY_RADIO_NRF5_ESB stays unsupported with primo!

- Split ACK negation flag into
    MY_NRF5_ESB_REVERSE_ACK_TX
    MY_NRF5_ESB_REVERSE_ACK_RX

- MY_RADIO_NRF5_ESB changes to act more than NRF24

- MY_RADIO_NRF5_ESB better support for powerdown/standby

- Moved initialization from MyMainNRF5 to hwInit()
This commit is contained in:
d00616
2017-09-30 22:55:55 +02:00
committed by Henrik Ekblad
parent 9ee837199e
commit 1b1cf8ff9c
9 changed files with 159 additions and 126 deletions
+11 -4
View File
@@ -503,10 +503,16 @@
#endif
/**
* @def MY_NRF5_ESB_REVERSE_ACK
* @brief Switch to SI24R1 or faked nRF24L01+ compatible ACK mode.
* @def MY_NRF5_ESB_REVERSE_ACK_TX
* @brief Switch to SI24R1 or faked nRF24L01+ compatible ACK mode. ACK bit is reversed on TX side.
*/
//#define MY_NRF5_ESB_REVERSE_ACK
//#define MY_NRF5_ESB_REVERSE_ACK_TX
/**
* @def MY_NRF5_ESB_REVERSE_ACK_RX
* @brief Switch to SI24R1 or faked nRF24L01+ compatible ACK mode. ACK bit is reversed on RX side.
*/
//#define MY_NRF5_ESB_REVERSE_ACK_RX
/** @}*/ // End of NRF5SettingGrpPub group
/**
@@ -1865,7 +1871,8 @@
// NRF5_ESB
#define MY_NRF5_ESB_ENABLE_ENCRYPTION
#define MY_DEBUG_VERBOSE_NRF5_ESB
#define MY_NRF5_ESB_REVERSE_ACK
#define MY_NRF5_ESB_REVERSE_ACK_RX
#define MY_NRF5_ESB_REVERSE_ACK_TX
// RFM69
#define MY_IS_RFM69HW
#define MY_RFM69_NEW_DRIVER
+2 -4
View File
@@ -61,7 +61,7 @@
#include "hal/architecture/MyHwSAMD.cpp"
#elif defined(ARDUINO_ARCH_STM32F1)
#include "hal/architecture/MyHwSTM32F1.cpp"
#elif defined(ARDUINO_ARCH_NRF5)
#elif defined(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_NRF52)
#include "drivers/NVM/VirtualPage.cpp"
#include "drivers/NVM/NVRAM.cpp"
#include "hal/architecture/MyHwNRF5.cpp"
@@ -291,7 +291,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
// POWER PIN
#ifndef DOXYGEN
#if defined(MY_RF24_POWER_PIN) || defined(MY_RFM69_POWER_PIN) || defined(MY_RFM95_POWER_PIN)
#if defined(MY_RF24_POWER_PIN) || defined(MY_RFM69_POWER_PIN) || defined(MY_RFM95_POWER_PIN) || defined(MY_RADIO_NRF5_ESB)
#define RADIO_CAN_POWER_OFF (true)
#else
#define RADIO_CAN_POWER_OFF (false)
@@ -384,8 +384,6 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
#if !defined(MY_CORE_ONLY)
#if defined(ARDUINO_ARCH_ESP8266)
#include "hal/architecture/MyMainESP8266.cpp"
#elif defined(ARDUINO_ARCH_NRF5)
#include "hal/architecture/MyMainNRF5.cpp"
#elif defined(__linux__)
#include "hal/architecture/MyMainLinux.cpp"
#elif defined(ARDUINO_ARCH_STM32F1)
+1 -5
View File
@@ -23,14 +23,10 @@
#ifndef __NRF_RADIO_H__
#define __NRF_RADIO_H__
#if !defined(ARDUINO)
#if !defined(ARDUINO_ARCH_NRF5)
#error "NRF5 Radio is not supported for this platform."
#endif
#if defined(NRF5_SOFTDEVICE)
#warning "NRF5 SoftDevice cannot be used with NRF5 Radio."
#endif
#include <nrf.h>
#include <stdint.h>
#include <stdio.h>
+76 -36
View File
@@ -70,6 +70,12 @@ static bool NRF5_ESB_initialize()
// Power on radio unit
NRF_RADIO->POWER = 1;
// Disable shorts
NRF_RADIO->SHORTS = 0;
// Disable radio
NRF_RADIO->TASKS_DISABLE = 1;
// Enable radio interrupt
NVIC_SetPriority(RADIO_IRQn, 1);
NVIC_ClearPendingIRQ(RADIO_IRQn);
@@ -80,10 +86,16 @@ static bool NRF5_ESB_initialize()
NVIC_ClearPendingIRQ(NRF5_RADIO_TIMER_IRQN);
NVIC_EnableIRQ(NRF5_RADIO_TIMER_IRQN);
// Clear events
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->EVENTS_READY = 0;
// Clear all events
NRF_RADIO->EVENTS_ADDRESS = 0;
NRF_RADIO->EVENTS_BCMATCH = 0;
NRF_RADIO->EVENTS_DEVMATCH = 0;
NRF_RADIO->EVENTS_DEVMISS = 0;
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->EVENTS_PAYLOAD = 0;
NRF_RADIO->EVENTS_READY = 0;
NRF_RADIO->EVENTS_RSSIEND = 0;
// Disable all interrupts
NRF_RADIO->INTENCLR = (uint32_t)~0;
@@ -161,9 +173,16 @@ static bool NRF5_ESB_initialize()
TIMER_SHORTS_COMPARE1_CLEAR_Msk | TIMER_SHORTS_COMPARE1_STOP_Msk;
// Reset timer
NRF5_RADIO_TIMER->TASKS_CLEAR = 1;
// Reset compare events
NRF5_RADIO_TIMER->EVENTS_COMPARE[0] = 0;
NRF5_RADIO_TIMER->EVENTS_COMPARE[1] = 0;
#ifdef NRF51
for (uint8_t i=0; i<4; i++) {
#else
for (uint8_t i=0; i<6; i++) {
#endif
NRF5_RADIO_TIMER->EVENTS_COMPARE[i] = 0;
}
// Enable interrupt
NRF5_RADIO_TIMER->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
NRF5_RADIO_TIMER->INTENSET = TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos;
@@ -179,6 +198,12 @@ static bool NRF5_ESB_initialize()
// Set internal variables
radio_disabled = true;
#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
intcntr_bcmatch=0;
intcntr_ready=0;
intcntr_end=0;
#endif
return true;
}
@@ -209,19 +234,24 @@ static void NRF5_ESB_powerDown()
static void NRF5_ESB_powerUp()
{
// Not needed
NRF5_ESB_initialize();
}
static void NRF5_ESB_sleep()
{
NRF5_RADIO_DEBUG(PSTR("NRF5:SLP\n"));
NRF5_ESB_powerDown();
// Disable shorts
NRF_RADIO->SHORTS = 0;
// Disable radio
NRF_RADIO->TASKS_DISABLE = 1;
}
static void NRF5_ESB_standBy()
{
NRF5_RADIO_DEBUG(PSTR("NRF5:SBY\n"));
NRF5_ESB_initialize();
NRF5_ESB_startListening();
}
static bool NRF5_ESB_sanityCheck()
@@ -274,27 +304,27 @@ static bool NRF5_ESB_isDataAvailable()
static uint8_t NRF5_ESB_readMessage(void *data)
{
uint8_t ret = 0;
// get content from rx buffer
NRF5_ESB_Packet *buffer = rx_circular_buffer.getBack();
// Nothing to read?
if (buffer == NULL) {
return 0;
}
if (buffer != NULL) {
// copy content
memcpy(data, buffer->data, buffer->len);
ret = buffer->len;
rssi_rx = 0-buffer->rssi;
// copy content
memcpy(data, buffer->data, buffer->len);
uint8_t ret = buffer->len;
rssi_rx = 0-buffer->rssi;
// Debug message
// Debug message
#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
NRF5_RADIO_DEBUG(PSTR("NRF5:RX:LEN=%" PRIu8 ",NOACK=%" PRIu8 ",PID=%" PRIu8 ",RSSI=%" PRIi16 ",RX=%"
PRIu32 "\n"),
buffer->len, buffer->noack, buffer->pid, rssi_rx, buffer->rxmatch);
NRF5_RADIO_DEBUG(PSTR("NRF5:RX:LEN=%" PRIu8 ",NOACK=%" PRIu8 ",PID=%" PRIu8 ",RSSI=%" PRIi16 ",RX=%"
PRIu32 "\n"),
buffer->len, buffer->noack, buffer->pid, rssi_rx, buffer->rxmatch);
#endif
// release buffer
rx_circular_buffer.popBack();
// release buffer
rx_circular_buffer.popBack();
}
// Check if radio was disabled by buffer end
if (radio_disabled == true) {
@@ -399,7 +429,7 @@ static bool NRF5_ESB_sendMessage(uint8_t recipient, const void *buf, uint8_t len
// build metadata
tx_buffer.len = len;
#ifndef MY_NRF5_ESB_REVERSE_ACK
#ifndef MY_NRF5_ESB_REVERSE_ACK_TX
tx_buffer.noack = noACK || recipient==BROADCAST_ADDRESS;
#else
// reverse the noack bit
@@ -408,13 +438,13 @@ static bool NRF5_ESB_sendMessage(uint8_t recipient, const void *buf, uint8_t len
tx_buffer.pid++;
// Calculate number of retries
tx_retries = ((recipient == BROADCAST_ADDRESS)?(NRF5_ESB_BC):(NRF5_ESB_ARC));
if (recipient == BROADCAST_ADDRESS) {
tx_retries = NRF5_ESB_BC_ARC;
} else {
tx_retries = ((noACK == false)?(NRF5_ESB_ARC_ACK):(NRF5_ESB_ARC_NOACK));
}
int8_t tx_retries_start = tx_retries;
// This line disables sending a broadcast packet multiple times
// ack_received = (recipient == BROADCAST_ADDRESS);
// This line force to send an boradcast packet multiple times like NRF24
ack_received = tx_buffer.noack;
ack_received = false;
// configure TX address
NRF_RADIO->PREFIX1 = (NRF_RADIO->PREFIX1 & NRF5_ESB_TX_ADDR_MSK) |
@@ -442,9 +472,6 @@ static bool NRF5_ESB_sendMessage(uint8_t recipient, const void *buf, uint8_t len
#endif
}
// Enable listening on Node and BC address
NRF_RADIO->RXADDRESSES = (1 << NRF5_ESB_NODE_ADDR) | (1 << NRF5_ESB_BC_ADDR);
// Calculate RSSI
if (rssi_tx == INVALID_RSSI) {
// calculate pseudo-RSSI based on retransmission counter (ARC)
@@ -452,12 +479,17 @@ static bool NRF5_ESB_sendMessage(uint8_t recipient, const void *buf, uint8_t len
// Arbitrary definition: ARC 0 == -29, ARC 15 = -104
rssi_tx = (-29 - (8 * (tx_retries_start - tx_retries)));
}
// Enable listening on Node and BC address
NRF_RADIO->RXADDRESSES = (1 << NRF5_ESB_NODE_ADDR) | (1 << NRF5_ESB_BC_ADDR);
#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
NRF5_RADIO_DEBUG(PSTR("NRF5:SND:END=%" PRIu8 ",ACK=%" PRIu8 ",RTRY=%" PRIi8 ",RSSI=%" PRIi16
",WAKE=%" PRIu32 "\n"),
events_end_tx, ack_received, tx_retries_start - tx_retries, rssi_tx, wakeups);
#endif
return ack_received;
};
@@ -486,7 +518,7 @@ static uint8_t reverse_byte(uint8_t address)
return address;
}
// Calculate time to transmit an byte in us as bit shift -> 2^X
// Calculate time to transmit an byte in µs as bit shift -> 2^X
static inline uint8_t NRF5_ESB_byte_time()
{
if ((MY_NRF5_ESB_MODE == NRF5_1MBPS) or
@@ -510,14 +542,16 @@ extern "C" {
*/
if (NRF_RADIO->EVENTS_BCMATCH == 1) {
NRF_RESET_EVENT(NRF_RADIO->EVENTS_BCMATCH);
#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
intcntr_bcmatch++;
#endif
// Disable bitcounter
NRF_RADIO->TASKS_BCSTOP = 1;
// In RX mode -> prepare ACK or RX
if (NRF_RADIO->STATE == RADIO_STATE_STATE_Rx) {
// ACK only for node address and unset noack bit
#ifndef MY_NRF5_ESB_REVERSE_ACK
#ifndef MY_NRF5_ESB_REVERSE_ACK_RX
if ((NRF_RADIO->RXMATCH != NRF5_ESB_NODE_ADDR) || (rx_buffer->noack)) {
#else
if ((NRF_RADIO->RXMATCH != NRF5_ESB_NODE_ADDR) || (!rx_buffer->noack)) {
@@ -561,6 +595,9 @@ extern "C" {
*/
if (NRF_RADIO->EVENTS_READY == 1) {
NRF_RESET_EVENT(NRF_RADIO->EVENTS_READY);
#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
intcntr_ready++;
#endif
// Fetch a new buffer
rx_buffer = rx_circular_buffer.getFront();
@@ -591,6 +628,9 @@ extern "C" {
*/
if (NRF_RADIO->EVENTS_END == 1) {
NRF_RESET_EVENT(NRF_RADIO->EVENTS_END);
#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
intcntr_end++;
#endif
// Enable ACK bitcounter for next packet
NRF_RADIO->BCC = NRF5_ESB_BITCOUNTER;
@@ -619,7 +659,7 @@ extern "C" {
// Prepare ACK package
ack_buffer.pid++;
ack_buffer.len=1; // data[0] is set some lines before
#ifndef MY_NRF5_ESB_REVERSE_ACK
#ifndef MY_NRF5_ESB_REVERSE_ACK_TX
ack_buffer.noack = 1;
#else
ack_buffer.noack = 0;
+17 -3
View File
@@ -25,6 +25,11 @@
#include "Radio.h"
#include <Arduino.h>
// Check SoftDevice presence
#if defined(SOFTDEVICE_PRESENT) && !defined(FORCE_RADIO_ESB_WITH_SD)
#error "NRF5 SoftDevice cannot be used with NRF5 Radio."
#endif
// Check maximum messae length
#if MAX_MESSAGE_LENGTH > (32)
#error "Unsupported message length. (MAX_MESSAGE_LENGTH)"
@@ -49,11 +54,14 @@
// auto retry delay in us, don't set this value < 1500us@250kbit
#define NRF5_ESB_ARD (1500)
// auto retry count
#define NRF5_ESB_ARC (15)
// auto retry count with noACK is false
#define NRF5_ESB_ARC_ACK (15)
// auto retry count with noACK is true
#define NRF5_ESB_ARC_NOACK (15)
// How often broadcast messages are send
#define NRF5_ESB_BC (1)
#define NRF5_ESB_BC_ARC (15)
// Node address index
#define NRF5_ESB_NODE_ADDR (0)
@@ -154,4 +162,10 @@ typedef struct nrf5_radio_packet_s {
#endif
} NRF5_ESB_Packet;
#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
static uint32_t intcntr_bcmatch;
static uint32_t intcntr_ready;
static uint32_t intcntr_end;
#endif
#endif // __NRF5_H__
+6
View File
@@ -32,7 +32,13 @@ void nrf5_pinMode(uint32_t ulPin, uint32_t ulMode)
return;
}
#ifdef ARDUINO_ARCH_NRF52
// Arduino: https://github.com/arduino-org/arduino-core-nrf52
ulPin = g_APinDescription[ulPin].ulPin;
#else
// Sandeep Mistry: https://github.com/sandeepmistry/arduino-nRF5
ulPin = g_ADigitalPinMap[ulPin];
#endif
// Set pin mode according to chapter '22.6.3 I/O Pin Configuration'
switch (ulMode) {
+26 -1
View File
@@ -66,6 +66,25 @@ void hwWriteConfig(int adr, uint8_t value)
bool hwInit()
{
// Clock is manged by sleep modes. Radio depends on HFCLK.
// Force to start HFCLK
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
;
// Enable low latency sleep mode
NRF_POWER->TASKS_CONSTLAT = 1;
// Enable cache on >= NRF52
#ifndef NRF51
NRF_NVMC->ICACHECNF = NVMC_ICACHECNF_CACHEEN_Msk;
#endif
// Suspend UART
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_SUSPEND = 1;
#ifdef MY_DISABLED_SERIAL
// Disable UART, when not configured
@@ -471,7 +490,13 @@ uint16_t hwCPUVoltage()
uint16_t hwCPUFrequency()
{
return F_CPU / 100000UL;
#if defined(VARIANT_MCK)
return (VARIANT_MCK) / 100000UL;
#elif defined(F_CPU)
return (F_CPU) / 100000UL;
#else
return 16;
#endif
}
uint16_t hwFreeMem()
+20 -4
View File
@@ -29,12 +29,17 @@
#endif
// Define NRF5_SOFTDEVICE when SoftDevice found
#if defined(S110) || defined(S130) || defined(S132)
#ifndef NRF5_SOFTDEVICE
#define NRF5_SOFTDEVICE
#if defined(S110) || defined(S130) || defined(S132) || defined(S140)
#ifndef SOFTDEVICE_PRESENT
#define SOFTDEVICE_PRESENT
#endif
#endif
// Define ARDUINO_ARCH_NRF5, if not defined
#ifndef ARDUINO_ARCH_NRF5
#define ARDUINO_ARCH_NRF5
#endif
#include "drivers/NRF5/nrf5_wiring_digital.c"
#include "drivers/NRF5/wdt.h"
#include "drivers/NVM/NVRAM.h"
@@ -42,8 +47,19 @@
#include <avr/dtostrf.h>
#include <nrf.h>
// mapping
#ifndef strncpy_P
#define strncpy_P strncpy
#endif
#ifndef snprintf_P
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)
#endif
#ifndef vsnprintf_P
#define vsnprintf_P vsnprintf
#endif
#ifndef printf_P
#define printf_P printf
#endif
#define MIN(a,b) min(a,b)
#define MAX(a,b) max(a,b)
@@ -139,4 +155,4 @@ typedef struct {
#define MY_CRITICAL_SECTION
#endif /* DOXYGEN || CPPCHECK */
#endif // #ifdef ARDUINO_ARCH_NRF5
#endif // #ifndef MyHwNRF5_h
-69
View File
@@ -1,69 +0,0 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of
* the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2017 Sensnology AB
* Full contributor list:
* https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
// Initialize library and handle sketch functions like we want to
extern "C" void __libc_init_array(void);
// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() {}
int main(void)
{
// Suspend UART
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_SUSPEND = 1;
// Clock is manged by sleep modes. Radio depends on HFCLK.
// Force to start HFCLK
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
;
// Enable low latency sleep mode
NRF_POWER->TASKS_CONSTLAT = 1;
// Enable cache on >= NRF52
#ifndef NRF51
NRF_NVMC->ICACHECNF = NVMC_ICACHECNF_CACHEEN_Msk;
#endif
init();
initVariant(); // arduino-nRF5 specific
delay(1);
_begin(); // Startup MySensors library
for (;;) {
_process(); // Process incoming data
if (loop) {
loop(); // Call sketch loop
}
if (serialEventRun) {
serialEventRun();
}
}
return 0;
}