Pages: 1 ... 3 4 [5] 6 7   Go Down
Author Topic: Arduino-izing the AVR Butterfly  (Read 11214 times)
0 Members and 1 Guest are viewing this topic.
Omaha
Offline Offline
Full Member
***
Karma: 0
Posts: 187
AC0KG
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Added an LCD driver. It is descended from Print so you can use LCD.print() and LCD.println() to output numbers. You can also print strings this way, but it's inefficient, better to use the provided prints(). I should override print() with the prints() code.

Here is the example sketch:

Code:
#include <butterfly_temp.h>
#include <LCD_Driver.h>
#include <timer2_RTC.h>

void setup()
{
  // Print a string from program memory. Faster than print,
  // and uses less ram than prints
  LCD.prints_f(PSTR("BUTTERDUINO"));
  delay( 3000 );
  
  // Print a string from RAM. Faster than print, and can
  // print strings that are not set at compile time.
  LCD.prints("TEMP Sensor");
  delay( 3000 );
  
  // Set up the RTC timer to call the secTick() function every second.
  Timer2RTC::init( secTick );
}

void secTick()
{
  // print() and println() functions can also be used to print
  // strings, and are not as efficient as prints(). However, both
  // will append to whatever is on the display. println() will cause
  // the display to be cleared before the next character is printed.
  LCD.print( TempSense.getTemp(FAHRENHEIT) );
  LCD.println( " F" );
}

void loop()
{
  
}

Logged


Oxford, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice work Dave. Sorry I had some last minute deadlines for work and my website got hacked which left me with no free time at all this last week or so.

I will check the code on my mac an make sure we are all still working.

[edit]Tested it and it all seems to work fine. Having trouble with my butterfly not erasing properly before programming but this is probably a separate issue with my setup. Keep up the great work.  smiley[/edit]

« Last Edit: December 24, 2008, 10:02:04 am by Brokentoaster » Logged

Omaha
Offline Offline
Full Member
***
Karma: 0
Posts: 187
AC0KG
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm working on a Dataflash library and I'm looking for some opinions on what sort of interface I should give it. In keeping with Arduino project principles I want to make it very easy to use, but I don't want to dumb it down too much.

I can of course expose the basic routines for power users to have direct access, but what are some ideas for a simpler interface for beginners?
Logged


Oxford, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'd like the library to be able to (if the user wants) take care of things like using the rom evenly i.e remembering the page last written when the application first started and also using the buffers effectively.

I guess the usefulness of that all depends on the application. In my butterfly logger application I've always meant to keep a record of the page last written in the eeprom so everytime I reboot the device or reconfigure the code it doesn't write to the first page of flash each time.

I normally select a page and write to the buffer until it is full. When I reach the end of a buffer I write the buffer to the flash and read the next page into the buffer.

The chip on the butterfly has 2 buffers which each can hold a page of rom. You could write a library routine that only writes /flushes the data to the rom when needed, i.e. you have reached end of page in a sequential write or you have started working on a different page in memory.

I would think one of the best things a library could do for a new user is abstract away from these details so you can simply read and write to any address in flash and the library will handle the writing efficiently, avoiding unnecessarily rewriting the same page in flash.

how does something like the following look

Code:
flash.read(page, addr, *data,length) // read length bytes from page into memory at data
flash.write(page,addr, *data,length) // write length bytes from memory at data into memory
flash.writebyte(page,addr,byte) // write byte at addr in current page
flash.readbyte(page,addr)  // read byte at addr in current page
flash.flush // write the current buffer to flash

Hope this gives you some ideas. If you wanted you could even remove the whole ideas of pages and use a linear address space across the rom. Let me know if you want me to test it smiley . Love the cricket example by the way. nice work.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

