Bad Moteino? R5 seems to "blink out" over time...

Started by G550_Pilot, March 30, 2018, 01:12:47 PM

G550_Pilot

Quote from: perky on October 17, 2018, 09:11:08 PM
I don't personally like doing this though, I think it's better to have a static volatile flag that simply gets set by the 1 second timer interrupt instead of running XMIT(), and in the main loop look for the flag being set. When you see it, clear the flag and run XMIT() as a normal function. This minimises the time in the ISR where interrupts are disabled by hardware to just the flag setting part, and millis() will update as it should.

Mark - Thanks for the good info, I will try and poke around altering the code to see if I can make this work!

- Richard

ChemE

#46
Quote from: G550_Pilot on October 18, 2018, 11:25:13 AM
Are you using a different radio library to get those transmit times down?

Yes though not a polished or supported one.  It is my own homebrew code that I've developed to interact with the radio. 

Save this in the project as RFM69CW.h
#include "Arduino.h"
#define         OPT_FLAG                                //__attribute__((always_inline))  // Comment this definition out to optimize for size
// ============================== User Definitions ============================== 
#define         NETWORKID                               100    //the same on all nodes that talk to each other - 170 is 10101010 DC free value
#define         RECEIVER                                1      // ID of the gateway that all nodes report back to
#define         NODEID                                  2      // ID of this Node
#define 	SS_PIN			                PB2    // Slave select pin

// ============================== SPI Definitions ============================== 
#define		SELECT			                noInterrupts(); PORTB &= ~(1<<SS_PIN)
#define		UNSELECT		                SS_WRITE_HIGH; interrupts()
#define   	SS_WRITE_HIGH     	                PORTB |= 1<<SS_PIN
#define         WAIT_WHILE_SPI_BUSY                     asm volatile("nop"); while (!(SPSR & 1<<SPIF))

// ============================== RFM69CW Definitions ============================== 
#define         SLEEP_MODE                              B00000000
#define         AUTO_TRANSMITTER                        B01011011    // Enter = FIFO level; Exit = Packet Sent; Intermediate Mode = TX
#define         CHANGE_OP_MODE(mode)                    writeReg(REG_OPMODE, mode)
#define         SET_POWER_LEVEL(level)                  writeReg(REG_PALEVEL, 0x80 | (level & 0x0F));  // Only works for the RFM69CW not the RFM69HCW
#define         REG_FIFO                                0x00
#define         REG_OPMODE                              0x01
#define         REG_BITRATEMSB                          0x03
#define         REG_BITRATELSB                          0x04
#define         REG_FDEVMSB                             0x05
#define         REG_FDEVLSB                             0x06
#define         REG_PALEVEL                             0x11
#define         REG_RXBW                                0x19
#define         REG_RSSITHRESH                          0x29
#define         REG_SYNCCONFIG                          0x2E
#define         REG_SYNCVALUE1                          0x2F
#define         REG_SYNCVALUE2                          0x30
#define         REG_PACKETCONFIG1                       0x37
#define         REG_AUTOMODES                           0x3B
#define         REG_PACKETCONFIG2                       0x3D
#define         RF_BITRATEMSB_300000                    0x00    // Begin 300 kbps auto Tx settings
#define         RF_BITRATELSB_300000                    0x6B
#define         RF_FDEVMSB_300000                       0x13
#define         RF_FDEVLSB_300000                       0x33
#define         RF_RXBW_DCCFREQ_111                     0xE0
#define         RF_RXBW_MANT_16                         0x00
#define         RF_RXBW_EXP_0                           0x00
#define         RF_SYNC_ON                              0x80
#define         RF_SYNC_FIFOFILL_AUTO                   0x00
#define         RF_SYNC_SIZE_2                          0x08
#define         RF_SYNC_TOL_0                           0x00
#define         RF_PACKET1_FORMAT_VARIABLE              0x80
#define         RF_PACKET1_DCFREE_OFF                   0x00
#define         RF_PACKET1_CRC_OFF                      0x00
#define         RF_PACKET1_CRCAUTOCLEAR_OFF             0x08
#define         RF_PACKET1_ADRSFILTERING_OFF            0x00
#define         RF_PACKET2_RXRESTARTDELAY_2BITS         0x10
#define         RF_PACKET2_AUTORXRESTART_ON             0x02
#define         RF_PACKET2_AES_OFF                      0x00    // End 300 kbps auto Tx settings

