Serial output is... interesting.

Hi guys,

working with some nRF24L01+ 2.4GHz RF modules and have been writing my own library for them, based on the mirf library.
I seem to be able to get all functionality of the modules working perfectly fine, the issue is in a function I am writing.

void Nrf24l::printAllRegisters()
{
	Serial.print("CONFIG: ");
	printRegVal(CONFIG);
	Serial.print("EN_AA: ");
	printRegVal(EN_AA);
	Serial.print("EN_RXADDR: ");
	printRegVal(EN_RXADDR);
	Serial.print("SETUP_AW: ");
	printRegVal(SETUP_AW);
	Serial.print("SETUP_RETR: ");
	printRegVal(SETUP_RETR);
	Serial.print("RF_CH: ");
	printRegVal(RF_CH);
	Serial.print("RF_SETUP: ");
	printRegVal(RF_SETUP);
	Serial.print("STATUS: ");
	printRegVal(STATUS);
	Serial.print("OBSERVE_TX: ");
	printRegVal(OBSERVE_TX);
	Serial.print("CD: ");
	printRegVal(CD);
	Serial.print("RX_ADDR_P0: ");
	printRegVal(RX_ADDR_P0);
	Serial.print("RX_ADDR_P1: ");
	printRegVal(RX_ADDR_P1);
	Serial.print("RX_ADDR_P2: ");
	printRegVal(RX_ADDR_P2);
	Serial.print("RX_ADDR_P3: ");
	printRegVal(RX_ADDR_P3);
	Serial.print("RX_ADDR_P4: ");
	printRegVal(RX_ADDR_P4);
	Serial.print("RX_ADDR_P5: ");
	printRegVal(RX_ADDR_P5);
	Serial.print("TX_ADDR: ");
	printRegVal(TX_ADDR);
	Serial.print("RX_PW_P0: ");
	printRegVal(RX_PW_P0);
	Serial.print("FIFO_STATUS: ");
	printRegVal(FIFO_STATUS);
}
void Nrf24l::printRegVal(uint8_t regName)
{
	Serial.println(getRegister(regName), BIN);
}
uint8_t Nrf24l::getRegister(uint8_t reg)
{
	uint8_t regVal;
	readRegister(reg, &regVal, 1);
	return regVal;
}
void Nrf24l::readRegister(uint8_t reg, uint8_t * value, uint8_t len)
{
	csnLow();
	spi->transfer(R_REGISTER | (REGISTER_MASK & reg));
	transferSync(value, value, len);
	csnHi();
}

This function prints a large amount of data (the values of all the registers), via serial. It obtains the values perfectly fine when the function is used on it's own.

CONFIG: 1000
EN_AA: 111111
EN_RXADDR: 11
SETUP_AW: 11
SETUP_RETR: 11
RF_CH: 0
RF_SETUP: 100110
STATUS: 1110
OBSERVE_TX: 0
CD: 0
RX_ADDR_P0: 1110011
RX_ADDR_P1: 11000010
RX_ADDR_P2: 11000011
RX_ADDR_P3: 11000100
RX_ADDR_P4: 11000101
RX_ADDR_P5: 11000110
TX_ADDR: 11100111
RX_PW_P0: 10000
FIFO_STATUS: 10001

However, when I integrate that with a sketch I am writing (which scans RF channels using the modules CD register), I get nonsense being sent. For some reason however, I am unable to copy and paste more than a certain amount of text from the serial monitor, so see below a screenshot.

The sketch that generates this:

void setup()
{
  rf24.spi = &MirfHardwareSpi;
  rf24.init();
  rf24.turnAcksOn();
  rf24.setChannel(0);
  rf24.setPayload(16);
  rf24.setDataRate(2);
  rf24.setRecvAddr(0, (byte *) "serv1");
  
  Serial.begin(115200); 

  rf24.printAllRegisters();
}

