Thursday, July 7, 2011

Vexing silicon bug on the PIC12F1822

Been having a problem with a firmware which uses the analog-to-digital converter (ADC) of the PIC12F1822 to read the buffered voltage output of a sensor. The circuit works for some time but then minutes or hours later goes amok. I've gone over the firmware half a dozen times and I can't find anything wrong. (That of course is no guarantee that the program has no coding errors. I may just be "blind" to the booboos I've committed.) 

While testing the circuit and observing the hiccups, it looked to me--among other possibilities--that the watchdog timer (WDT) was timing out--that it wasn't being cleared and thus the MCU was being reset. Sure enough when I disabled the WDT the MCU would hang and the push button and LED would fail to respond. Something was very wrong indeed. It was then that it occurred to me to check the silicon errata sheet for this device.

When I saw item number two on the rather obscenely long list of bugs I had an "Oh shoot!" moment. According to Microchip
Under certain device operating conditions, the ADC conversion may not complete properly. When this occurs, the ADC Interrupt Flag (ADIF) does not get set, the GO/DONE bit does not get cleared and the conversion result does not get loaded into the ADRESH and ADRESL result registers.
Two workarounds are listed:
Method 1: Select the dedicated RC oscillator as the ADC conversion clock source, and perform all conversions with the device in Sleep.

Method 2: Provide a fixed delay in software to stop the A-to-D conversion manually, after all 10 bits are converted, but before the conversion would complete automatically. The conversion is stopped by clearing the GO/DONE bit in software. The GO/DONE bit must be cleared during the last ½ TAD cycle, before the conversion would have completed automatically. Refer to Figure 1 for details.
The firmware uses mikroC's built-in ADC function and checking the assembly of the compiled program it's clear that the function is polling the GO/DONE bit to determine whether conversion is finished or not. If the silicon bug is indeed being triggered then when it does strike this polling would go on ad infinitum since the bit would never change state. To find out if this ADC bug is the cause of my woes I had to write my own ADC function to implement one of the workarounds above.

Well the part about clearing the GO/DONE bit during the last ½ TAD cycle in method 2 is a great put-off. I just don't like the idea of stopping a conversion at "just the right time." Seems too risky. So I opted for putting the MCU to sleep. Sounds simple and straightforward. Here's my version of Method 1.

unsigned int ADC(int8 ch)
  ADCON0 = ch << 2;                    // left shift ADC channel to be read from into ADCON0
  ADCON0.ADON = 1;                     // power up ADC
  ADCON1 = 0b11110000;                 // right justified, use Frc, Vdd as positive reference voltage
  INTCON.GIE = 0;                      // global interrupt disabled
  PIR1.ADIF = 0;                       // clear ADC interrupt flag
  PIE1.ADIE = 1;                       // ADC interrupt enabled
  INTCON.PEIE = 1;                     // peripheral interrupts enabled
  ADCON0.GO = 1;                       // start ADC conversion
  asm {sleep}                          // zzzzzzzzzzzzzzz.... when ADIF = 1 MCU will wake up and will continue execution of the program
  PIR1.ADIF = 0;                       // clear ADC interrupt flag
  PIE1.ADIE = 0;                       // disable ADC interrupt
  INTCON.PEIE = 0;                     // disable peripheral interrupts
  ADCON0.ADON = 0;                     // power down ADC
  return ADRESH*256 + ADRESL;          // return the 10-bit ADC value as a 16-bit number

I've been testing the circuit using the above function instead of mikroC's and so far so good. WDT is enabled and so far no resets have occurred. Will do extended testing over the week to make sure the problem has been truly licked.

[Addendum: Forgot to mention that, as per the errata sheet, the ADC bug appears only on 1822's with device revision ID#6. I did check the parts (see the errata for instructions on how to do this) I have before even attempting to write the workaround and of course as luck would have it, I had been shipped the affected components. Sigh.]

No comments:

Post a Comment