Go Down

Topic: Compiling an SD/MMC and fat16 library (Read 5 times) previous topic - next topic


How can i get an unsigned long int converted to it´s bytes?
I want to store the offset in the start range of the card, the first four bytes.
So this could be read the next time it starts recording and does not overwrite the record from before.

I thought code like this could help, but i googled extensively for a solution, but didn´t found something really helpful.
Here´s how i thought:

Code: [Select]

unsigned long int sdoffset=1024;  // r/w offset
// offset 0 to 1023 is for rw offset and whatever storage.
// for the first usage have to write zeroes to that.

void checkStartOffset(){
 byte offsetstored[4];
 sd_raw_read(0, offsetstored ,4);
 sdoffset=(unsigned long int)offsetstored;
 Serial.print("sdoffset read: ");
void WriteLastStartOffset(){
 char offsetstored[4];
 sd_raw_write(0, offsetstored ,4);

the start check compiles, but don´t know at the moment if that works. The read function will not compile.
Could someone point me into the right direction?

Thank you very much for any help with this!


Ok I'll try and expalin but someone else probably can do it better. If you are writing numbers larger than bytes (8bits =  2^8-1 = 255) then you need to split the number up into separate bytes. I'll give a code example. I wanted to store the values of the arduino ADC in the memory card. Values from the ADC are 10bit (10bits = 2^10-1 = 1023). So the 10bit number needs to be split into two values to be able to be stored in 8bits.

Code: [Select]

// Store my 10bit value in an int (NOT a byte, which is only 8bits) so 16 bit number. High(1111 1111) Low (1111 1111)
int temp;

byte low;    // Variable to store the low byte in
byte high;   // Variable to store the high byte in

temp=analogRead(0); //Read in the value

// AND the number with 255 which wipes the 8bits at front of number
// The front 8 bits gets wiped->High(1111 1111) Low(1111 1111) = High(0000 0000) Low(1111 1111)
// So you can store half the number in the low byte variable

// Rotate the number 8 bits right to get the high bits.

So you can then store each byte in an array and then write it to disc. To read back from the disc you read in each byte and then join them together again.
Code: [Select]

byte low;
byte high;
byte info[2];
int value;

sd_raw_read(0,info,2); // Read the 2 values from disc
low=info[0];  // store low byte
high=info[1]; //Store high byte
result=high<<8; // rotate left 8 bits the high value and store in result
Serial.print(result+low,DEC); //Add low and high together to get the original number you split up into 2 bytes

The easiest way to see how this all works is to try this code and use Serial.print after each operation and print the numbers in binary. Then you can see how the bit manipulations are working. For larger values long int etc, you have to split the number up into 8bytes and then store each byte individually. So if you wanted to store a 32 bit number you would need to split it into 4 bytes and then write each byte to disc.

Well, hopefully I explained it ok  :)


Feb 17, 2008, 02:04 pm Last Edit: Feb 17, 2008, 11:14 pm by strohhalm Reason: 1
Thanks again a lot! I think i´ve got it mostly. I made for test  some handy defines:
Code: [Select]
#define HIGHBYTELONG(x)  ((byte)((x) >> 24))
#define LOWBYTELONG(x)  ((byte)((x)  >> 16))
#define HIGHBYTE(x)  ((byte)((x) >> 8))
#define LOWBYTE(x)  ((byte)((x) & 0x00ff))
#define WORD(x,y)   (( ( (byte)(x) ) << 8) | ((byte)(y)))

unsigned long int ulnumber = 0xABCDEF89;  

void setup()
 Serial.println(ulnumber, HEX);   // prints value as string in binary (base 2)
 byte hbl = HIGHBYTELONG(ulnumber);
 Serial.println(hbl, HEX);  
 byte lbl = LOWBYTELONG(ulnumber);
 Serial.println(lbl, HEX);  
 byte hb = HIGHBYTE(ulnumber);
 Serial.println(hb, HEX);  
 byte lb = LOWBYTE(ulnumber);
 Serial.println(lb, HEX);  
 unsigned int wi = WORD(hbl,lbl);
 Serial.println(wi, HEX);  
 unsigned int wi2 = WORD(hb,lb);
 Serial.println(wi2, HEX);  
 unsigned long int wix = (( (((unsigned long int) wi) <<16)) | ((unsigned  int) wi2));
 Serial.println(wix, HEX);  

void loop()

i get the following output:

i took hex numbers, so you can see it directly if it works correct.
But i could not make a working define for the unsigned long int directly. But for now i have what i need to go on.
Thanks a lot again! :)

