When 30 is an odd n...

# When 30 is an odd number???

Page 2 / 2
(@pugwash)
Prominent Member
Joined: 9 months ago
Posts: 880
2020-02-09 10:26 am

@dale

Well, I feel like I have been holding a carrot to the wrong end of a horse and wondering why it wasn't eating!! All the data was in the 32 to 63 registers where it should be, it was just not being read into the mByte[] array.

After dispensing with all your ornamental code in the sketch above (woods and trees), I figured that you had already implemented what I had been mulling over in my scatterbrain. I had been thinking also about reducing the data chunks to 16 bytes to eliminate the 32(30) problem. This may be required if using the block write function(2) from the website,

Anyway here is how I have implemented your idea in my code:

```// Include the I2C Wire Library
#include "Wire.h"

#define i2c_eeprom 0x50

unsigned char dataArray[64];
unsigned char tempArray[16];

void setup() {

Serial.begin(9600);
Wire.begin();
randomSeed(65);

}

void loop() {

//create an array of random numbers length 64
for(int i = 0; i < 64; i++){
dataArray[i] = random(255);
}

// write the data in 16 byte chunks into the EEPROM registers
for(int j = 0; j < 64; j += 16){
for(int i = 0; i < 16; i++){
tempArray[i] = dataArray[j + i];
}
writeEEPROM(i2c_eeprom, j, tempArray);
}

// show data stored in the dataArray[]
Serial.println("\n\ndata array");
for(int i = 0; i < 64; i++){
Serial.println(byte(dataArray[i]));
}
Serial.println("array print complete");

delay(5);

// get the first 32 bytes of the mByte array*********

Wire.beginTransmission (i2c_eeprom);
// Set device to start read reg 0
Wire.endTransmission ();

int idx = 0;

// read the bytes into an array
while(Wire.available()) {

mByte[idx] = Wire.read(); // read each byte from the register and store in the array
idx++;
}

// get the second 32 bytes of the mByte array*********

Wire.beginTransmission (i2c_eeprom);
// Set device to start read reg 0
Wire.endTransmission ();

idx = 32;

// read the bytes into an array
while(Wire.available()) {

mByte[idx] = Wire.read(); // read each byte from the register and store in the array
idx++;
}

// print to monitor the contents of mByte[] i.e. first 64 registers

Serial.println("\nValues returned from EEPROM");
Serial.println("Register , Value\n");

for (int i = 0; i < 64; i++){
Serial.print(i);
Serial.print(" , ");
Serial.println(mByte[i]);

}

Serial.println();
Serial.println("Done");
while(1);
}

//write up to 64 bytes of data

{
// Write a string of chars to eeprom
unsigned char i = 0;

do{
Wire.write((byte) data[i]);
i++;
} while(data[i]);
Wire.endTransmission();

delay(6);  // needs 5ms for page write
}```

It only remains to put the "read and fill array" code into a separate function outside the main loop(), to handle huge blocks of data.

SteveC - Topple Rudd Poltman

(@pugwash)
Prominent Member
Joined: 9 months ago
Posts: 880
2020-02-09 1:59 pm

@dale

This looks like the final version for my boilerplate library!

SteveC - Topple Rudd Poltman

(@dale)
Trusted Member
Joined: 8 months ago
Posts: 78
2020-02-14 10:10 pm

Hey @pugwash. You've inspired me to give the problem a try.  Also, I wanted to try to implement instructions for building an Arduino library, that Ralph Bacon published three years ago. I'm still working on setting up the github repository according to github standards, but at least I've started. I've put my first cut up on github, if you wish to give it a try. I took a slightly different approach, as I wanted to minimize the library users efforts. I provide two methods. One to write and one to read. I have hidden both the 30 byte buffer problem and the use of 64 byte pages within the methods. The user just needs to pass the start address, the data array, and the size of the array. The start address can be any address, the size of the array is limited only by the amount of Arduino's memory.

USE:

The class constructor takes the I2C address of the EEPROM chip.

`SerialROM <object>(<I2C address>);`

The .begin method, is not absolutely required. It is used to allow the passing of a baud rate to the object, to support debug messages.

`<object>.begin(baud rate);`

The Serial EEPROM Controller library provides two methods .write and .read. For each the user supplies the starting memory address within the chip, a pointer to the data byte array, and the size of the array to be writen or read.

`<object>.write( <start address>, <data array>, sizeof(<data array> ); <object>.read(<start address>, <data array>, sizeof(<data array> );`

I've got lots to do yet. There is no fault handling, plenty of inefficiencies to wring out of the code, and I want to make the library easily loaded into the Arduino IDE.

--
Dale

Reputable Member
Joined: 8 months ago
Posts: 365
2020-02-15 10:54 am

@dale

Hey Dale, had a quick look at your code... not a bad first up attempt, but there are some points that I think you might want to consider as you develop it further:

1) Your constructor - I would consider restructuring it as follows:

