An archive of as of Saturday January 26, 2019.

A few Questions about writing to SD and hardware device registers


First, do any of the Demo's have logging to the SD card? Looking how to learn to log the data I collect to the SD card but I want it in like a CSV type format. But any example of writing actual data to the SD would be helpful.

Second, I'm trying to understand how a blob works with a hardware register. I hope I have that right. In the OneWire or maybe the DS18b20 nuts one of them is reading a register that contains the SN of the 1-wire device, the DS18B20, and I'm trying to get at that number and save it for future use. There is an address method but it changes so I don't think it is the SN of the device that has been laser coded. The address seems to change so It would be hard to reference the same temp probe every time I think. Could be wrong about that.

I'm very new at writing code to talk to hardware and still understanding how get information from the device and put information into the device or change it's behavior settings I guess you could say.

I have the Data Sheet for the DS18B20 and can see in what register and what bits are used for the SN, just don't know how to get it out.

Thanks, any help would be most appreciated.



Hi Jeffery,

Maybe Scott, or someone else, will answer the DS18B20 questions. But here's some code I use to log light sensor data to a file on the SD card:


digitalLightSensor <- TSL2561(I2C(0));
analogLightSensor <- ADC(0);

// Open a log file on the micro SD
const LUX_LOG_FILE = "sd:/lux.log";
try {
   // If the file already exists, open for append
    luxLogFile <- file(LUX_LOG_FILE, "r+");, 'e');
} catch (error) {
    // if it doesn't exist, create and open for write
    luxLogFile <- file(LUX_LOG_FILE, "w+");

local lastMin = 0;

while (true) {
    // Get readings from both the I2C and analog sensors
    local lux = digitalLightSensor.getLux();
    local lightV = analogLightSensor.readv(0);
    // Get the current local date/time
	local t = date();
    // Write the sample to the file with format: [<timestamp>] <digital sensor lux>, <analog sensor Voltage>
    local logEntry = format("[%04d-%02d-%02d %02d:%02d:%02d] %0.6f, %0.6f\n",
                                t.year, t.month,, t.hour, t.min, t.sec, lux, lightV);
    // Flush to the SD every minute
    if (t.min > lastMin)
    lastMin = t.min;

To get the serial code from the DS18B20 ROM, use the searchRomFirst() and searchRomNext() methods in the Onewire class. Since 1-Wire is a shared bus, getting the serial code is not as easy as reading a register since you must already have the serial code in order to address the device. These methods implement a special bit search algorithm to iterate through each serial code on the bus. For example:

onewire <- Onewire(1);

for (local rom = onewire.searchRomFirst(); rom != null; rom = onewire.searchRomNext())
    print("Found device: ");
    for (local i = 0; i < rom.len(); i++)
        print(format("\\x%02x", rom[i]));

If you only have a single DS18B20 on the 1-Wire bus, then you can pass a null as the serial code and the addressing is skipped:

ds18b20 <- DS18B20(Onewire(1), null);
print("temp = " + ds18b20.readT()+ "\n");

If you are using multiple DS18B20 devices, then you can save the serial codes reported during the above iteration and use them to talk to specific DS18B20 devices:

// Saved serial code for DS18B20 sensor 1
code1 <- blob();

// Saved serial code for DS18B20 sensor 2
code2 <- blob();

// Create DS18B20 instances
sensor1 <- DS18B20(onewire, code1);
sensor2 <- DS18B20(onewire, code2);

That is awesome, thanks guys for all your help.

I'm still not sure what a blob is and how it holds data. Does it store the ones and zeros from the register or is it like any character you want to put in there. It looks like a blob can be used for a lot of things according to the documentation.

The for loop is cool, I would have never of thought to use it that way.

What does <- mean. I tried to Google that but it didn't want to search for that.

Is it a pointer or is that how squirrel creates an instance of an object?




A blob is a simply class that holds a byte array of binary data. The equivalent in C would be a char or uint8_t array. Blobs are used throughout the Esquilo libraries to pass around binary data.

When you declare a blob with a size, that many bytes of zeros are allocated:

// A 15 byte array filled with zeros
data <- blob(15);

The C equivalent is:

uint8_t data[15];

Unlike a C array, blobs can dynamically expand and behave like a stream class:

// Allocate a blob with zero length
data <- blob();

// Append 0x5f and 0x23 to the blob

// The blob is now 2 bytes long now

You can also use array indexing with brackets just like C to directly access the bytes:

// Change byte 0 to 0x12
data[0] = 0x12;

In the previous DS18B20 example, the blob holds the 8 bytes of binary data for the scan code. You can use the methods available in the blob class to access and operate on those bytes.

The slot add operator <- creates a slot in a table. In Squirrel, it is explicitly required to create a slot. The slot get operator . is only used to access preexisting slots. This is different from how JavaScript works where slots are automatically created if they don't exist with the access . operator. Here is an example:

// Create an empty table named mytable as a global variable
mytable <- {};

// Create a slot name x with value 10
mytable.x <- 10;

// Print x (OK to use get operator)

// Change x to 20 (OK since x already exists)
mytable.x = 20;

// Set y to 30 with the get operator (throws exception since y does not exist)
mytable.y = 10;

The global namespace is actually a table (it's called the root table) so you must use the slot add operator to create global variables:

// Create a global variable called timeout
timeout <- 100;

// Change the timeout (OK since timeout already exists)
timeout = 200;

// Try to set non-existent global variable (throws exception since it does not exist)
delay = 100;

Since the global namespace is actually a table, you can also do fun things like print out all global variables:

foreach (k,v in getroottable())
    print(k + " = " + v + "\n");

If you are inside a function, then you can use the local keyword with the equal operator to create variables with function scope:

function myfunc()
    // Create a local table
    local mytable = {};

Thanks Scott, This is great. I read about tables in the Squirrel reference but didn't quite understand what they meant but I think I get it now.

So how do you remove a global variable from a slot or can you? I don't know if there is a reason to but with such little memory on these things I could see needing a global variable for awhile then dumping it. I try to keep Global variables to a minimum, I know they take up memory that you may not be able to get back.

That makes since on the DS18B20, the 64-Bit Lasered Rom Code would need 8 bytes to hold it.

Thanks a lot Scott, I'll be using this as a reference. I'll probably have to come back to it several times before it sticks in my head.

You and Patrick are great. Thanks both of you for all your help. I look forward to more cool things from you guys.



Good question. You can use the delete operator to remove a global or table value:

// Remove the timeout global
delete timeout;

// Remove the x table member
delete mytable.x;

You can also check for existence with the in operator:

// Check if timeout exists
if ("timeout" in getroottable())

// Check if x is in mytable
if ("x" in mytable)