Send multiple (64) bytes via I2C in a loop?

bpowell

Senior Member
Using a 08M2
Trying to page-write to 24LC256


I'm trying to write a program that will load an EEPROM from a text file on my PC ... I'll have a Python program that will shake-hands with the PICAXE, and will then send the text file in groups of 64 bytes ...

I'm catching those bytes okay, and storing them in memory using @bptrinc (started at 28)...

However, how can I write 64 bytes to the EEPROM without having a silly command such as

Code:
hi2cout eeprom_address, (@bptrinc, @bptrinc, @bptrinc, ... etc 64 times)
I'd like to use a for/next or a while loop ... but I don't want to just write a byte at a time ... I'd like to reduce eeprom wear (I'm not really concerned about the eeprom, but it's my goal to do page-writes, vs. byte-writes).

Any thoughts?
 

Buzby

Senior Member
The 'multiple @bptrinc' method is the only easy method I can see to send a block of bytes in a single I2C message.

There might be two other ways, but I've only tried one.

Idea 1, Instead of your Python writing bytes to the Picaxe, make it write lines to a .bas file that Picaxe can run, maybe as an 'include' file.
Each line would look like 'hi2cout eeprom_address, (xx, yy, zz .... 64 bytes )', and there would be a line for each block of 64 bytes.
I used this method to programme eeprom values which were pre-calculated by some Excel VBA. The Excel wrote the Basic file, the Picaxe ran it.

Idea 2, Bit-Bang your own I2C on a couple of IO pins. Then you can send an 'I2C Start', run a loop to send 64 bytes, then send 'I2C Stop'. There are example I2C codes in this forum somewhere.

I have a third idea, but it's really off-the-wall !

You can't do it with an M2 chip, you need an X2. My experiments were on 20X2 chips, but I didn't fully explore the results.

Set another 24LC256 as an external #slot.
Write a simple line that sends hi2cout with 64 bytes of $FF, then download that line to the external #slot.
Now you can switch to reading the eeprom using normal I2C to find the locations of the $FF and replace with your data.
Now run the #slot.

I'm sure it's not as easy as that, but it's the sort of thing I'd like to try. It's effectively 'self modifying code' on a Picaxe !
( One problem I can expect is that the compiled data wont't look like a string of $FF because of the method Picaxe uses to store variables. )

Let us know how you get on.

Cheers,

Buzby
 

Aries

New Member
You could always have a loop which writes N bytes and executes 64/N times (N a power of 2, of course)
 

Buzby

Senior Member
You could always have a loop which writes N bytes and executes 64/N times (N a power of 2, of course)
The first problem with this solution is that you can't change the data in the loop, it just repeats the same transmission 64/N times.

The second problem is that it still won't transmit a 'page full' in one one message.

But does a page full really need to be sent in one go ?. It is unclear why the OP wants to write full pages, as he already said he's not concerned about eeprom wear-out. ( A sensible approach. These eeproms are tough !. See the post about my eeprom endurance test. )

 

Buzby

Senior Member
Correct, I thought you meant fixed data. Doh !

Thinking on it, a single line of 64 @btrinc instructions is still the simplest way. Only one line of these is needed, as the OP sends 64 byte strings with handshaking, he just needs to reset bptr after the 64 byte TX, set the next eeprom address, load the next chunk to RAM, and repeat in a loop.

The original purpose of the page buffer was to improve speed and reduce wear. With modern eeproms, where each piece of data has an extra few bits added for error correction, and built-in wear leveling, it is unclear if page buffers are actually needed, or where the data is stored. I seem to remember some Microchip publication stating that 'page mode' was still supported to allow legacy designs to use modern tech chips.
 

bpowell

Senior Member
With modern eeproms, where each piece of data has an extra few bits added for error correction, and built-in wear leveling ...
the EEPROM is question is a 24LC256; which does not employ any error correction or wear-leveling.

I wanted to do full page writes because it's the best practice. If I write 64 bytes individually; then the page will get written 64 times ... not only is this more wear and tear on the EEPROM (again, not a real concern, but still) it's also a time-sync, as you have the 5ms penalty per write....so If I can eliminate 63 writes per page, that's 315ms.
 

bpowell

Senior Member
You could always have a loop which writes N bytes and executes 64/N times (N a power of 2, of course)
I'm afraid using "hserout" in a loop will result in the EEPROM interpreting each write as a full transaction, and executing the write ... so I won't be doing page-writes, but byte-writes.

I suppose I could gin-up some I2C routines of my own ... but that seems like more work than writing a comical, "hserout address, (@bptrinc, @bptrinc ... 64 times)
 

bpowell

Senior Member
Let us know how you get on.
Lots of good ideas; thanks!

Ultimately, I went with the funny-looking "hserout address (@bptrinc, @bptrinc, @bptrinc, ...) line ... it works.

So, after some tweaking, I do have a good pair of programs that work ... one on the PICAXE to receive data in 64-byte chunks (storing to ram, and then writing as a page-write to the EEPROM) and the other program on the PC to grab a text file, shake-hands with the PICAXE, and then send the file in 64-byte chunks until 32,768 bytes have been sent (i.e. 512 times). I've had to add some delays to keep the PICAXE happy ... so it's a bit slow (takes 8 minutes to load an EEPROM) but it works. I might work on trying to eliminate the delays to speed things up. But that's a down-the-road thing.

So, I now have an EEPROM that (at the moment) has a good portion of, "The Art of War" loaded on it ... and a simple PICAXE routine that randomly picks out a full sentence and displays it. I feel wiser every time I press the button! :)

