Monday, December 13, 2010

Affected by electrical noise pollution

Several months ago I described a problem with transients affecting the PIR motion detection circuit. A 0.01uF monolithic capacitor was eventually installed at GP3 of the PIC 10F202 MCU. This markedly reduced false triggering of the circuit.

Recently, a newly repaired 2x40W fluorescent lamp which is within a meter or two of the PIR circuit has been causing the MCU to reset (program counter PC is zeroed) almost every time it is switched on, but not when turned off. I speculated that the transients produced by the fluorescent's starting circuit (starter and ballast) might be tripping the MCLR (GP3) pin, causing the resets.

To check whether the MCLR pin was experiencing any abnormal voltages, that pin was monitored using a Fluke 87V set to measure VDC with Min-Max turned on and set to Peak detect (250µsec response time). The fluoro lamps were switched on and off several times. Results showed that the voltage at GP3 was within normal range of zero to 3.3V.

I then rechecked the 5VDC power supply (which was already checked months back and showed no problem). With the same meter and settings the voltage at the power supply pin of the MCU was monitored. Voltage was within normal range.

Voltage at GP2--which is connected to the mode switch--was then checked. It measured a peak maximum 1.243V and peak minimum of -0.030V. The expected value is zero volts with mode switch at its default auto position. Apparently, transients were affecting this pin. Any appreciable length of conductor (more than 5cm) has the potential of capturing and conducting EMI. And the two-wire #22 SPT fixture cable going from the circuit board to the mode switch is around a meter long. So this could explain the nonzero voltage measured at GP2. To try and address this, a 0.1uF monolithic capacitor was installed from GP2 to ground. The lamps were then switched on and off several times. The recorded peak max and peak min values were: 0.080V and -0.018V. With the 0.1uF capacitor no further MCU resets were observed.

I'm curious as to the actual peak voltages impressed upon GP2. I have my doubts whether the Fluke 87V is fast enough, even with its stated 250µs response time, to capture the glitches. The 10F202's spec sheet says the I/O pins can withstand a voltage down to -0.3VDC and so the no-capacitor voltage readings of -0.03 to 1.2VDC shouldn't cause any problems. However, according to the spec sheet as well, GP2 is TTL when configured as input, and the undefined range is between 0.8 and 2.0VDC. The measured peak max of 1.24V is right smack in this badland. I might just do another round of tests using a digital oscilloscope and capture the transients. I'm really curious as to their frequency and amplitude.

On the firmware end, since the reset isn't being caused by a MCLR, I'm suspecting a WDT timeout. I will have to pore over the code and figure out how that might occur.

Thursday, October 7, 2010

These are going to be among my favorite PICks

Product brochure for the PIC 12F/16F18xx. Problem with these chips is that there's hardly any C compiler for them. As far as I know Microchip's own Hi Tech C doesn't support any of them yet. Can somebody please kick their butts?

Thursday, September 30, 2010

Hi-Tech C vs mikroC Pro

Just out of curiosity I compiled a small sample program on Hi-Tech C for PIC18 v9.63L3 and mikroC Pro v4.10 freeware version. Target MCU was a PIC18F2321. Hi-Tech was used within Microchip's MPLAB IDE v.8.30. Hi-Tech's Omniscient Code Generation (OCG) is on (for the duration of the 45-day eval period). I set the mikroC optimization level to 5 (the maximum).

According to the compilers the Hi-Tech version took up 84 bytes of Flash while the mikroC required 122 bytes. Both compilers used only 2 bytes of RAM. Apparently Hi-Tech wins by a mile, at least in this particular test.

Here's the C program I fed both compilers:

#define  int8    unsigned char

void InitRegisters()
{
  IRCF1 = 1;
  ADCON1 = 0b1111;           // turn all analog inputs into digital

  PORTA = 0;
  PORTB = 0;
  PORTC = 0;
  TRISA = 0;
  TRISB = 0;
  TRISC = 0;
}

void OnLoad(int8 *salad)
{
  *salad = 0xFF;
}

void OffLoad(int8 *greens)
{
  *greens = 0;
}

// ====================================================================
//     main
// ====================================================================

void main()
{
  InitRegisters();

  while(1)
  {
    if (PORTC)
      OffLoad(&PORTC);
    else
      OnLoad(&PORTC);
  }  // while (1)
}  // main


Here's the disaasembly listing by Hi-Tech:
1:                 /*
2:                 
3:                 sandbox
4:                 compiler = Hi Tech 
5:                 
6:                 */
7:                 
8:                 #include  
9:                 
10:                __CONFIG (1, INTIO & FCMDIS & IESODIS);
11:                __CONFIG (2, PWRTDIS & BORDIS & WDTDIS & WDTPS4);
12:                __CONFIG (3, PBDIGITAL & LPT1DIS & MCLRDIS);
13:                __CONFIG (4, XINSTDIS & STVRDIS & LVPDIS & DEBUGDIS);
14:                __CONFIG (5, 0xFFFF);                                      // write protect disabled
15:                __CONFIG (6, 0xFFFF);            // write protect disabled
16:                __CONFIG (7, 0xFFFF);                                      // write protect disabled
17:                
18:                
19:                #define  int8    unsigned char
20:                
21:                // ====================================================================
22:                //     Global variables and enumerations
23:                // ====================================================================
24:                
25:                
26:                
27:                
28:                // ====================================================================
29:                //      Functions
30:                // ====================================================================
31:                
32:                void InitRegisters()
33:                {
34:                  IRCF1 = 1;
  1FC8    8AD3     BSF 0xfd3, 0x5, ACCESS
35:                  ADCON1 = 0b1111;           // turn all analog inputs into digital
  1FCA    0E0F     MOVLW 0xf
  1FCC    6EC1     MOVWF 0xfc1, ACCESS
36:                
37:                  PORTA = 0;
  1FCE    6A80     CLRF 0xf80, ACCESS
38:                  PORTB = 0;
  1FD0    6A81     CLRF 0xf81, ACCESS
39:                  PORTC = 0;
  1FD2    6A82     CLRF 0xf82, ACCESS
40:                  TRISA = 0;
  1FD4    6A92     CLRF 0xf92, ACCESS
41:                  TRISB = 0;
  1FD6    6A93     CLRF 0xf93, ACCESS
42:                  TRISC = 0;
  1FD8    6A94     CLRF 0xf94, ACCESS
43:                }
  1FDA    0012     RETURN 0
44:                
45:                void OnLoad(int8 *salad)
46:                {
47:                  *salad = 0xFF;
  1FBC    C000     MOVFF 0, 0xfe9
  1FBE    FFE9     NOP
  1FC0    C001     MOVFF 0x1, 0xfea
  1FC2    FFEA     NOP
  1FC4    68EF     SETF 0xfef, ACCESS
48:                }
  1FC6    0CFF     RETLW 0xff
49:                
50:                void OffLoad(int8 *greens)
51:                {
52:                  *greens = 0;
  1FB0    C000     MOVFF 0, 0xfe9
  1FB2    FFE9     NOP
  1FB4    C001     MOVFF 0x1, 0xfea
  1FB6    FFEA     NOP
  1FB8    6AEF     CLRF 0xfef, ACCESS
53:                }
  1FBA    0C00     RETLW 0
54:                
55:                // ====================================================================
56:                //     main
57:                // ====================================================================
58:                
59:                void main()
60:                {
61:                  InitRegisters();
  1FDC    ECE4     CALL 0x1fc8, 0
  1FDE    F00F     NOP
62:                
63:                  while(1)
  1FFE    D7F0     BRA 0x1fe0
64:                  {
65:                    if (PORTC)
  1FE0    5082     MOVF 0xf82, W, ACCESS
  1FE2    E007     BZ 0x1ff2
66:                      OffLoad(&PORTC);
  1FE4    0E82     MOVLW 0x82
  1FE6    6E00     MOVWF 0, ACCESS
  1FE8    0E0F     MOVLW 0xf
  1FEA    6E01     MOVWF 0x1, ACCESS
  1FEC    ECD8     CALL 0x1fb0, 0
  1FEE    F00F     NOP
  1FF0    D7F7     BRA 0x1fe0
67:                    else
68:                      OnLoad(&PORTC);
  1FF2    0E82     MOVLW 0x82


Disassembly listing by mikroC:
;  LST file generated by mikroListExporter - v.2.0 
; Date/Time: 9/30/2010 8:21:34 PM
;----------------------------------------------

;Address Opcode         ASM
0x0000        0xF000EF2D          GOTO        90
0x0004        0x0000              NOP
0x0006        0x0000              NOP
0x0008        0xF000EF00          GOTO        0
0x000C        0x0000              NOP
0x000E        0x0000              NOP
0x0010        0x0000              NOP
0x0012        0x0000              NOP
0x0014        0x0000              NOP
0x0016        0x0000              NOP
0x0018        0xD7F3              BRA         0
_OnLoad:
;sandbox18F.c,36 ::                 void OnLoad(int8 *salad)
;sandbox18F.c,38 ::                 *salad = 0xFF;
0x001C        0xFFE1C015          MOVFF       FARG_OnLoad_salad, FSR1L
0x0020        0xFFE2C016          MOVFF       FARG_OnLoad_salad+1, FSR1H
0x0024        0x0EFF              MOVLW       255
0x0026        0x6EE6              MOVWF       POSTINC1 
;sandbox18F.c,39 ::                 }
0x0028        0x0012              RETURN      0
; end of _OnLoad
___CC2DW:
;__Lib_System.c,21 ::                 
;__Lib_System.c,23 ::                 
_CC2DL_Loop1:
;__Lib_System.c,24 ::                 
0x002A        0x0009              TBLRD*+
;__Lib_System.c,25 ::                 
0x002C        0xFFE6CFF5          MOVFF       TABLAT, POSTINC1
;__Lib_System.c,26 ::                 
0x0030        0x0600              DECF        R0, 1, 0
;__Lib_System.c,27 ::                 
0x0032        0xE1FB              BNZ         _CC2DL_Loop1
;__Lib_System.c,28 ::                 
0x0034        0x0601              DECF        R1, 1, 0
;__Lib_System.c,29 ::                 
0x0036        0xE1F9              BNZ         _CC2DL_Loop1
;__Lib_System.c,31 ::                 
0x0038        0x0012              RETURN      0
; end of ___CC2DW
_OffLoad:
;sandbox18F.c,41 ::                 void OffLoad(int8 *greens)
;sandbox18F.c,43 ::                 *greens = 0;
0x003A        0xFFE1C015          MOVFF       FARG_OffLoad_greens, FSR1L
0x003E        0xFFE2C016          MOVFF       FARG_OffLoad_greens+1, FSR1H
0x0042        0x6AE6              CLRF        POSTINC1 
;sandbox18F.c,44 ::                 }
0x0044        0x0012              RETURN      0
; end of _OffLoad
_InitRegisters:
;sandbox18F.c,23 ::                 void InitRegisters()
;sandbox18F.c,25 ::                 OSCCON.IRCF1 = 1;
0x0046        0x8AD3              BSF         OSCCON, 5 
;sandbox18F.c,26 ::                 ADCON1 = 0b1111;           // turn all analog inputs into digital
0x0048        0x0E0F              MOVLW       15
0x004A        0x6EC1              MOVWF       ADCON1 
;sandbox18F.c,28 ::                 PORTA = 0;
0x004C        0x6A80              CLRF        PORTA 
;sandbox18F.c,29 ::                 PORTB = 0;
0x004E        0x6A81              CLRF        PORTB 
;sandbox18F.c,30 ::                 PORTC = 0;
0x0050        0x6A82              CLRF        PORTC 
;sandbox18F.c,31 ::                 TRISA = 0;
0x0052        0x6A92              CLRF        TRISA 
;sandbox18F.c,32 ::                 TRISB = 0;
0x0054        0x6A93              CLRF        TRISB 
;sandbox18F.c,33 ::                 TRISC = 0;
0x0056        0x6A94              CLRF        TRISC 
;sandbox18F.c,34 ::                 }
0x0058        0x0012              RETURN      0
; end of _InitRegisters
_main:
;sandbox18F.c,50 ::                 void main()
;sandbox18F.c,52 ::                 InitRegisters();
0x005A        0xDFF5              RCALL       _InitRegisters
;sandbox18F.c,54 ::                 while(1)
L_main0:
;sandbox18F.c,56 ::                 if (PORTA)
0x005C        0x5280              MOVF        PORTA, 1 
0x005E        0xE006              BZ          L_main2
;sandbox18F.c,57 ::                 OffLoad(&PORTA);
0x0060        0x0E80              MOVLW       PORTA
0x0062        0x6E15              MOVWF       FARG_OffLoad_greens 
0x0064        0x0E0F              MOVLW       hi_addr(PORTA)
0x0066        0x6E16              MOVWF       FARG_OffLoad_greens+1 
0x0068        0xDFE8              RCALL       _OffLoad
0x006A        0xD005              BRA         L_main3
L_main2:
;sandbox18F.c,59 ::                 OnLoad(&PORTA);
0x006C        0x0E80              MOVLW       PORTA
0x006E        0x6E15              MOVWF       FARG_OnLoad_salad 
0x0070        0x0E0F              MOVLW       hi_addr(PORTA)
0x0072        0x6E16              MOVWF       FARG_OnLoad_salad+1 
0x0074        0xDFD3              RCALL       _OnLoad
L_main3:
;sandbox18F.c,60 ::                 }  // while (1)
0x0076        0xD7F2              BRA         L_main0
;sandbox18F.c,61 ::                 }  // main
0x0078        0xD7FF              BRA         $+0
; end of _main

Tuesday, September 28, 2010

The PIC16F1827: an inexpensive, fully loaded MCU

I'm excited about the PIC16F1827 because it's packed with peripherals, has five! timers, has an internal clock with a maximum frequency of 32MHz, and yet is no more expensive than other 18pin PIC16s. I want a tube of these!

Just my luck though. I'll have to wait. I try and obtain all my PICs from Microchip Direct, but the 1827 won't be available till the end of this year (extended temperature PDIP is on stock, however). RS Components has none either. Farnell has stocks but comes out way pricier. 

Hardware aside, I have no plans on programming this chip using assembly. So I need a C compiler. You'd expect Microchip's compiler division would have a compiler ready once the chip is out, but even with the acquisition of Hi Tech it has yet to support the 1827. That's rather strange. The just released MikroC Pro v4.10 does support the MCU and several other enhanced PIC16s. BoostC by SourceBoost also recognizes the 1827. 

Guess I'll be playing with this MCU early next year.

Friday, September 24, 2010

On the blink

James Bryant of Analog Devices and his dirty dozen ways for circuits to fail.

The PIR circuit I recently installed has been challenging me. Just two days after it was installed it began to at times fail to switch the load on even if the PIR sensor was detecting motion (I know because the LED had turned on, ergo, PIR output was high). The fault was infrequent and usually occurred the first time the pantry was accessed in the morning--circuit must be too groggy to start the day. After days of checking and monitoring supply voltages (and finding nothing wrong with them), I decided to reprogram the MCU. The problem disappeared. Could've been an intermittent contact problem--which was licked when I removed the MCU and reinserted it--or it could've been a bad burn of the firmware.

Another problem which was noticed along with the above has yet to be resolved. When the dining room lights are turned off, the pantry light sometimes switches on. This occurs probably once every couple of dozen switchings. Rather obviously transients in the power line from switching off four conventionally ballasted plug-in type 11-watt compact fluorescent lamps are falsely triggering the circuit. I've already monitored MCU VDD using the Min-Max with Peak detect feature of the Fluke 87V for some 24hours and found the voltage to be from 4.930V to 5.048V, so no problem there. On the other hand, given the cable length to the PIR module of some 40cm, the problem may lie there. That's No.5 in Bryant's list. I've been mullling where in the sensor circuit to install additional bypass/decoupling caps. May have to put one at the VDD of the module and another at the MCU input pin (GP3); 0.1 to 1uF for the former and 10 to 100nF for the latter.

Wednesday, September 22, 2010

An important pointer on using mikroC with PIC18s

After half a day of trying to get it to work I nearly gave up. Was trying out C pointers using an old version of mikroC on a Microchip PIC18F2321. Here's the test program (to preclude clutter I've removed the initialization routines for OSCCON, PORTx, TRISx, and ADCON1 registers):

void OnLoad(unsigned char *salad)
{
  *salad = 0xFF;
}

void OffLoad(unsigned char *greens)
{
  *greens = 0;
}

void main()
{
  while(1)
  {
    OnLoad(&PORTC);    
    Delay_100ms();
    OffLoad(&PORTC);
    Delay_100ms();
  }
}  

The firware merely toggles PORTC on and off every tenth of a second. An LED is connected to one of the PORTC pins, so it should blink when the MCU is powered up. Well, it didn't work.

After a couple of hours of racking my brain and trying out variations on the program, I decided to test the code on a PIC 16F device. I inserted a PIC12F615 into the breadboard, plugged in an LED and resistor, and hooked up the PICKit 2. Opened a new project in mikroC and used the same program, changing PORTx to GPIO, and initializing the appropriate SFRs. Guess what? Worked the first time around. No problems. That told me there's nothing wrong with the program. Went back to the PIC18.

After several more hours of checking and hair-pulling, it occured to me that there might be something in the MCU configuration bits which hasn't been set properly. Referring to the datasheet, the only one that seemed relevant was the XINST (Extended Instruction Set enable) bit in configuration word CONFIG4L. Noting that according to the datashet it's off by default, I first enabled it. I compiled the firmware, uploaded to the MCU, and powered it up. Nothing. The program still wouldn't work. Went back to mikroC, unchecked the "XINST_ON_4L" box and checked "XINST_OFF_4L."

Hallelujah! The LED finally started blinking, and at the proper rate at that. Finally found the culprit! Just to make sure it was indeed the XINST bit, I enabled it again. Sure enough the program failed again. Disabling XINST once more and the firmware worked. As a final test, I unchecked both these boxes (it was in that condition before I fiddled around with the XINST) and uploaded the compiled code. It didn't work. Therefore, regardless of what Microchip says about the default condition of the configuration words, it is quite clear that they must be explicitly set in mikroC.

So there. A nasty little trap which MikroElektronika does not state in their manual. Beware.

Monday, September 20, 2010

Fluke face to face with Kryptonite

Australian electronics engineer Dave Jones proves that the Fluke 87V DMM goes haywire in the presence of GSM.



Much as I'd like to see this fault for myself, I simply cannot afford to fry my 87V. Instead I used a Fluke 117 as the lab rat. Apparently, the cheapo doesn't even know what a cell phone is. Barely a reaction and not a hint of malfunction.

This GSM susceptibility is yet another item in the list of disappointments I have with the 87V. First and foremost is its unforgivably flimsy 9V battery connector. It's no different from those found in China made toys!


I cannot imagine how Fluke could have blundered something as basic as this. My old Sanwa DMM had a far more superior battery-compartment-connector system. You unscrew the battery compartment at the back of the meter, remove it, flip it over and insert the battery into it, and then plug the whole thing back into the meter body and screw tight. Once inserted the battery terminals automatically make contact with metal prongs inside the meter. Absolutely great design! Now why couldn't Fluke have made something similar with this model? It's already the Series 5!

They certainly did it right on the Fluke 117:



Next on the list, and one that puts me off whenever I notice it is the LCD. For some reason Fluke seems to have sacrificed the viewing angle exactly perpendicular to the unit. When looking straight down the segments have rather poor contrast--not as black--as when looking at an angle. At first I thought my unit was faulty, but I've checked another brand new 87V and an 83V and their LCDs both have the same characteristic. And the batteries are still fresh so it's not a low voltage problem. I was never annoyed with the display of my old Sanwa so I guess it didn't have this quirk. Testing the 87V, the LCD is a  6:00 type with a bias angle somewhere between 20 and 30°. The readout is still tolerable even at 60°.