For syntax FRAM

I've recently received some FRAM memory and am trying examples in a few different libraries to try and get my head around how best to use it. One library that I have tried is:

I am a little confused by the syntax in this library for the "for" loops, I have included the full example below but here is a snippet.

  uint8_t ar[100];
  for (int i = 0; i < 100; i++) ar[i] = i;

  start = millis();
  fram.write(1000, ar, 100);
  stop = millis();
  Serial.print("WRITE 100 bytes TIME:\t");
  Serial.print(stop - start);
  Serial.println(" ms");

  for (int i = 0; i < 100; i++) ar[i] = 0;

This doesn't apear to conform with the standard syntax:

for (initialization; condition; increment) {
  // statement(s);
}

There are arguments after the close brackets and also no containing curly brackets. I'm having difficulty understanding the flow of the sketch. Is the whole "for" loop contained in the single line? If so I would expect it to read

for (int i = 0; i < 100; i++) {ar[i] = i;}

If anybody could point me in the direction of an explanation of this variant of the "for " loop I would be very grateful.

The full example is below: (note, I have reassigned the I2C pins)

//
//    FILE: testFRAM.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: test for FRAM library for Arduino
//     URL: https://github.com/RobTillaart/FRAM_I2C


#include "FRAM.h"
#define I2C_SDA 33
#define I2C_SCL 32


FRAM fram;

uint32_t start;
uint32_t stop;


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("FRAM_LIB_VERSION: ");
  Serial.println(FRAM_LIB_VERSION);

  Wire.begin(I2C_SDA, I2C_SCL);

  int rv = fram.begin(0x50);
  if (rv != 0)
  {
    Serial.println(rv);
  }
  else
  {
    testID();
    testFRAMmemory();
    testReadWriteSmall();
    testReadWriteLarge();
    testWriteText();
    testReadText1();
    testReadText2();
  }
  Serial.println("done...");
}


void loop()
{
}


void testID()
{
  Serial.println();
  Serial.println(__FUNCTION__);
  Serial.print("ManufacturerID: ");
  Serial.println(fram.getManufacturerID());
  Serial.print("     ProductID: ");
  Serial.println(fram.getProductID());
  Serial.print("     memory KB: ");
  Serial.println(fram.getSize());

  Serial.println();
}


void testFRAMmemory()
{
  Serial.println();
  Serial.println(__FUNCTION__);
  Serial.println("takes ~32 seconds");

  start = millis();
  uint8_t val = 0x55;
  for (uint16_t addr = 0; addr < 32768; addr++)
  {
    fram.write8(addr, val);
    if (fram.read8(addr) != 0x55)
    {
      Serial.print("FAIL: \t");
      Serial.println(addr);
    }
    if (addr % 1000 == 0)
    {
      Serial.print(".");
    }
  }
  stop = millis();
  Serial.println();
  Serial.print("TIME:\t");
  Serial.print(stop - start);
  Serial.println(" ms");
  Serial.println();
}


void testReadWriteSmall()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  Serial.print("test8:\t");
  uint8_t t8 = 0xFE;
  fram.write8(1000, t8);
  if (fram.read8(1000) != 0xFE)
  {
    Serial.println("failed.");
  }
  else
  {
    Serial.println("ok.");
  }

  Serial.print("test16:\t");
  uint16_t t16 = 0xFADE;
  fram.write16(1000, t16);
  if (fram.read16(1000) != 0xFADE)
  {
    Serial.println("failed.");
  }
  else
  {
    Serial.println("ok.");
  }

  Serial.print("test32:\t");
  uint32_t t32 = 0xFADEFACE;
  fram.write32(1000, t32);
  if (fram.read32(1000) != 0xFADEFACE)
  {
    Serial.println("failed.");
  }
  else
  {
    Serial.println("ok.");
  }
  Serial.println();
}


void testReadWriteLarge()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  uint8_t ar[100];
  for (int i = 0; i < 100; i++) ar[i] = i;

  start = millis();
  fram.write(1000, ar, 100);
  stop = millis();
  Serial.print("WRITE 100 bytes TIME:\t");
  Serial.print(stop - start);
  Serial.println(" ms");

  for (int i = 0; i < 100; i++) ar[i] = 0;

  start = millis();
  fram.read(1000, ar, 100);
  stop = millis();
  Serial.print("READ 100 bytes TIME:\t");
  Serial.print(stop - start);
  Serial.println(" ms");

  for (int i = 0; i < 100; i++)
  {
    if (ar[i] != i)
    {
      Serial.print("FAIL: \t");
      Serial.println(i);
    }
  }
  Serial.println();
}


void testWriteText()
{
  char str[10][20] =
  {
    "Hello world 0",
    "Hello world 1",
    "Hello world 2",
    "Hello world 3",
    "Hello world 4",
    "Hello world 5",
    "Hello world 6",
    "Hello world 7",
    "Hello world 8",
    "Hello world 9",
  };
  Serial.println();
  Serial.println(__FUNCTION__);

  start = millis();
  fram.write(2000, (uint8_t *)str, 200);
  stop = millis();
  Serial.print("WRITE 200 bytes TIME:\t");
  Serial.print(stop - start);
  Serial.println(" ms");
  Serial.println();
}


void testReadText1()
{
  char str[10][20];

  Serial.println();
  Serial.println(__FUNCTION__);

  start = millis();
  fram.read(2000, (uint8_t *)str, 200);
  stop = millis();
  Serial.print("READ 200 bytes TIME:\t");
  Serial.print(stop - start);
  Serial.println(" ms");
  Serial.println();

  for (int i = 0; i < 10; i++)
  {
    Serial.println(str[i]);
  }
  Serial.println();
}