Thanks again for the help!
 

bpowell

Senior Member
so it's a bit slow (takes 8 minutes to load an EEPROM) but it works. I might work on trying to eliminate the delays to speed things up. But that's a down-the-road thing.
The slowness was the intra-byte delay I had built into the Python code .... the delay I was using has a minimum of 10 - 13ms ... so I used a different delay that allows me to get down to 4ms which the PICAXE seems to tolerate.

Probably could eliminate that entirely if I were using HSERIN, but, already using I2C there!

So, now it takes about 76 seconds to fully load the 24LC256 with no retries.

My PICAXE says, "Appear at points which the enemy must hasten to defend; march swiftly to places where you are not expected."

I love these little nuggets of wisdom!
 

Buzby

Senior Member
While you are waiting for your eeprom to download, your opponent has read his copy of TAOW, used his intelligence, and swiftly attacked your blindside.

You need a faster download. The fastest download for 32K is, according to Microchip, about 3 seconds.

A technological advance, raw PIC assembler, will give you the advantage !
 

papaof2

Senior Member
If you can write to the "metal" you can almost always get better performance. Most of my PICAXE projects have been simple automation: checking temperature in an enclosure and turning a fan on and off, counting gallons of water used in irrigation - from a tank at ground level so with pressure less than 1PSI and the water moving slowly enough to not need anything fast to do the counting.
Even if it's not a PIC or PICAXE, the closer you get to the metal, the faster your program can run.
One of my assignments while in the corporate "skunkworks" in the 1990's was to "speed up" a process which had a 386PC running an interpreted BASIC program to read incoming mail on a UNIX system, extract key phrases and transfer that to a mainframe via a 3270 card. The organization that originally put it together denied any knowledge of which 3270 library had been used and denied having a copy of that library at that facility. I don't think anyone wanted to claim that fatherless child. That left only one "speed up" option: compiling that huge block of BASIC. The "skunkworks" didn't have a compiler so I brought my copy of PowerBasic to work and did the tweaks needed for that interpreted BASIC to be compiled. With some general code cleanup and it being compiled, I got a 10 to 1 speedup: the "every 15 minutes" process that had been running 20+ minutes was eventually down to 2 minutes. Sometimes you just need the right tools...
 

hippy

Technical Support
Staff member
Thinking on it, a single line of 64 @btrinc instructions is still the simplest way.
And you can save on typing, and miscounting, by leveraging '#define' ...
Code:
#define WR4    @bPtrInc , @bPtrInc , @bPtrInc , @bPtrInc
#define WR16   WR4      , WR4      , WR4      , WR4
#define WR64   WR16     , WR16     , WR16     , WR16