Made yesterday in the late evening a little walk with the raw boxed logger device. It worked so far. But i must have had some worse serial connector or the cold was to much, @-4Celsius. Many track point missed  caused by worse checksums, also the serial connection had too much failures or the mmc? .  I´ll make today a walk again.
The sd_raw write works really fine now, but it is much more slower than the gps. I expected it been faster than the gps. So i changed for test the buffer to 512bytes, thats the bulk it always wants to write i think.
i´ll post that code later.

--- more info to come
added a missing "#" in code section


For an outside was no time, but tested inside. Now the data looks quite good. Saving the offset seams to work now. So the hole thing is still quite dirty, but it seems to work so far.
I take a 1G Kingston card. Data write section starts at offset 4096. The first 4 bytes on the card are for saving the actual offset.
At power on it checks the offset on the card, so it should be cleared on a  fresh card or when you want to write from beginning. If it finds offset data, writing starts from there.
(On the PC i read it with HxD http://www.mh-nexus.de thats a raw reader i found for free.
You can read the data with it and clear the card if you want. Useful for test anyway.)

Then the arduino fills the write buffer with 128 bytes, the length of the serial buffer, i thought that may increase speed. Tried that with 512 bytes, i read in the sd card data sheet that this is always that bulk it writes. But that didn´t wanted to work. Went back to 128, no problem. After fill it writes the data on the card, writes the new offset and flushes the cache. Without flushing i had sometimes no data on the card.

After an 1hour test run i converted the data with GPS Babel http://www.gpsbabel.org/ to kml and checked with g**gle earth. For the test run i was on USB.
For the 3.3V i added a low drop regulator a LF33CV. I simply connected it to 5V and ground on my shield, the out pin directly to the Vin of the card. Before i had added an elco to 3.3 and ground at the card, so there was no need for an additional one. The first proposed condensator i saw no need for, cause of the stabilized 5V, but that may not be correct, but works. With my Velleman personal scope voltage looks fine without ripples, ups and downs. The Velleman may not be the best, but it´s very useful for me. Mostly better than a multimeter.

Ok, the code:  Binary sketch size: 5348 bytes (of a 14336 byte maximum)
in the next post...


... continues from previous post