void loop()
{
  int count[5][128];
  for(int i=0; i<5; i++)
    for(int j=0; j<128; j++)
      count[i][j] = 0;
  
  Serial.println("Beginning scan...");  
  for(int runNo=0; runNo<5; runNo++)
  {
    for(int channel=0; channel<128; channel++)
    {
      rf24.setChannel(channel);
      for(int testNo=0; testNo<5000; testNo++)
      {
        count[runNo][channel] += rf24.getRegister(CD);
      }  
	  Serial.print(".");
    }
	Serial.print("Run ");
	Serial.print(runNo);
	Serial.println(" Complete.");
  }
  
  Serial.println("Analysing results...");
  int average[128];
  for(int i=0; i<128; i++)
    average[i] = 0;
  for(int channel=0; channel<128; channel++)
  {
    for(int runNo=0; runNo<5; runNo++)
      average[channel] += count[runNo][channel];
    //average[i] /= 5;
  }

  //int average[128];
  
  Serial.println("Finished analysing. Printing results...");
  for(int channel=0; channel<128; channel++)
  {
    Serial.print("Channel: ");
    Serial.print(channel);
    Serial.print(" hits: ");
    Serial.println(average[channel]);
  }
}

The register data function is only called once, so immediately there's an issue there as it's attempting to print it again. I wondered if I was overloading the transmission buffer perhaps?
I've attempted to insert delays at various points with no benefit.
In addition, I've attempted to locate the section of code causing the issue. Commenting out lines from the bottom of the code traces it back to the final paragraph (which prints the values of average), however, when compiled with all other sections commented out (and a variable array for average put in), it functions as expected.

Anyone able to offer advise?

Regards

int count[5][128];

1280 bytes of RAM, plus all those strings?

Start with Serial.println(F("Finished analysing. Printing results...")); etc

Hi, thanks for the reply. I hadn't even considered the RAM usage.

Dropping the F in has cleaned it up a lot, it's no longer dumping out characters I didn't expect. However, it is repeatably reprinting the results from the printAllRegisters() function, as opposed to the '.' that I expect.

What exactly does the F do?

F keeps constant strings in flash memory, so they don't gobble up RAM.

Can you repost your code?

Of course:

void setup()
{
  rf24.spi = &MirfHardwareSpi;
  rf24.init();
  rf24.turnAcksOn();
  rf24.setChannel(0);
  rf24.setPayload(16);
  rf24.setDataRate(2);
  rf24.setRecvAddr(0, (byte *) "serv1");
  
  Serial.begin(115200); 

  rf24.printAllRegisters();
}

void loop()
{
  int count[5][128];
  for(int i=0; i<5; i++)
    for(int j=0; j<128; j++)
      count[i][j] = 0;
  
  Serial.println(F("Beginning scan..."));  
  for(int runNo=0; runNo<5; runNo++)
  {
    for(int channel=0; channel<128; channel++)
    {
      rf24.setChannel(channel);
      for(int testNo=0; testNo<5000; testNo++)
      {
        count[runNo][channel] += rf24.getRegister(CD);
      }  
	  Serial.print(F("."));
    }
	Serial.print(F("Run "));
	Serial.print(runNo);
	Serial.println(F(" Complete."));
  }
  
  Serial.println(F("Analysing results..."));
  int average[128];
  for(int i=0; i<128; i++)
    average[i] = 0;
  for(int channel=0; channel<128; channel++)
  {
    for(int runNo=0; runNo<5; runNo++)
      average[channel] += count[runNo][channel];
    //average[i] /= 5;			//Uncomment to actually calculate average instead of summing.
  }
  
  Serial.println(F("Finished analysing. Printing results..."));
  for(int channel=0; channel<128; channel++)
  {
    Serial.print(F("Channel: "));
    Serial.print(channel);
    Serial.print(F(" hits: "));
    Serial.println(average[channel]);
  }
}

The only issue now, is that it is printing the results of the function instead of "Run Complete."

I can of course re-order my code in order that I don't require the use of all of that memory in order to store the data (can obviously calculate sums and/or averages on-the-fly) but am curious now if there's any other ways of saving RAM.

Instead of

void loop()
{
  int count[5][128];
  for(int i=0; i<5; i++)
    for(int j=0; j<128; j++)
      count[i][j] = 0;

, I'd be more inclined to

  int count[5][128];
void loop()
{
  memset ((void*)count, 0, 5 * 128 * sizeof (count[0][0]));

keeping that big array off the stack.

That's nice. Hadn't seen that function before.

Many thanks. I will go ahead and re-write my code such that the sum is calculated on the fly. (256 bytes RAM then, as opposed to 1280, I believe).

I missed this earlier:

for(int testNo=0; testNo<5000; testNo++)
      {
        count[runNo][channel] += rf24.getRegister(CD);

An "int" can only hold up to 32767 - if those 5000 samples average greater than 6, you're going to overflow.

The register is simply either set or cleared, depending on if there is network traffic. Bits 1-7 in the register are always zero. =)