I don't think that int_8 is sufficient enough, even for the standard Arduino EEPROM size, did you actually mean at least uint8_t instead of int8_t?

```SerialROM::SerialROM(uint8_t I2C_Address, bool displayMsg)
```

I also think you should consider using an constructor initialisation list (as shown above), instead of direct assignment in the constructor body.  The advantage of using an initialisation list, is that the data members are initialised before the body of the constructor is executed, and with greater efficiency.

2) If your class needs to work with or set the serial baud rate, then rather than re-creating the Serial object, you would be much better off passing just one Serial object around by reference, for example:

```// Serial is-a type of HardwareSerial
void SerialROM::begin(HardwareSerial& serial) {
serial.begin(9600); // Use "serial" as normal within function
if (_msg) {
serial.println("By the way... this is not the CONSTRUCTOR ;-).");
}
}

void setup() {
SerialROM MySR(0, true);
MySR.begin(Serial);
}
```

3) I also see that you're using too many print statements to incorporate new lines, for example:

```  Serial.println("");
Serial.println("");
```

Rather than just one line to do the same thing:

```  Serial.print("\nData as read.\n");
```

One last thing about print statements... when crating a library, you probably want to avoid having them in there, and only include them where absolutely necessary.  Normally, it's better to allow the user the control of where they would like to place any monitoring messages, so returning a Boolean value is a good idea to indicate the status of the action of the function, then the user can determine what to do and print.

Please take this as constructive criticism 🙂

Cheers!

(@pugwash)
Prominent Member
Joined: 9 months ago
Posts: 880
2020-02-15 11:13 am

@dale

Hey @pugwash. You've inspired me to give the problem a try.

Perhaps you should correct the typo in the SerialROM.h file "Twowire_h" not "Towwire_h" in the second line.

I will try out your library out soon and get back to you with my findings!

This post was modified 2 weeks ago by Pugwash

SteveC - Topple Rudd Poltman

(@dale)
Trusted Member
Joined: 8 months ago
Posts: 78
2020-02-15 1:56 pm

All feed back is welcome. Just one question... Regarding passing the object by reference, does this require that there is a Serial object setup in the calling sketch? I don't imagine there is a way to check for a valid object in the constructor. My preference is to not do any printing in SerialROM.cpp. I'd just strip everything out after completion of testing. Then again, in the broader sense, there is likely to be a situation when you need to pass on an object. I'll have to mull that one over.

--
Dale

(@dale)
Trusted Member
Joined: 8 months ago
Posts: 78
2020-02-15 2:07 pm

@pugwash

That is an odd one. I originally put those three lines in to resolve a problem. While it (at the time) seemed to resolve the problem, when I now look at it. It does nothing at all. So, out it goes 🙂

By the by, I've updated github based on the feed back so far.

--
Dale

Reputable Member
Joined: 8 months ago
Posts: 365
2020-02-15 3:11 pm

@dale

Posted by: @dale

No problem at all, glad to help!

Posted by: @dale

Regarding passing the object by reference, does this require that there is a Serial object setup in the calling sketch?

It all depends on how you want to use your program, as far as I can see there is no real requirement, because the "Serial" object has already been instantiated for immediate use... we never actually declare it, as it has already been done for us without our knowledge behind the scenes:

`HardwareSerial Serial;`

... we're just passing it around, and once you've called begin(n), your main loop can access it's member functions like println() just like before, because it's a global object... it's just a good habit to pass objects around by reference, especially when it might not be in visible scope.

Cheers!

This post was modified 2 weeks ago 2 times by frogandtoad

(@pugwash)
Prominent Member
Joined: 9 months ago
Posts: 880
2020-02-15 4:23 pm

@dale

If the wire.h library is invoked in the sketch, does it need to be invoked again in your SerialROM.h library?

Or should the code look like this:

`#ifndef wire_h#include wire.h#endif`

Just from someone who doesn't really know what they are talking about 🤣 🤣

And I was wondering why you have included a read() function in your library as reading the EEPROM is not really an issue, whereas writing to the I2C EEPROM is a big complex issue??

SteveC - Topple Rudd Poltman

(@dale)
Trusted Member
Joined: 8 months ago
Posts: 78
2020-02-15 5:11 pm

OK. So, as blind leading the blind we have...

`#ifndef Wire_h#include <Wire.h>#endif`

Does not work. It throws...

`In file included from U:\New Sketches\Serial_EEPROM\Serial_EEPROM.ino:4:0:SerialROM.h:7:10: error: #include expects "FILENAME" or <FILENAME>#include wire.h^~~~exit status 1#include expects "FILENAME" or <FILENAME>`

In my original code I had the conditional, in order to avoid multiple references to Wire. This does not seem necessary however, as simply typing

`#include <Wire.h>`

into my .h file works just fine.

As to read(); I believe we had issues with reading from the chip as well, and that this was again due to the 32 byte buffer in Wire.

