Some of you may have seen my tutorials at http://www.gooligum.com.au/tutorials.html Anyway, in finishing off one last example in my latest lesson, I got stumped for a couple of nights. I'd done a lesson (not yet uploaded) on the dual comparator module in the 16F684, using assembler. The final example demonstrates wake-up on comparator change using both comparators, where a common input is compared against low and high thresholds, and if either is crossed while the PIC is in sleep mode, the device wakes and the offending condition (too high or low) is indicated by an LED (high or low), until the condition clears and the PIC goes back to sleep. Very simple code, which worked perfectly. Then I did the HI-TECH C version, for the equivalent "C" lesson. The "indicate bad condition and wait until it clears" part of that code, logically exactly equivalent to the (working) assembler version, is as simple as: while (C1OUT) // while input (C2IN+) < low threshold (C1IN-) RC3 = 1; // light "low" LED while (C2OUT) // while input (C2IN+) > high threshold (C2IN-) RC2 = 1; // light "high" LED After getting through here, unless the input is changing very very quickly (low to high in a few us), at this point we can say that it's no longer too high or low, so both LEDs are turned off, the comparator mismatch is cleared by reading CMCON0, the interrupt flags are cleared, and off we go to sleep - and if the input is bouncing around, the device will wake, restart the main loop, and this snippet of code will light the appropriate LED and wait until the signal is back between thresholds. That's the theory, and the assembler version worked perfectly. But in the HI-TECH PICC-Lite version, only the "low" LED would light, after an input change woke the PIC from sleep. The example circuit uses an LDR/resistor divider on C2IN+, with a high voltage corresponding to bright light. So - with the C version, shining a light on the LDR would not appear to do anything, while putting the LDR in shadow would turn on the "low" LED, as it should. And yet, in the assembler version, both "high" and "low" worked equally well. I couldn't figure it out. I looked at the disassembler output, and it all seemed correct and very nice code (I used the 16F684 precisely because it's supported by PICC-Lite, which generates fully optimised code). In fact, the code was shorter than my hand-written assembler version, which included unnecessary 'banksel' directives - because the only registers being accessed are CMCON0 (to read C1OUT and C2OUT) and PORTC, which are in the same bank. This turns out to be the key factor, but it took me ages to figure out. What do you do when your code doesn't work? Debug, of course. So I whipped out my 16F684 ICD header, single stepped and set breakpoints (but only simple ones are supported on the 16F684, with an ICD 2) - and it all worked perfectly! I watched the comparator outputs changing correctly. Saw the interrupt flags being set. Set a breakpoint on "RC2 = 1", which is only run when the device wakes after the high threshold is crossed - and lo and behold, I'd shine a light on the LDR and the "high" LED would come on. But let it run without the breakpoint - nothing. Not visible, anyway. So, when my trusty ICD 2 fails me, how about simulation? I dove into MPLAB SIM, made a workbook to produce every condition I could think of, and all worked perfectly in simulation. Aargh! Then it finally hit me. The difference between single stepping, or stopping on a breakpoint, and full speed running, is speed. PICC-Lite had generated more efficient, and faster, code than my assembler version. Despite having written about read-modify-write in my tutorials, I didn't see that anything like that applied here. In theory, lighting an LED attached to PORTC will not affect an analog input on PORTC (C2IN+ in this case, on RC0). And because in theory there is no such effect, the simulator won't show it. What was happening was that, when the input on C2IN+ went high, the PIC would wake, the C2OUT bit would (correctly) be set, and the "while (C2OUT)" statement correctly saw this condition and ran the following "RC2 = 1", turning on the "high" LED. That's why, when I had a breakpoint set on that line, execution stopped, as expected, with that LED lit. But - turning on an LED means that PORTC has to suddenly supply more current. Now, in theory, even if the extra current drags down the Vdd supply, both the C2IN+ input and the reference on C2IN- are generated by a voltage divided from Vdd, and everything should remain proportional, any affect applying to both C2IN+ (RC0) and C2IN- (RC1), so the comparator output shouldn't change. But theory isn't practice, because, immediately after turning on the LED on RC3, C2OUT no longer read as "high". So the test failed the next time around the loop, and the LED was turned off almost immediately after being turned on - too fast for me to see, but not too fast for a breakpoint to pick up. What was making the assembler version work was the "unnecessary" banksel directives. So to make the C version work, I had to add a small delay: while (C1OUT) // while input (C2IN+) < low threshold (C1IN-) { RC3 = 1; // light "low" LED DelayUs(2); // 2 us delay to settle port } while (C2OUT) // while input (C2IN+) > high threshold (C2IN-) { RC2 = 1; // light "high" LED DelayUs(2); // 2 us delay to settle port } Live and learn, I guess. I'm posting this in case anyone else can learn from my experience! Regards, David Meiklejohn -- http://www.piclist.com PIC/SX FAQ & list archive View/change your membership options at http://mailman.mit.edu/mailman/listinfo/piclist