void testReadText2()
{
  char str[20];

  Serial.println();
  Serial.println(__FUNCTION__);

  for (int i = 0; i < 10; i++)
  {
    fram.read(2000 + 20 * i, (uint8_t *)str, 20);
    Serial.println(str);
  }
  Serial.println();
}


//  -- END OF FILE --

No, there is a single program statement after the for loop and that is the only code dependant on the for loop

Here is the code formatted in a different way

uint8_t ar[100];
for (int i = 0; i < 100; i++)
    ar[i] = i;
start = millis();
fram.write(1000, ar, 100);
stop = millis();
Serial.print("WRITE 100 bytes TIME:\t");
Serial.print(stop - start);
Serial.println(" ms");

When there is only a single dependant statement then the curly brackets denoting the dependant code block can be omitted. Personally I prefer to use them to make things clearer

uint8_t ar[100];
for (int i = 0; i < 100; i++)
{
    ar[i] = i;
}
start = millis();
fram.write(1000, ar, 100);
stop = millis();
Serial.print("WRITE 100 bytes TIME:\t");
Serial.print(stop - start);
Serial.println(" ms");

yes

The C/C++ syntax allowed you to omit the curly brackets if the code block contains only one line. This applies not only to for loop, but also to other language constructions - if-else, while...

PS Your question has nothing to do with FRAM memory and its library, this is basic C/C++ syntax, so it would be more correct to change the topic title.

Thanks for that. Is this also the case for other functions such as while or if statements?

I think I'll keep using the brackets because it makes the it clearer for me.

1 Like

Agreed, using a brackets anyway is a good programming practice.

Another confusion that I have with this sketch sre the read and write statements.

for (int i = 0; i < 100; i++) ar[i] = i;

  start = millis();
  fram.write(1000, ar, 100);
  stop = millis();
  Serial.print("WRITE 100 bytes TIME:\t");
  Serial.print(stop - start);
  Serial.println(" ms");

  for (int i = 0; i < 100; i++) ar[i] = 0;

  start = millis();
  fram.read(1000, ar, 100);
  stop = millis();
  Serial.print("READ 100 bytes TIME:\t");
  Serial.print(stop - start);
  Serial.println(" ms");

For the write line fram.write(1000, ar, 100); it appears that 1000 is the address, ar is the array and 100 is the number of bytes allowed.

For the read line fram.read(1000, ar, 100); I dont understand why the ar is used (all as zeros), logically I would have expected to just need the 1000 address and the number of bytes to read.

Any ideas?

If the destination array name was not included in the read function parameters then how would the function know where to store the bytes that are read ?

I think that I understand what you are saying. So is this line there just to clear the array?

Yes. The outcome will be that the array is filled with zeroes

Thanks for the help.

Without the Arduino Forum, I think that I would still be working on making LEDs blink.

You are welcome. Good luck with your project going forward

tl;dr: Learn C.


This is true but misses what is the thing to learn.

This is a statement:

   ar[i] = i;

This is a statement:

{ar[i] = i;}

and this is a statement:

{
  ar[i] = i;
  ar[i] += ar[i - 1];
  mask <<= 1;
}

Never mind if it makes sense or complies or works, I just wanted to make a three statement compound statement.

Then what you learn about the syntax is simple. A for loop controls the execution of one statement.

It is not a matter of allowing or making exceptions or special cases. One statement.

As to whether it is good programming practice to always use braces, no matter how many statements are being embraced, opinions will obvsly vary.

The same discussion is heard around whether to always use parentheses.

I had to actually learn C. I prefer to use at little ink as possible. For my own code, I do no use syntactically unnecessary elements, braces and parentheses for sure among things that can be left out, or jettisoned when found to be unnecessary in code under scrutiny.

When I doubt my own memory about rare or obscure cases like logical and mixed with bitwise or and some comparators and arithmetic, I go to the source and refresh my memory so I get it right.

This may indeed be after using parentheses if I am in a hurry and just can't stop for "learning time".

C is a tiny relatively small language, the BNF syntax chart lays out the entire possibility for a valid C program in a page and a half.

You can know it, and it is only bad educational materials that leave autodidacts with the impression that a for loop has to have a compound statement as its body, even if the compound statement is comprised of one statement.

I don't know if any course in any language in any environment ever starts, or gets around to, exposing students to syntax charts (BNF diagrams).

a7

I'll look for BNF diagrams. It sounds like these may be very useful.

Well I can't find yet a graphic BNF, but here's how a statement is dexcribed in a textual BNF

stmt    :   
        if '(' expr ')' stmt [ else stmt ]
    |   while '(' expr ')' stmt
    |   for '(' [ assg ] ';' [ expr ] ';' [ assg ] ')' stmt
    |   return [ expr ] ';'
    |   assg ';'
    |   id '(' [expr { ',' expr } ] ')' ';'
    |   '{' { stmt } '}'
    |   ';'

There's a set of rules to learn for reading it, but here we see every possible C statement, including, on the last line

;

Yup. you can put stray semicolons all over the place, perfectly good syntactically valid C statements.

Harmlessly? Not always.

Here's one line decoded:

if '(' expr ')' stmt [ else stmt ]

an if statement is "if" followed by a ( parenthesized expression) followed by a statement, with an optional "else" and another statement.

Just noticed do/while isn't in there, or I need to eat.

Maybe it was left out as an exercise for the reader. :expressionless:

a7

Thanks for that. This is the sort of thing I need pasted on the wall above my screen.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.