static inline void SPI_INIT(void) {  // Level 0 code - initialize the SPI bus at fosc/2 (8MHz)
  PORTB |= 1<<SS_PIN;
  DDRB |= _BV(SS_PIN);
  SPCR |= _BV(MSTR) | _BV(SPE);
  SPSR |= (1<<SPI2X);    // Set the SPI bus speed to Fosc/2 = 8MHz at full speed
  
  // No clue why this is neccessary as opposed to DDRB |= 1<<SCK | 1<<MOSI
  volatile uint8_t *reg;
  reg = &DDRB;	
  *reg |= 0x28;  // Bit mask of SCK and MOSI
  //DDRB = 0x28;
}

OPT_FLAG uint8_t SPI_XFER(uint8_t data) {    // Level 0 code - move data over the SPI bus
  SPDR = data;
  WAIT_WHILE_SPI_BUSY;
  return SPDR;
}

OPT_FLAG uint8_t readReg(uint8_t addr) {    // Level 1 code - interact with the radio's registers
  SELECT;
  SPDR = ( addr & 0x7F );
  WAIT_WHILE_SPI_BUSY;
  SPDR = ( 0 );
  WAIT_WHILE_SPI_BUSY;
  UNSELECT;
  return SPDR;
}

OPT_FLAG void writeReg(uint8_t addr, uint8_t value) {  // Level 1 code - interact with the radio's registers
  SELECT;
  SPDR = ( addr | 0x80 );
  WAIT_WHILE_SPI_BUSY;
  SPDR = ( value );
  WAIT_WHILE_SPI_BUSY;
  UNSELECT;
}

static inline void SendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize) {  // Level 2 code - do useful work
  SELECT;
  SPI_XFER(REG_FIFO | 0x80);   // write to FIFO using SPI burst mode
  SPI_XFER(bufferSize + 3);    // LEN byte
  SPI_XFER(toAddress);         // 1st byte
  SPI_XFER(NODEID);            // 2nd byte
  SPI_XFER(0x00);              // 3rd byte
  for (uint8_t i = 0; i < bufferSize; i++) SPI_XFER(((uint8_t*) buffer)[i]);  // Write 6 more bytes to the FIFO
  UNSELECT;
}

static inline void RadioInit(void) {
    SPI_INIT();
    CHANGE_OP_MODE(SLEEP_MODE);  // Put the radio to sleep ASAP to save power
    writeReg( REG_BITRATEMSB, RF_BITRATEMSB_300000 );	// 0x03
    writeReg( REG_BITRATELSB, RF_BITRATELSB_300000 );	// 0x04
    writeReg( REG_FDEVMSB, RF_FDEVMSB_300000 );	// 0x05
    writeReg( REG_FDEVLSB, RF_FDEVLSB_300000 );	// 0x06
    writeReg( REG_RXBW, RF_RXBW_DCCFREQ_111 | RF_RXBW_MANT_16 | RF_RXBW_EXP_0 );	// 0x19
    writeReg( REG_RSSITHRESH, 220 );	// 0x29
    writeReg( REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 );	// 0x2E - 2 sync bytes
    writeReg( REG_SYNCVALUE1, 0xAA );	// 0x2F
    writeReg( REG_SYNCVALUE2, NETWORKID );	// 0x30
    writeReg( REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_OFF | RF_PACKET1_CRCAUTOCLEAR_OFF | RF_PACKET1_ADRSFILTERING_OFF );  // 0x37	// 0x37
    writeReg( REG_AUTOMODES, AUTO_TRANSMITTER );  // 0x3B - Put the radio in automatic mode
    writeReg( REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF );	// 0x3D
    SET_POWER_LEVEL(0);
}


And then call it like this
uint8_t data[8];  //16-bit temp, 16-bit RH, 16-bit Vcc, 16-bit packet counter
RadioInit();  // Configure the radio while it is asleep
...populate the bytes of data...
SendFrame(RECEIVER, data, 8);                   // Send the data


Further reading on my quest to speed up the code can be found here: https://lowpowerlab.com/forum/low-power-techniques/speeding-up-the-rfm69-library/