Designing a simple and cheap temperature logger. Part 3: Open collector, FATs and de-debugging.

I had at last some time to work on the project. The prototype PCB is (at least, electrically) functional.

I started with making the TMP102 temperature sensor work. Nothing to say in particular, it’s just an other I2C-small-package-sensor. Or rather SMBus, but apart from the minimum speed clock requirements on the SMBus, the two protocols are alike.

On boot-up, the sensor gets configured and put to shutdown mode. Then, I use the “One Shot conversion” feature. When the right command is sent, the sensor starts a one-time temperature acquisition and returns to shutdown state, allowing to save as much as energy as possible.

The precision of the sensor is typically 0.5°C over its standard temperature range (-25°C to +85°C, the one I’ll be using) and the resolution is 0,0625°C (the LSB).

The temperature results are read on two bytes (12bits resolution). The first byte is the number before the comma, 2’s complemented for negative temperatures. The second byte contains the number after the comma. It has to be multiplied by 0.0625°C to get the real number.

I thought that a two digits after the comma precision should be enough (ie. by rounding), and instead of wasting CPU time with multiplication, I just made a string array containing all the results:


Then, when the second temperature byte is read (Temp1byte), I just have to index the array with it (after a 4-bit shift, because it comes left-aligned). “TempASCII” is a string containing the temperature value:

TempASCII[i] = ',';
TempASCII[i+1] = Temp_Precision[Temp1byte*2];
TempASCII[i+2] = Temp_Precision[Temp1byte*2+1];

Which gives the following numbers vs. the original 0,0625-stepped ones, in °C:

The array could of course contain all the non-rounded numbers:

TempASCII[i] = ',';
TempASCII[i+1] = Temp_Precision[Temp1byte*4];
TempASCII[i+2] = Temp_Precision[Temp1byte*4+1];
TempASCII[i+3] = Temp_Precision[Temp1byte*4+2];
TempASCII[i+4] = Temp_Precision[Temp1byte*4+3];

And so on. Useful trick instead of making a 0,0625 multiplication.

As said in earlier posts, I want to store the temperature readings in an Atmel AT25DF081 EEPROM. I chose it because it has a big capacity (8Mb) and a really low voltage supply value (1,8V). It connects via SPI to the microcontroller.

Now, with the great help of Microchip and its PICs I/Os being configurated as “Analog inputs” on startup and read as “0” when one forgets to set the right registers (ADCON0 & ADCON1), I had the great chance to spend two days measuring the EEPROM SPI link. Who would know the Analog ports “ANx” were also on the PORTB, and not only on the PORTA with ‘A’, as anolog? I know, RTFM.

During my investigations of the now perfectly working SPI, I could notice that the serial output pin of the memory (SDO) wasn’t an open collector, as I thought. It’s a pity it’s written nowhere in the Atmel’s datasheet. The Maximum input voltage of “3,8V”, Voh min of “Vcc-0,2” and no value for Voh max leave some room for imagination.

Well, the PIC seems to recognize the 1,8V SDO high state as high, even at higher speed, so it’s not such a big concern. A diode between the pin and the PIC will increase the EEPROM Voh to approx 2,5V (even if it also increases the EEPROM Vol of 0,6V). It could be an optional component on the final PCB design, replaced by a 0 Ohm resistor if the tests show no logical state decoding problem.

On the software page:

I took an example app from the Microchip’s USB libraries called “USB SD Card data logger”. It’s supposed to be an application for a logger with a SD card, being able to write on the card a value from a potentiometer.

It’s using the files SD-SPI.c and .h to access the SD Card, part of the Microchip’s MDD Filesystem. I started with these files and re-wrote them to make the project work with my EEPROM. Of course, that’s where the problems started..

On the filesystem, the default sector size is 512 bytes. As the PIC has to buffer the sector it’s writing to or reading from, there must be the same amount of memory allocated to the buffer as the size of the sector.  With the PIC18F26J50 I’m using, it cannot be bigger as 512 bytes.

The AT25DF081 EEPROM is organized into 256 bytes program pages. As they are smaller than the sector, it’s not a problem (I’m just making an address shift when the PIC wants to write more than 256 bytes). Reading is even easier, as there’s no page limit (it can be read starting form 0x000000 till 0x0FFFFF, the address counter on the EEPROM increments itself).

It gets complicated when you notice that the EEPROM’s erasing granularity doesn’t match the writing one. The smallest block to be erased is 4KB (then, 32KB, 64KB and 1MB) which means that to change even only one bit, all the 4KB must be read, erased and re-programmed.

AT25DF081 Memory space diagram

For now, I’m using only the first 512 Bytes of each 4KB page, but it limits the available space to 256 sectors of 512 bytes. That’s 128KB. Minus the space required for the filesystem and the sector for the logger configuration file, that leaves roughly 120KB of storage for the temperature measurements. Each of them will be something like “12/12/2011;23:59:59;127,00←↓” which is 28 Bytes. Divide 120KB by 28B, you get more or less a 40 000 temperature-acquisitions-worth-logger. Could be better and the idea of wasting 90% of my EEPROM is bad.

So, what exactly do we have to store in the EEPROM?

  • The FAT12 or 16 filesystem (3 or 4 sectors)
  • The configuration file (1 or 2 sector)
  • The temperature data

The FAT and the configuration file must be accessed often and must be user, computer-OS and PIC modifiable. But, the temperature data will only be written directly by the PIC and then only read by the user when the logging is over. The only modifications they (or rather the file containing them) will be subject to, are adding new measurements or erasing all the data for a new logging round. All that done by the PIC, which has direct access the the EEPROM.

I’ll need to modify the Microchip’s MMD filesystem routines to be able to directly write into a reserved block for the temp. measurements on the EEPROM. Plus, make the appropriate modifications in the FAT to allow a computer OS to read them, without being able to modify anything on the reserved block.

Quite a piece of work, especially because the library linking the USB procedures to the disk is complicated. And with optimized C code, it’s quite hard to debug the program, as the code pointer is jumping around all the time (I even thought it was a problem with my debugger/compiler/program/stack)

That’s for the next episode. I’ll also try to post the two files (SD-SPI.c and .h) I modified to use the AT25DF081 with the Microchip’s MDD and I’ll say a few words about the ICD3 debugger.