Code: [Select]
/* work in progress ... 2008 02 17
* it´s still quite dirty! take care!
* using stuff from:
* arduino.cc -> got the basics, they made it easy and fun!
* Roland Riegel http://www.roland-riegel.de/sd-reader/ -> the awesome mmc&fat libs
* Ulrich Radig http://www.ulrichradig.de/home/index.php/avr/mmc-sd -> hardware hint
*                 has also made an interesting mmc & fat lib, but not used here.
* www.mikrocontroller.net -> got some good soft-&hardware hints (german language)
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1199737337 -> the important things for the code
*                 from the nice people here to get started with this project.
* www.navilock.de -> the gps module (got the rs232, better would be the ttl level one)
* so i had to add a max232 IC for serial communication. with ttl no need for that.
*    http://www.navilock.de/produkte/gruppen/13/Boards_und_Module/60409_NL-500ERS_Sirf3_RS232_Modul.html
* This little project is for getting the basics of gps reading
* and long time data storage together.
* Should get a useful gps-data-logger when ready.
* Ideas&ToDo:
* buttons for r/w/a (read write append) functionality?
* Adding a Siemens S65 LCD display.
* Connect it to a WiiRemote -- log acceleration, degree, communicate with BT &
*    add XBeePro for reality mesh network activity (great potential in it!)
*    maybe for exploring land- and city scapes, reality gaming... with a group of people.
// including the mmc libraries for raw r/w support:
#include <sd-reader_config.h>
#include <sd_raw.h>
#include <sd_raw_config.h>

// defines for splitting the unsigned long int into bytes for storage:
#define HIGHBYTELONG(x)  ((byte)((x) >> 24))
#define LOWBYTELONG(x)  ((byte)((x)  >> 16))
#define HIGHBYTE(x)  ((byte)((x) >> 8))
#define LOWBYTE(x)  ((byte)((x) & 0x00ff))
#define WORD(x,y)   (( ( (byte)(x) ) << 8) | ((byte)(y)))

unsigned long int sdoffset=4096;  // r/w offset
// offset 0 to 4096 is for rw offset and whatever future storage.
// for the first usage have to write zeroes to the card.
// the last offset on my 1G card is 1009254384
// get as much buffer length as the serial port has:
int in_buf_length=128;
byte incomingBuffer[128];  // for incoming serial data

// optical function control:
int ledWrite = 9;
int ledRead = 8;

void setup() {
 pinMode(ledWrite, OUTPUT);      // sets the digital pin as output
 pinMode(ledRead, OUTPUT);      // sets the digital pin as output

 //Init of the MMC/SD-Card
 // give it some time
 digitalWrite(ledRead, HIGH);   // sets the Read-LED on
 digitalWrite(ledWrite, HIGH);   // sets the Write-LED on
 sd_raw_init ();
 digitalWrite(ledRead, LOW);   // sets the Reaad-LED off
 digitalWrite(ledWrite, LOW);   // sets the Write-LED off
 // and a second time...
 sd_raw_init ();
 // let´s see where we go:
 for (int i=0; i <= 3; i++){
   digitalWrite(ledRead, HIGH);   // sets the Read-LED on
   digitalWrite(ledWrite, HIGH);   // sets the Read-LED on
   digitalWrite(ledRead, LOW);   // sets the Read-LED off
   digitalWrite(ledWrite, LOW);   // sets the Read-LED off
 Serial.begin(9600);      // navilock works with 9600bps from scratch
 // For programming you have to disconnect the gps physically!
 // check where we stopped writing the last time:

void loop() {
 digitalWrite(ledRead, HIGH);   // sets the Read-LED on
 digitalWrite(ledRead, LOW);   // sets the Read-LED off
 digitalWrite(ledWrite, HIGH);   // sets the Write-LED on
 sd_raw_write( sdoffset , incomingBuffer , in_buf_length );
 sd_raw_sync ();      
 digitalWrite(ledWrite, LOW);   // sets the Write-LED off

void writeLastStartOffset(){
 byte offset[4];

 sd_raw_write(0, offset ,4);
void fillSerialbuffer(){
 // we have enough storage with 1G
 // so we take the hole input from gps.
 // don´t care about single lines, get the whole stuff!
 // read one serial buffer with length of 128:
 int var = 0;
 while(var < in_buf_length-1){
   if (Serial.available() > 0) {
     incomingBuffer[var] = Serial.read();
void checkStartOffset(){
 byte offsetstored[4];
 sd_raw_read(0, offsetstored ,4);
 unsigned int wri = WORD(offsetstored[0],offsetstored[1]);
 unsigned int wri2 = WORD(offsetstored[2],offsetstored[3]);
 unsigned long int readdoffset=( (((unsigned long int) wri) <<16)) | ((unsigned  int) wri2);
 // when it is a clean card with 00 00 00 00 on it,
 // start anyways at the right offset.
 if (readdoffset < 4096)

i had to cut out the out-commented debug code, it was to long.

Thanks again for help! I feel having hijacked this thread, hope that is ok for everyone? Should i stay here with future additions and improvements? Because it is not purely the topic of the post now?

If there is serious interest i can describe the project with more detail, pictures and so on.

Tomorrow i will try to log my way to work. I´ll post information especially when success is not satisfying.

Go Up