Main Menu

Atmega328 @8Mhz

Started by ulli, January 04, 2015, 03:18:24 PM

ulli

I really need your support.
I have to Atmega328p devices, each is assembled with a RFM69HW. Both running the same code.
One Atmega is @16Mhz and the other @8Mhz.

I can transmit data from the 16Mhz device to the 8Mhz device. But in the other direction from 8Mhz to 16Mhz it does not work.
Therefore 16Mhz TX definitely works and @8Mhz RX works... :(

Can anybody give me a hint what the problem could be?
I am desperate...

Felix

SPI clock gets divided by 4 in my library. On the 8mhz one it might be too slow even though I would be surprised. But that's where I would look first.

ulli

I also thought about that...
I changed it to the following in the select() function
SPI.setClockDivider(SPI_CLOCK_DIV2);

But it still does not work in the direction of 8MHz -> 16MHz atmega...
I also built up a second hardware....the same issue.....

(By the way, I am using your Node and Gateway Sketch)

please help!

Felix

Do you have a schematic of your 8mhz device?
Other than that ... im out of ideas, I know almost nothing about what you're doing and how you're doing it.
Although it sometimes works, fortunately electronics is not a game of dice or guessing. Time to get the logic analyzer and do some analyzing.

ulli

#4
Enclosed the schematic.
The Quarz and the Capacitors 22pF are not connected.

Thanks for your support!

The strange thing is that it works just fine in receiving messages. It just does not work for transmitting messages.... :(

TomWS

Quote from: ulli on January 04, 2015, 03:18:24 PM
I really need your support.
I have to Atmega328p devices, each is assembled with a RFM69HW. Both running the same code.
One Atmega is @16Mhz and the other @8Mhz.

I can transmit data from the 16Mhz device to the 8Mhz device. But in the other direction from 8Mhz to 16Mhz it does not work.
Therefore 16Mhz TX definitely works and @8Mhz RX works... :(

Can anybody give me a hint what the problem could be?
I am desperate...
What are your fuses set to?  I am running just fine with RFM69HW & internal 8MHz clock.  So it's not the frequency that's the issue.

Here is my avrdude command to set the fuses:
avrdude -b 19200 -c usbtiny -p atmega328p -u -v -U lfuse:w:0xE2:m -U hfuse:w:0xDA:m -U efuse:w:0x07:m


Check what the CPU THINKS the frequency is with:
Serial.println(F_CPU);


Tom

ulli

#6
Hello Tom and Felix,

I spend some more hours on my issue and found the real issue.
Tom you are right, it is not an issue of frequency.

The strange thing is, I have a very low output power on the 8MHz device. (Distance between two devices is about 2 meters)
I configured the RFM69 on the 8MHz device to HighPower mode. This let the 16MHz device receive the messages.....  :-[

Do you know what can effect the output power in that way?
In the following my RFM69 configuration....Did I do something wrong?
  const byte RFM69_CONFIG_MyProtocol[][2] =
  {
  	//* 0x00 */ Fifo
		/* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY }, //Sequencer on | Standby Mode
	  /* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, //no shaping
	  /* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_17240}, //LaCrosse 17.24 kbps
    /* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_17240},
    
    /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_90000}, //default:5khz, (FDEV + BitRate/2 <= 500Khz) /FDEV = frequency deviation
    /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_90000}, // rfm12 90kHz Deviation -> (90kHz + 17,24kbps/2) <= 500kHz i.O.
    
    /* 0x07 */ { REG_FRFMSB, 0xD9 }, //FRF_MSB }, //868,3 MHz
    /* 0x08 */ { REG_FRFMID, 0x13 }, //FRF_MID },
    /* 0x09 */ { REG_FRFLSB, 0x33 }, //FRF_LSB },    
        
    //* 0x0A */ calibration of the RC oscillator, trigger and read
		/* 0x0B */ { REG_AFCCTRL, RF_AFCCTL_LOWBETA_OFF }, // Improved AFC // needed when index<2  modulation index 0.5 <= beta = 2*Fdev/BitRate <=10 -> Standard AFC routine
		//* 0x0C */ unused
		//* 0x0D */ { REG_LISTEN1, RF_LISTEN1_CRITERIA_RSSI }, // match >minRSSI & AddressSync
		//* 0x0D - 0x10 */ RegListen deaktivated
		
		/* Transmitter Registers */
		/* 0x11 */
		/* 0x13 */
		/* 0x12 */
		/* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, //over current protection (default is 95mA)
		
		/* Receiver Registers */
		//* 0x14 - 0x17 */ unused
		/* 0x18 */ { REG_LNA,  RF_LNA_ZIN_50 | RF_LNA_GAINSELECT_AUTO }, // 200Ohm default / rfm12 MAX-LNA Gain setting
		/* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_1 }, //(BitRate < 2 * RxBw) -> (17,24kbs < 2* rfm12 166,7 kHz
		//* 0x1A */ RegAfcBw
		//* 0x1B */ OOK Data Mode
		//* 0x1C */ OOK Data Mode
		//* 0x1D */ OOK Data Mode		
		/* 0x1E */ { REG_AFCFEI, RF_AFCFEI_AFCAUTO_ON | RF_AFCFEI_AFC_CLEAR | RF_AFCFEI_AFCAUTOCLEAR_ON | RF_AFCFEI_FEI_START },
		//* 0x1E - 0x22 */ Afc Setting
		//* 0x23 0x24 */ RSSI 
		
		/* IRQ and Pin Mapping */
		/* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, //DIO0 is the only IRQ we're using
		//* 0x26 */ ClockOut
		//* 0x27 */ RegIrqFlags1 read only
		/* 0x28 */ { REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN }, // Writing to this bit ensures the FIFO & status flags are reset
    /* 0x29 */ { REG_RSSITHRESH, 0xE4 /*MAX*/ }, //(97*2) rfm -91dBm //must be set to dBm = (-Sensitivity / 2) - default is 0xE4=228 so -114dBm
		//* 0x2A-0x2B */ Timeout after switching to Rx mode if Rssi interrupt doesn't occur
		
		/* Packet Engine Registers */
		/* 0x2C */ { REG_PREAMBLEMSB, RF_PREAMBLESIZE_MSB_VALUE },
		/* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE }, // default 3 preamble bytes 0xAAAAAA
		/* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 },
    /* 0x2F */ { REG_SYNCVALUE1, 0x2D },      //attempt to make this compatible with sync1 byte of RFM12B lib
    /* 0x30 */ { REG_SYNCVALUE2, 0xe4 }, //NETWORK ID LaCrosse 0xD4
    //* 0x31 - 0x36 */ possible SyncValues
    /* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF |
    						 RF_PACKET1_CRC_OFF | RF_PACKET1_CRCAUTOCLEAR_OFF | 
    						 RF_PACKET1_ADRSFILTERING_NODEBROADCAST },
    /* 0x38 */ { REG_PAYLOADLENGTH, RFM69_PROTOCOL_MYPROTOCOL_PAYLOADLENGTH }, //max0x40 in variable length mode: the max frame size, not used in TX
    /* 0x39 */ { REG_NODEADRS, DEVICE_ID }, //using address filtering  
  	/* 0x3A */ { REG_BROADCASTADRS, DEVICE_ID_BROADCAST }, //0 is the broadcast address
  	//* 0x3B */ {  REG_AUTOMODES, 0 }, // Automatic Modes, currently not needed
  	/* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, //TX on FIFO not empty
    /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, //RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
    //* 0x3E - 0x4D */ AesKey
    
    /* Temperature Sensor Registers */
    /* 0x4E - 0x4F */
    
    /* Test Registers */
    /* 0x58 - 0x71 */
    /* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode, recommended default for AfcLowBetaOn=0   
    {255, 0}
  };

TomWS

ulli,
I can't take the time look at the configuration table you've included (for several reasons), but I will say that I do not believe that you need to change these at all.  IMO, the RFM69 method interface is the correct way to configure the radio to meet your needs.  Playing with the raw configuration values is too fragile and can easily break your device (not physically, but it won't work the way you expect).

If you have an RFM69HW you MUST use the high power settings (via radio.setHighPower(true)) otherwise the HW power amplifiers are turned off and you will not get any signal generated.  Once you have setHighPower(true) then setPowerLevel(0) to consume the least amount of power on the RFM69HW.  You should have enough RF power to communicate within one or two rooms in your house with this setting.

Tom

ulli

Hi Tom,

sounds like a noob failure :/
I did
setHighPower(true);
setPowerLevel(0);

and it works! Thanks a lot!

Still the wired thing is that one device worked without setHighPower and the other not....

TomWS

Quote from: ulli on January 08, 2015, 10:25:24 AM
<...snip>
Still the wired thing is that one device worked without setHighPower and the other not....
EXACTLY the same SW loaded on both???
If so, I can't explain.  If not, use diff...

Tom

ulli

I have a question regarding the power options in the RFM69 library. I currently do not understand how to use the available PowerLevel functions right.
I understood I always have to execute setHighPower.

In the case I have a RFM69HW the _powerLevel will not be set up by the function "setHighPower" because the variable will only be considered for RFM69W.
Shouldn`t it be "writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON | _powerLevel);"?
void RFM69::setHighPower(bool onOff) {
  _isRFM69HW = onOff;
  writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON);
  if (_isRFM69HW) // turning ON
    writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages
  else
    writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); // enable P0 only
}


Can the power be adjusted for the RFM69HW and RFM69W with the following function?
// set output power: 0=min, 31=max
// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver
void RFM69::setPowerLevel(byte powerLevel)
{
  _powerLevel = powerLevel;
  writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | (_powerLevel > 31 ? 31 : _powerLevel));
}


Is the setHighPowerRegs function just for the library internal use or is it public and have to be used for output power adjustments?
void RFM69::setHighPowerRegs(bool onOff) {
  writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55);
  writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70);
}


I already tried fot the initialization the following for the RFM69HW
setHighPower(true);
setPowerLevel(0);

But when I adjust the "setPowerLevel" from 0-31 I do not see any changes in the RSSI value of the receiver....

Thanks a lot!

TomWS

Quote from: ulli on January 09, 2015, 03:14:18 AM
I have a question regarding the power options in the RFM69 library. I currently do not understand how to use the available PowerLevel functions right.
I understood I always have to execute setHighPower.

In the case I have a RFM69HW the _powerLevel will not be set up by the function "setHighPower" because the variable will only be considered for RFM69W.
Shouldn`t it be "writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON | _powerLevel);"?
void RFM69::setHighPower(bool onOff) {
  _isRFM69HW = onOff;
  writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON);
  if (_isRFM69HW) // turning ON
    writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages
  else
    writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); // enable P0 only
}

This function needs to be called first for two reasons.  First, it does enable PA1 & PA2, but secondly, it sets the _isRFM69HW which is used elsewhere in the library.

Quote from: ulli on January 09, 2015, 03:14:18 AM
Can the power be adjusted for the RFM69HW and RFM69W with the following function?
// set output power: 0=min, 31=max
// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver
void RFM69::setPowerLevel(byte powerLevel)
{
  _powerLevel = powerLevel;
  writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | (_powerLevel > 31 ? 31 : _powerLevel));
}

Yes, the
(readReg(REG_PALEVEL) & 0xE0)
section masks everything but the PA control bits so they can be combined with the powerlevel value.
Quote from: ulli on January 09, 2015, 03:14:18 AM
Is the setHighPowerRegs function just for the library internal use or is it public and have to be used for output power adjustments?
void RFM69::setHighPowerRegs(bool onOff) {
  writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55);
  writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70);
}

This function is used internally as the radio switches between TX & RX since the high power regs can not be left on while in RX mode.
Quote from: ulli on January 09, 2015, 03:14:18 AM
I already tried fot the initialization the following for the RFM69HW
setHighPower(true);
setPowerLevel(0);

But when I adjust the "setPowerLevel" from 0-31 I do not see any changes in the RSSI value of the receiver....

Thanks a lot!
How close are your radios (ie, what is the RSSI value you're getting from the radio you're trying to control)?  Also, the receiver has its own AGC control that you'll need to disable if you want an accurate measure of the setPowerLevel effect.

You could add this method to the RFM69 code to control the AGC (read the datasheet for the various values):
byte RFM69::setLNA(byte newReg) {  // TWS: New method used to disable LNA AGC for testing purposes
	byte oldReg;
	
	oldReg = readReg(REG_LNA);
	
	writeReg(REG_LNA, ((newReg & 7) | (oldReg & ~7)));   // just control the LNA Gain bits for now
	
	return oldReg;  // return the original value in case we need to restore it later
}


Note that the AGC will need to be disabled in the RECEIVING radio, not the device under test.

Tom

ulli

Thanks for your great support.
All right, for the RFM69HW:
I understood "setHighPower" configures the max output power at the beginning.
But the output power can be still changed with "setPowerLevel".

Due to the active AFC the sensitivity will be changed by the receiver therefore I can not just compare the RSSI values after a "setPowerLevel" change at the transmitter, right?
I configured the LNA and ADC like
/* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, //over current protection (default is 95mA)
/* 0x0B */ { REG_AFCCTRL, RF_AFCCTL_LOWBETA_OFF },
/* 0x18 */ { REG_LNA,  RF_LNA_ZIN_50 | RF_LNA_GAINSELECT_AUTO },
/* 0x1E */ { REG_AFCFEI, RF_AFCFEI_AFCAUTO_ON | RF_AFCFEI_AFC_CLEAR | RF_AFCFEI_AFCAUTOCLEAR_ON | RF_AFCFEI_FEI_START },


Currently I try to reduce the power consumption as much as possible...
I also found a source code from you Tom and I am thinking to include your function which is the following to reduce the power consumption more..
// set output power: 0=min, 31=max (for RFM69W or RFM69CW), 0-31 or 32->51 for RFM69HW (see below)
// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver
void RFM69::setPowerLevel(byte powerLevel)
{
	// TWS Update: allow power level selections above 31.  Select appropriate PA based on the value
		
	_transmitLevel = powerLevel;		// save this for later in case we do auto power control.
  _powerBoost = (powerLevel >= 50);
  
	if (!_isRFM69HW || powerLevel < 32) {			// use original code without change
    _powerLevel = powerLevel;
    writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | (_powerLevel > 31 ? 31 : _powerLevel));
  } else {
  	// the allowable range of power level value, if >31 is: 32 -> 51, where...
  	// 32->47 use PA2 only and sets powerLevel register 0-15,
  	// 48->49 uses both PAs, and sets powerLevel register 14-15,
  	// 50->51 uses both PAs, sets powerBoost, and sets powerLevel register 14-15.
  	if (powerLevel < 48) {
      _powerLevel = powerLevel & 0x0f;	// just use 4 lower bits when in high power mode
      _PA_Reg = 0x20;
    } else {
	    _PA_Reg = 0x60;
    	if (powerLevel < 50) {
	    	_powerLevel = powerLevel - 34;  // leaves 14-15
	    } else {
	    	if (powerLevel > 51) 
	    		powerLevel = 51;  // saturate
	      _powerLevel = powerLevel - 36;  // leaves 14-15
	    }
	  }
	  writeReg(REG_OCP, (_PA_Reg==0x60) ? RF_OCP_OFF : RF_OCP_ON);
    writeReg(REG_PALEVEL, _powerLevel | _PA_Reg);
  }
}

void RFM69::setHighPower(bool onOff, byte PA_ctl) {
  _isRFM69HW = onOff;
  	
  writeReg(REG_OCP, (_isRFM69HW && PA_ctl==0x60) ? RF_OCP_OFF : RF_OCP_ON);
  if (_isRFM69HW) { //turning ON based on module type 
  	_powerLevel = readReg(REG_PALEVEL) & 0x1F; // make sure internal value matches reg
  	_powerBoost = (PA_ctl == 0x60);
  	_PA_Reg = PA_ctl;
    writeReg(REG_PALEVEL, _powerLevel | PA_ctl ); //TWS: enable selected P1 & P2 amplifier stages
  }
  else {
    _PA_Reg = RF_PALEVEL_PA0_ON;				// TWS: save to reflect register value
    writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); //enable P0 only
  }
}


Is my understanding and assumption right?

Thanks a lot!

TomWS

Ulli,
as I said before, changing the initialization table is not the right way to configure your radios.  The RFM69 library has a rich set of functions for configuring the radio.  Use those and you will get support from this forum, use the tables and no one will know what's been changed.

Also, disabling the AGC should only be used as a TEMPORARY means to test your devices.  Your radios will not perform well if you permanently disable AGC.

Regarding the function to set power, that function was part of a complete library with several changes.  I can't comment on how well it will work if you simply copy one function.

Tom


ulli

#14
Of course your functions will not work alone....I included the needed code lines in my code to use the setPowerLevel properly....looks good.
I also checked the additional settings I have in the initialization table and made it aligned with moteinos...I could not discover any signal TX or RX issues. Therefore I use the moteinos...

I just have one remark regarding the AFC. Looks like your AFC is turned off. Because your initialization table does not set the REG_AFCFEI.
Per default the Bit AfcAutoOn is set to 0. Therefore the AFC just running when you manually set the AfcStart flag....

I have after the initialization a Calibration function which looks like that
void myRFM69::rcCalibration()
{
  writeReg(REG_OSC1, RF_OSC1_RCCAL_START);
  while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00);
  
  writeReg(REG_AFCFEI, RF_AFCFEI_AFC_CLEAR | RF_AFCFEI_AFC_START | RF_AFCFEI_AFCAUTO_OFF | RF_AFCFEI_AFCAUTOCLEAR_OFF /*default*/);
  while ((readReg(REG_AFCFEI) & RF_AFCFEI_AFC_DONE) == 0x00);
  
  //RF_AFCFEI_AFCAUTO_ON -> 1 → AFC is performed each time Rx mode is entered
  writeReg(REG_AFCFEI, RF_AFCFEI_AFCAUTO_ON | RF_AFCFEI_AFCAUTOCLEAR_OFF /*default*/);
}


What do you think?