WriteI2c $8A, ( WR64 )
 

bpowell

Senior Member
And you can save on typing, and miscounting, by leveraging '#define' ...
Code:
#define WR4    @bPtrInc , @bPtrInc , @bPtrInc , @bPtrInc
#define WR16   WR4      , WR4      , WR4      , WR4
#define WR64   WR16     , WR16     , WR16     , WR16

WriteI2c $8A, ( WR64 )
As always: Hippy steps in with an elegant solution!

Thanks sir!
 

bpowell

Senior Member
While you are waiting for your eeprom to download, your opponent has read his copy of TAOW, used his intelligence, and swiftly attacked your blindside.

You need a faster download. The fastest download for 32K is, according to Microchip, about 3 seconds.

A technological advance, raw PIC assembler, will give you the advantage !
So ... I don't know if it's OCD, or what ... but I've been wondering how to speed this process up!

Grabbed my 20x2 proto-board, and threw a 512k eeprom on it ... (all I had) and started tinkering.

Using HSERIN at 115200 (or 230,400 ... doesn't make a material difference) and removing the delays in the PICAXE and Python code, I'm able to program 512 pages (doesn't matter if they're 64-byte or 128-byte ... no material difference) in 8.3 seconds!

Code:
...
Sent Page:  509   65152  bytes
Sent Page:  510   65280  bytes
Sent Page:  511   65408  bytes
Done message received...
Elapsed Time:  8.30388355255127
Total bytes sent:  65536
Press ENTER to exit
I might fiddle a little more; but I think we're at the limit of the PICAXE receiving, updating HSERPTR numbers, and writing to EEPROM. Still, not shabby!

I am using a software flow-control as well; so the PICAXE says, "Go for it" ... receives a page, and then, if the count is right, it burns it to EEPROM and gives another "Go for it" message ... that's when Python grabs the next bit of data from disk. If the byte-count isn't correct; PICAXE will send a "Whoops" message, and Python will resend. So that process probably impacts performance as well.

If I get a few minutes, I might try just sending the same 128 bytes 512 times, to see if disk / file access is impacting the send time or not.

Side note: I had to grab a different book, since TAOW is only 59k-ish in size; so doesn't even fill up the 512k eeprom!
 

bpowell

Senior Member
Sending 128 Bytes from PC @ 230400 bps = 5ms
Sending 128 Bytes to EEPROM @ 400khz = ~ 2.8ms + 5ms "write time"
I'm overlapping to some extent the PC send with the write-time ... so I'm very happy with 8.3 seconds for 512kB!

I tried to rework the PICAXE program to use background receive and try to parallelize the HSERIN with the H12COUT ... but that actually added about 2 seconds to the transaction.

Still, it's kind of crazy shoving 512kB of data into these little chips in under 10 seconds!
 

hippy

Technical Support
Staff member
I'm able to program 512 pages (doesn't matter if they're 64-byte or 128-byte ... no material difference) in 8.3 seconds!
That seems to be in the right ballpark. A page write will take something like 10ms which I would guess is where most of the time is; 512 x 0.01 = 5.12 seconds and the remainder, about 3.2 seconds, being in serial, processing and passing data to the chip, overhead.

The best you can do is shave down those 3.2 seconds. About 0.33 seconds is the time taken to send 64KB at 20400 baud. I can't imagine reading a 64KB disk file is taking much time at all. So perhaps the focus should be on getting received data to the chip. Maybe a SETFREQ would help there ?

You probably need to toggle output pins and use a logic analyser or scope to measure the time of parts of the code to see where the time is taken.

But, at the proverbial end of the day, the best you can probably do is get 8.3 seconds down to nearer 5 seconds which may not make it worth doing in practice.
 

julianE

Senior Member
The art of war is a young man's book, may i suggest a tang dynasty poem, The Song of Everlasting Regret, should fit in an even smaller eeprom.
 
Top