...sine propero notiones
|You are here: Kiko > PostsInEnglish > EnBlogEntry2008Feb24A||Printable | topic end|
and the real time clock, but no events yet.
complete: we already have the TWI EEPROM, LCD,
batteries and buzzer.
RWsignal. Properly adjusting the delay loops, I quickly got it working. Then I restructured the routines so that a task in the firmware's main loop takes care of moving bytes from a buffer to the LCD, so printing to the LCD is actually done by stashing data in this buffer -- the advantage being that we can print as fast as possible without needing to care about timing issues. I was also very pleased with the fact that the LCD module used only meager 0.8mA, contributing very little to the device's overall consumption of just 8mA (meaning we're still below the 10mA budget). But after I added the LCD, the first pitfall presented itself: the frequency measurements started to exhibit a strange variation every now and then -- it was 60.000 in a moment, then something near 63Hz, then a very low number, then back to normal. I had added accumulators to count how many "fast" and "slow" semicycles we had (that is, semicycles with periods +/- 10% larger than the expected 1,042 Timer1 ticks) and noticed that the "fast semicycle" counters incremented when it happened. Overconfident with the good results from the initial assembly, I almost dismissed the problem as yet another oddity in the mains here, much like the flattened out wave. Then it got worse, then it got better and I got puzzled. Then I thought it was a software problem and quickly discovered that I went away when I disabled the LCD code. A few hours of frustrating debugging led me to one particular assembler instruction: the one that moves the low 4 bits of the byte to the LCD data bus. Then it struck me: the
D7line is physically just next to the MCU's
ICPpin, so my problem was electrical switching noise: whenever the character being sent to the LCD had bit 3 on and the
ICPpin was zero, it triggered the ICP edge detector. Apparently, the AVR's event capture circuitry is much too sensitive. In retrospect, perhaps the right thing to should be to move the entire LCD data bus elsewhere, say, to the mostly-unused SPI pins (I had intentionally left them unused so we could use In-System Programming and for a future expansion to use SD cards as storage). But I was tired and not in the right mood for extensive resoldering, so I simply moved the
D7line to the
PD2/INT0pin. This made the bit manipulation in the LCD routines a bit clumsy and ruined I plan I was entertaining to use INT0 as a second serial to get measurements from my UT60E serial-capable multimeter and add a very accurate self-calibration system. Anyway, after that quick kludgy fix, everything worked just fine. Gotta remember that when designing the printed circuit board. I also added the 24C512, a 512 kibibit (64KiB x 8bits) TWI ("two-wire interface", the name Atmel uses because I2C is trademarked) EEPROM chip. The TWI bus requires pullup resistors, but I didn't bother to add them because we could use internal pullups in the AVR pins. While I was in the development cycle (write-burn-test) of the interrupt-driven TWI service routine, I spotted a potential timing problem: byte writes to the EEPROM can take up to 10ms to complete, so writing 32 bytes (the size of the data structure that represents an event) may take in excess of 320ms or almost 40 semicycles. This means if we have two events closer than 40 semicycles, we might be unable to save them. Rereading the 24C512's datasheet I found an easy solution: the chip is capable of receiving a whole 128-byte page in a single TWI bus transaction and saving the whole page within a single 10ms period. So I wrote the event storage routines like this: I created an 8-entry (256 byte) event queue in RAM. Whenever we get 4 queued events (exactly one 128-byte page), the system flushes the data to the TWI EEPROM and frees the queue entries. Four events take at least 8 semicyles to happen (one event start and one event finish four times in consecutive semicycles), but with this page write feature, we can flush 4 pending events at a time to the EEPROM in less than 15ms (the 10ms EEPROM time plus bus transmission time) or two semicycles. In other words, we can store events four times faster than they are generated, which allows us to cope with fast event trains. The excess 128 bytes in the queue takes care of buffering events in case the EEPROM is busy writing a previous page or recalling event data. This also means that it should be safe to use an EEPROM chip with smaller page size as long as the store-to-generate speed ratio is grater than one. The 24C256 (32KiB x 8), with a 64-byte page, should be usable, yielding slightly more than 2-to-1. The 24C128 (16KiB x 8) however, with a 32-byte page, yields just slightly better than 1-to-1, which is uncomfortably close to critical but possibly doable (newer EEPROMs have faster page write times, sometimes as low as 5ms). But the same argument says that 64-kibibit EEPROMs or smaller will probably get us into trouble. Here's the version 0.4 firmware with the following added features:
event: with no arguments tells how many stored events we have; with a numeric argument recalls and prints that event;
clear: clear all stored events (zeroes the counters, actually, so data gets gradually overwritten);
param: with a single argument, displays parameter value. With two arguments, sets value;
start: artificially starts an event: the elapsed time counter starts and the current value of the RTC is copied to the event start time. Argument is the event type;
finish: finish an event, flusing it to EEPROM when we fill a page;
poke: specify address and value to write it directly to the TWI EEPROM;
fill: specify start address, fill value and increment. Fills a single TWI EEPROM page;
dump: specify start address and optional size. Dumps data in hex.
0: Bit mapped flags:
1: Frequency variations also generate events;
2: Voltage sags or surges also generate events;
1: Raw ADC minimum value for power failure: if less than this, start a new power failure event. If more than this, cancel a power failure event if one was in effect;
2: Raw ADC minimum value for voltage sag: if less than this but more than the value at parameter 1, we increment the "sag_semicycles" counter;
3: Raw ADC maximum value for voltage surge: if more than this, increment the "surge_semicycles" counter;
4: Raw ICR mininum value: if less than this, increment the "high frequency semicycles" counter;
5: Raw ICR maximum value: if more than this, increment the "low frequency semicycles" counter;
6: Beeps for this many millisseconds when power fails
7: Beeps for this many millisseconds when power comes back;
8: Beeps for this many millisseconds on power sags;
9: Beeps for this many millisseconds on power surges;
10: Beeps for this many millisseconds on low frequency;
11: Beeps for this many millisseconds on high frequency.