From 2020-02-08 8:44 pm, I identified that in order to read 64 bytes, you had to perform two 32 byte reads.

Yep! looks like the 32 byte buffer strikes again. I changed the wire.right part to output incremental data. Then split the wire.read part to first read just the first 32 bytes, then repeat the read on the second 32 bytes. (code below)

`Values returned from EEPROMRegister , Value1 *** , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 *** 89 *** , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 *** 1617 *** , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 *** 2425 *** , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 *** 32Values returned from EEPROMRegister , Value33 *** , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 *** 4041 *** , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 *** 4849 *** , 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 *** 5657 *** , 56 , 57 , 58 , 59 , 60 , 61 , 62 , 63 *** 64Done`

Hope this helps.

--
Dale

Reputable Member
Joined: 8 months ago
Posts: 365
2020-02-18 2:18 pm

@dale

All this recent talk about scope jolted my memory about another scope I totally forgot about, and it might be helpful to solve this chicken and egg situation with initialising the serial object in the constructor... not sure how well it will work yet, but I'll give it a try and see what I can come up with.

Cheers!

(@dale)
Trusted Member
Joined: 8 months ago
Posts: 78
2020-02-18 3:27 pm

Great.  While I've got my code running, I would like to know why, and/or if there are better ways to achieve it.

--
Dale

Reputable Member
Joined: 8 months ago
Posts: 365
2020-02-19 2:01 am

@dale

All this recent talk about scope jolted my memory about another scope I totally forgot about, and it might be helpful to solve this chicken and egg situation with initialising the serial object in the constructor... not sure how well it will work yet, but I'll give it a try and see what I can come up with.

Posted by: @dale

Great.  While I've got my code running, I would like to know why, and/or if there are better ways to achieve it.

OK, so when I mentioned another scope I totally forgot about, it is what is known as an anonymous scope, that’s right… ANONYMOUS! 😀

I was trying to figure out a good way to demonstrate how to use this anonymous scope, and the effect that it can impose on a piece of code.  If you’re familiar with and or comfortable with C++ objects, then you’ll know that when we create a class, there are two default (hidden) constructors, and one default (hidden) destructor provided for us, and they are:

Default Constructor (invoked for default instantiation, if no other constructor is provided)
Copy Constructor (implicitly copies one object to another)
Destructor (responsible for clean up, destroying the object at the end of its SCOPE!)

Given the role of the destructor, I have come up with an example to demonstrate how to use the ANONYMOUS scope as follows:

```struct Object {
String Name;
Object(String name) : Name(name) {}
~Object(){
Serial.println("Destructor called for object: " + Name);
}
};

void setup() {
Serial.begin(9600);

Serial.println("Top of scope");

//{ // Braces introduce a new scope and force early object destruction
Object A("A");
//}

Serial.println("Bottom of scope\n");
}
```

As we can see here, when we remove the comments for the curly braces, they introduce a new scope for where the object was instantiated in, therefore when execution reaches the last brace, the object goes out of scope and in turn the destructor is invoked and forced to initiate clean up, thus object destruction, and the message printed from the destructor demonstrates it’s early destruction, right in the middle of Top and Bottom of the loop scope – Check your serial monitor with and without the curly braces in play.

Interesting you say?  Any how does any of this help us to get the Serial object to work in the constructor of our class as I mentioned yesterday?  Well, let’s see, using the following example:

```class Base {
private:
String message = "34#-'jf/2f1)4-5gf|ko";
public:
// Anonymous scope introduced to force the baud rate to be set
Base(unsigned int baudrate) { {
Serial.begin(baudrate);
}
Serial.println(decode());
}

String decode() {
for(unsigned int idx(0); idx < message.length(); idx++) {
message[idx] ^= 'F';
}

return message;
}
};

void setup() {
Base B(9600);

}
```

By introducing an anonymous scope within the context of our constructor, we are now forcing the global Serial.begin() function to complete setting the baud before exiting its current scope, and at that point when it exists, the serial object is ready for printing to the monitor – This works because the serial object has already been globally instantiated - Pretty cool eh?

Enjoy! 😜

ZeFerby liked
(@dale)
Trusted Member
Joined: 8 months ago
Posts: 78
2020-02-19 7:48 pm

I'm not certain that I, entirely, grasp what you've posted. However, I'll try a few things out and see what there is to see.

As far as

If you’re familiar with and or comfortable with C++ objects

goes... My previous example is the first C++ class that I've ever built. It's the first time I've ever run code with a class I've written. The fact that it does preform the task I assigned it, has struck me with a level of awe. Made me a bit cocky too, I suppose. I've spent the past three days constructing (pun intended) a Python class. Testing on it has gone satisfactorily, but has certainly highlighted the deltas between C and Python.

In any case, I'll do some testing over the weekend and post my results (and likely a few questions :).

Thanks again.

--
Dale

Page 2 / 2