you could implement a next fit or best fit algorithm. (http://www.developerfusion.com/article/5540/bin-packing/5/)

just my 2 cents... sunny
Logged

Omaha
Offline Offline
Full Member
***
Karma: 0
Posts: 187
AC0KG
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Regarding Best Fit; this really starts to get into making some assumptions about what the user is going to store. It also starts to get into a territory where I need to keep track of the number of page writes within a sector (every page in a sector has to be refreshed at least once per 10,000 page writes within that sector).

I'm inclined to make the base library conform very closely to the interface functions of the dataflash, with the two SRAM buffers, paged read/write functions and the direct linear read access to the main memory.

This, obviously, because this is simple in terms of developer (that's me) effort, as well as code space. I don't like to add lots of fancy features to a library for a device as limited as the AVR without a darn good reason, program memory is just too valuable.

However, since it wouldn't be terribly difficult, I think it might also be worthwhile to do a second version of the library that presents the entire dataflash as a flat address space. Reading is pretty easy as this is more or less supported by the chip, and writing isn't hard since it is pretty straightforward to page the writes. This introduces some unpredictable delays that the user might experience when a page buffer fills and has to be written, but that's a cost of hiding such details.
Logged


Oxford, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I agree. I'd go for a first implementation that simply ports some of the existing functions of dataflash.c/h over to the arduino evnvironment.

Once that is in place we can shape the object to better fit the arduino ideology.

The problem with paging writes is, as you noted, that there maybe unexpected delay when flushing the buffer to flash is triggered. I think that this simply has to be assumed that in terms of timing a full buffer to flash operation takes place after each write.

You could also have a check function that you pass the length and address of the data and returns true if a page write will be triggered by and actual write of the same size. But this of course complicates the way in which the user would use the library. If a user is concerned with delays then they will need to use more complicated code.

I guess the real answer here is in documenting the functions in such a way so that the delays occurred when a buffer is written to flash is expected.

Anyway I'll see if I can put a simple data logger example together using the rtc, temp sense and dataflash libraries.
Logged

0
Offline Offline
God Member
*****
Karma: 1
Posts: 513
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So, does this handy, write one value at a time, flash functionality require a constant 128+ bytes of ram?

Should this sort of thing be in its own thread?
« Last Edit: December 29, 2008, 09:51:27 am by dcb » Logged

Oxford, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The dataflash chip on the butterfly has two single page buffers. The flash chip has 2048 pages of 264 Bytes each.

No system ram is used.  smiley
« Last Edit: December 29, 2008, 12:40:55 pm by Brokentoaster » Logged

Omaha
Offline Offline
Full Member
***
Karma: 0
Posts: 187
AC0KG
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
So, does this handy, write one value at a time, flash functionality require a constant 128+ bytes of ram?

This particular dataflash works by giving you sequential read or write access over the SPI connection. There are several different access modes.

For example, you can write the command byte for directly reading the flash memory out the SPI connection, then when you read you get the first byte. The next time you read you get the second byte.

You can access it in a paged mode, where you tell it you want paged read mode, and what page, then instead of reading from the beginning it starts with the specified page.

You also have the option of reading/writing to either of the two single-page sized SRAM buffers Nick mentioned. These work the same way, once activated you can only start reading/writing from the first byte, and when you get to the end it wraps back around to the beginning. At any given point you can tell it to write the buffer to a flash page, or read a flash page into a buffer.

There are two buffers so that you can write continuously. Since it takes time to erase a flash page and then write the contents of the buffer the chip provides two independent buffers. While buffer 1 is writing to flash you can work in filling buffer 2. By the time you finish filling buffer 2 and command it to write, buffer 1 will be available again. Of course you don't have to use both buffers if you don't want to.

One possible use of one of the buffers might be to treat it as a ring buffer that you can just keep writing to for long periods, letting it wrap automatically. It could be used as a kind of FIFO history buffer for whatever you needed.
Logged


Omaha
Offline Offline
Full Member
***
Karma: 0
Posts: 187
AC0KG
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, I committed a basic dataflash driver. I haven't done much testing of it, and I haven't tested the deep power-down mode at all. I put a basic flash test in as the example:

Code:
#include <dataflash.h>
#include <LCD_Driver.h>

bool test()
{
    bool result = true;

    // Set up to write data to SRAM buffer 1, starting at byte 0
    DataFlash.BufferWriteEnable(1,0);
    // Write a series of bytes into the buffer
    for(byte j=2; j<52; j++)
        DataFlash.WriteNextByte(j);

    // Write SRAM buffer 1 to flash page 1
    DataFlash.BufferToPage (1,1);            
    
    // Set up to read directly from flash page 1, starting at byte 0
    DataFlash.ContFlashReadEnable (1,0);

    // Read a series of bytes and check the value
    for ( byte j=2; j<52; j++ ) {
        if ( j != DataFlash.ReadNextByte()) {
            result = false;
            break;
        }
    }

    // Deactivate the flash chip when not in use.
    DataFlash.Deactivate();    
    return result;
}


void setup()
{
  LCD.prints("flash test");
  delay(2000);

  LCD.clear();
  if (test())
    LCD.prints("Success");  
  else
    LCD.prints("Failure");
}

void loop()
{
}

I stripped the original driver code of support for other flash chips, refactored it a bit to save some space, and added the deep power-down support routines. (should save another 20uA over standby mode, and only takes 35uS to resume).

This interface isn't really obvious for the beginner. I'd like to make a simplified version of this library and give it an interface more like a file, where the user can do something like:

Code:
DataFlash.Open( <New or Append> );
DataFlash.Print( RTC.Date );
DataFlash.Print( ':' );
DataFlash.Println( TempSense.getTemp() );
DataFlash.Close();

The Open function would set up a buffer for writing. The 'New' or 'Append' parameters would specify either that the dataflash should be cleared or that new lines should go to the end of the existing data.

The print functions would write data to the current buffer until it was full, then dump that data to the flash and swap in the next buffer. Close would flush whatever data was in the current buffer.

A Readln() function would read bytes until it hit a newline.
Logged


0
Offline Offline
God Member
*****
Karma: 1
Posts: 513
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, I think I get it smiley you are talking about the 8 pin, AT45DB041B-SC-2.5 4 megabit chip that is specific to the butterfly package.

mouser lists it as obsolete, what would be a more current surrogate chip do you suppose (if someone wanted to butterfly-ize their arduino)?

« Last Edit: January 01, 2009, 07:06:57 pm by dcb » Logged

Omaha
Offline Offline
Full Member
***
Karma: 0
Posts: 187
AC0KG
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Try the D revision:

AT45DB041D

Of course if you are doing your own you could use other sizes as well, the 32Mbit AT45DB321D is only a couple of bucks more.

Actually, it might be interesting to swap the Butterfly's 4Mbit chip for the 32Mbit for data logging applications.
Logged


Omaha
Offline Offline
Full Member
***
Karma: 0
Posts: 187
AC0KG
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm thinking of options to improve low power operations. Should the Butterfly core assume low power is a priority and initialize the butterfly with that in mind (turning off various things that take power, deep-sleeping the flash, etc), or should we have a low power library that the user includes that will do those things?

I'm inclined to go the route of using a library so that the limited code space on the device isn't taken up by things that aren't always necessary.
Logged


Oxford, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The Butterfly was always intended as a demo of the low power capabilities of the AVR.
I think however that in this application we a prioritising ease of programming and flexibility so I'd argue for a low power library so that should a specific application require these attributes they can be called upon.
Logged

Pages: 1 ... 3 4 [5] 6 7   Go Up
Jump to: