Author Topic: PIC - can't toggle GP1 and GP2  (Read 11343 times)

0 Members and 1 Guest are viewing this topic.

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
PIC - can't toggle GP1 and GP2
« on: September 08, 2015, 03:23:53 pm »
I haven't used PIC chips until now. I'm programming a pic10f200 with MPLAB X IDE v2.35. The pic10 is a very small, limited micro controller, but I just need to toggle pins with delay in a certain order. It's working fine for the gernal purpuse IO pin number 0 and 1, but 2 won't do anything. I wonder why this is. I know that GP3 is input only, but GP2 should be bi-directional. Did I do something stupid? Can you help me?

Here is a minimal verbose example:

Code: [Select]
#include <xc.h>
#pragma config CP    = OFF   // Code protection off
#pragma config MCLRE = OFF   // Master Clear Enable (GP3/MCLR pin fuction is digital I/O, MCLR internally tied to VDD)
#pragma config WDTE  = OFF   // Watchdog Timer disabled
#define _XTAL_FREQ 40000000

void main(void) {
    OPTION = 0
        |  nGPWU // 7: no wake-up on pin change
        |  nGPPU // 6: no weak pullups
        | ~T0CS // 5: internal clock
        | ~T0SE // 4: increment low to high
        | ~PSA  // 3: pre-scale for Timer0
        |  PS2 |  PS1 |  PS0 // 2-0: clock devision by 256
    ;
    OSCCAL &= ~(FOSC4);    // no clock output on GP2
    TRISGPIO = 0b00000000; // set all to out

    while(1) {
        GP0 = 1;   GP1 = 1;   GP2 = 1;   __delay_ms( 50);
        GP0 = 0;   GP1 = 0;   GP2 = 0;   __delay_ms(250);
    }
}

GP2 is connected directly to the gate of a small P-channel MOSFET that is pulled down to GND with a 12k resistor. I' measuring directly hat the gate. My intend is to have the MOSFET default to on and turn if off by pulling the gate high every once in a while.
« Last Edit: September 08, 2015, 03:34:39 pm by con-f-use »
 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #1 on: September 08, 2015, 04:06:27 pm »
Thanks! The PIC10F200 doesn't have a comparator so MPLAB doesn't even recognize the comparator register to change anything. Even the clock output you're referring to is default-off.  I just put in there to be sure. FOSC4 should be off because the timer is set for internal clock. I wouldn't know what else to turn off.
« Last Edit: September 08, 2015, 04:29:44 pm by con-f-use »
 

Offline picandmix

  • Frequent Contributor
  • **
  • Posts: 395
  • Country: gb
 

Offline Zarhi

  • Contributor
  • Posts: 24
  • Country: bg
Re: PIC - can't toggle GP1 and GP2
« Reply #3 on: September 08, 2015, 04:29:03 pm »
Set T0CS in OPTION register to 0, it defaults to 1.
 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #4 on: September 08, 2015, 04:31:22 pm »
Set T0CS in OPTION register to 0, it defaults to 1.

Yes, and it is set to 0 in this line:

Code: [Select]
| ~T0CS // 5: internal clock
This tutorial might help...
http://www.best-microcontroller-projects.com/12F675.html#Program_1_:_12F675_Flashing_an_LED
I think I'm familiar with the basics. As I said, the Code works for pins zero and one, just not for two. I don't see anything in that tutorial related to this specific problem.
« Last Edit: September 08, 2015, 04:34:12 pm by con-f-use »
 

Online macboy

  • Super Contributor
  • ***
  • Posts: 2265
  • Country: ca
Re: PIC - can't toggle GP1 and GP2
« Reply #5 on: September 08, 2015, 04:33:19 pm »
Thanks! The PIC10F200 doesn't have a comparator so MPLAB doesn't even recognize the comparator register to change anything. Even the clock output you're referring to is default-off. I just put in there to be sure. I wouldn't know what else to turn off.
What else to turn off is listed in table 5.1 as posted by AchMed99. Three function have precedence above the GPIO usage. You must ensure it is not set to output FOSC/4 by clearing bit 0 of OSCAL. You must ensure it is not used by the comparator (not an issue with this device). You must ensure it is not used as an input for Timer 0 by clearing bit T0CS of OPTION register. Then it is usable as a GPIO pin.
 

Offline Zarhi

  • Contributor
  • Posts: 24
  • Country: bg
Re: PIC - can't toggle GP1 and GP2
« Reply #6 on: September 08, 2015, 04:38:03 pm »
Well, that is assembly result from mplabx, xc 1.33

    60  005                     _main: 
    61                           
    62                           ;newmain.c: 8: OPTION = 0
    63                           ;newmain.c: 9: | 0x80
    64                           ;newmain.c: 10: | 0x40
    65                           ;newmain.c: 11: | ~0x20
    66                           ;newmain.c: 12: | ~0x10
    67                           ;newmain.c: 13: | ~0x8
    68                           ;newmain.c: 14: | 0x4 | 0x2 | 0x1
    69                           ;newmain.c: 15: ;
    70                           
    71                           ;incstack = 0
    72                           ; Regs used in _main: [wreg-fsr0h+status,2+status,0+btemp+3]
    73  005  CFF                        movlw   255
    74  006  002                        option
    75                           

So, You are setting OPTION to 0xff, which is default at power on.
 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #7 on: September 08, 2015, 04:43:38 pm »
Okay, I might be mistaking, but I thing I got all that covered...

You must ensure it is not set to output FOSC/4 by clearing bit 0 of OSCAL.

Code: [Select]
    OPTION = 0 // <--------- here is a zero to start with
        |  nGPWU // 7: no wake-up on pin change
        |  nGPPU // 6: no weak pullups
        | ~T0CS // 5: internal clock   <-------------- this ensures it's set to zero
        | ~T0SE // 4: increment low to high
        | ~PSA  // 3: pre-scale for Timer0
        |  PS2 |  PS1 |  PS0 // 2-0: clock devision by 256
    ;

You must ensure it is not used as an input for Timer 0 by clearing bit T0CS of OPTION register.

Code: [Select]
OSCCAL &= ~(FOSC4);    // no clock output on GP2

Also it is zero on power on see:

 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #8 on: September 08, 2015, 04:48:18 pm »
                   
So, You are setting OPTION to 0xff, which is default at power on.

Okay, than back to bit operators, for me.  |O

Just to double-check, it should work with

Code: [Select]
OPTION = 0b11011111;
« Last Edit: September 08, 2015, 04:51:14 pm by con-f-use »
 

Offline Zarhi

  • Contributor
  • Posts: 24
  • Country: bg
Re: PIC - can't toggle GP1 and GP2
« Reply #9 on: September 08, 2015, 05:04:14 pm »
Code: [Select]
OPTION = 0 // that 0 is not needed
        |  nGPWU // 7: no wake-up on pin change
        |  nGPPU // 6: no weak pullups
        & ~T0CS // 5: internal clock
        & ~T0SE // 4: increment low to high
        & ~PSA  // 3: pre-scale for Timer0
        |  PS2 |  PS1 |  PS0 // 2-0: clock devision by 256
;

Looking at cpu header file help allways ( in Your case pic10f200.h, look in xc8 installation directory )
 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #10 on: September 08, 2015, 05:16:41 pm »
Okay, thank you guys. That is what I meant to write. It was a stupid little error on my part and rather embarrassing. I've coded thousands of lines on AVRs and never made a basic bit-operations error. Sorry to have bothered you.
« Last Edit: September 08, 2015, 05:20:00 pm by con-f-use »
 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #11 on: September 09, 2015, 12:09:42 pm »
If I can bother you guys again. As an exercise in getting to grip with the C dialect that MPLAB uses, I now want to put the pic in sleep mode during the wait phases. Is that at all possible and if so, does the pic reset complete when waked by the watchdog or is there a way to preserve data between watchdog resets?

With ATTinys and ATmegas, I would just configure the watchdog to do an interrupt instead of a reset, have the uC wake from that interrupt and have the interrupt function empty. Then it would automatically resume code execution where it left of before the sleep.

So here is an idea of what I want, obviously that doesn't work:

Code: [Select]
#include <xc.h>
#pragma config CP    = OFF   // Code protection off
#pragma config MCLRE = OFF   // GP3/MCLR pin fuction is digital I/O
#pragma config WDTE  = ON    // Watchdog Timer enabled
#define _XTAL_FREQ 4000000

void main(void) {
    OPTION = 0 | nGPWU | nGPPU & ~T0CS & ~T0SE | PSA | PS2 | PS1 | PS0;    // bits: 7: no wake-up on pin change; 6: no weak pullups; 5: internal clock; 4: incremnt low to high; 3: prescale on wdt (Timer0 if cleared); 2-0: clock division by 128
    TRISGPIO = 0b00000000; // set all to output

    while(1) {
        GP0 = 1;   GP1 = 1;   GP2 = 1;   SLEEP();  // set all high and sleep a bit
        // --------> MAGICALLY CONTINUE HERE AFTER SLEEP <---------
        GP0 = 0;   GP1 = 0;   GP2 = 0;   SLEEP();  // set all low  and sleep a bit
    }
}

I find the datasheet to be a bit vague on what exactly is reset during sleep and where the entry point after sleep is. Any help is very much appreciated!



 

Offline BloodyCactus

  • Frequent Contributor
  • **
  • Posts: 482
  • Country: us
    • Kråketær
Re: PIC - can't toggle GP1 and GP2
« Reply #12 on: September 09, 2015, 12:23:10 pm »
Code: [Select]
OPTION = 0 // that 0 is not needed
        |  nGPWU // 7: no wake-up on pin change
        |  nGPPU // 6: no weak pullups
        & ~T0CS // 5: internal clock
        & ~T0SE // 4: increment low to high
        & ~PSA  // 3: pre-scale for Timer0
        |  PS2 |  PS1 |  PS0 // 2-0: clock devision by 256
;

Looking at cpu header file help allways ( in Your case pic10f200.h, look in xc8 installation directory )

that C code for setting your option looks so wrong to me. you have bitwise AND's that are not operating on what you think they are operating on. I dont think you understand how the & is working in that specific statement regarding operator precedence and LR associativity.

Code: [Select]
OPTION = nGPWU |  nGPPU |  PS2 |  PS1 |  PS0;
You could add but probably dont need

Code: [Select]
OPTION &= ~(T0CS | T0SE | PSA); after the above line.

I see you spammed this all over stack exchange as well.

-- Aussie living in the USA --
 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #13 on: September 09, 2015, 01:26:27 pm »
that C code for setting your option looks so wrong to me. you have bitwise AND's that are not operating on what you think they are operating on. I dont think you understand how the & is working in that specific statement regarding operator precedence and LR associativity.

You are completely right. My code above is a bit convoluted.
In my tests I always set it in bit-notation like `OPTION = 0b11000111` but for the Forum I thought the way above might be clearer. My bad for using something I normally don't and doing it without testing first.
But it should yield the same results, provided the Macros are single bits in an 8bit integer, which we can assume. See this example written in plain C and run on my laptop. I might still have the associativity and order wrong in my head, but at least it randomly seems to spurt out the right result.

Quote from: BloodyCactus link=topic=54764.msg750484#msg750484
I see you spammed this all over stack exchange as well.

I wouldn't say one question on a site that is made for questions, means it is "spammed all over". I asked it here again, after many hours, because it didn't get an answer and people were criticizing my choice of C as the language to use instead of either ignoring my stupid question or helping me. Here people tend to be a little more helpful.
« Last Edit: September 09, 2015, 01:51:44 pm by con-f-use »
 

Offline Zarhi

  • Contributor
  • Posts: 24
  • Country: bg
Re: PIC - can't toggle GP1 and GP2
« Reply #14 on: September 09, 2015, 02:33:01 pm »
Code: [Select]
OPTION = 0 // that 0 is not needed
        |  nGPWU // 7: no wake-up on pin change
        |  nGPPU // 6: no weak pullups
        & ~T0CS // 5: internal clock
        & ~T0SE // 4: increment low to high
        & ~PSA  // 3: pre-scale for Timer0
        |  PS2 |  PS1 |  PS0 // 2-0: clock devision by 256
;

Looking at cpu header file help allways ( in Your case pic10f200.h, look in xc8 installation directory )

that C code for setting your option looks so wrong to me. you have bitwise AND's that are not operating on what you think they are operating on. I dont think you understand how the & is working in that specific statement regarding operator precedence and LR associativity.


It "may" looks wrong, but that is resolved/calculated in C pre-processor. Assembly result is only two instructions: load 199 ( 0xc7, 0b11000111 ) to W, load W to OPTION register.

This was example how to set/clear particular bits when they are defined as bit-mask.

In this case OPTION register is set at once, ignoring it's current value, so it's enough to OR with bit-masks we want to set to 1, or AND 0xFF with ~bit-mask we want to clear. In that particular cpu OPTION register is write-only, there is no way to read it's current value.

 

Offline Maxlor

  • Frequent Contributor
  • **
  • Posts: 565
  • Country: ch
Re: PIC - can't toggle GP1 and GP2
« Reply #15 on: September 09, 2015, 02:45:42 pm »
Actually, SLEEP() works exactly like you want it to, i.e. like a pause in your program, with automagic resumption after the SLEEP() command. If you set the watchdog beforehand, it'll turn into a timed sleep (just don't forget to disable or otherwise handle the watchdog after sleeping!)

The documentation is clear enough: it says that on watchdog reset during sleep, or !MCLR reset during sleep, all registers keep their values except for these four bits: !TO, !PD, GPWUF and CWUF. They allow you to check why you woke up, whether it was the watchdog expiry, whether  !MCLR was pulled high, or whether one of the peripherals caused it. If there's only one possible wakeup source, i.e. just the watchdog, you can ignore those.
 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #16 on: September 09, 2015, 03:41:08 pm »
Then I have no idea, why my example code doesn't work and I see all the pins high all the time. Do I have to clear the watchdog somehow with an extra command?

Here is another example. It never stops blinking, although it should enter an infinite while loop where all pins are low.

I'm sure I'm missing something incredibly stupid, I just don't see what it is.
« Last Edit: September 09, 2015, 04:06:47 pm by con-f-use »
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2556
  • Country: us
Re: PIC - can't toggle GP1 and GP2
« Reply #17 on: September 09, 2015, 04:50:31 pm »
For your 1st example code, I'm having a hard time determining exactly what you tested with.  You say you posted one thing for the OPTION and tested with another thing.  Can you post exactly what you tested with?  Maybe try setting and clearing the I/O bits by setting the GPIO byte instead of the individual bits.  Maybe try this small variant:
Code: [Select]
#include <xc.h>

// PIC10F200 Configuration Bit Settings
#pragma config WDTE = OFF       // Watchdog Timer (WDT disabled)
#pragma config CP = OFF         // Code Protect (Code protection off)
#pragma config MCLRE = OFF      // Master Clear Enable (GP3/MCLR pin fuction is digital I/O, MCLR internally tied to VDD)

#define _XTAL_FREQ 4000000L     // 4MHz clock
#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))


 int main(int argc, char** argv) {
   OSCCAL = 0b11111110;
   OPTION = 0b11000111;
   TRISGPIO = 0b00000000;

   // MAIN LOOP
   while (1) {
      GPIO = 0;
      delay_ms(1000);
      GPIO = 7;
      delay_ms(1000);
   }
}


In your 2nd example code, you turned on the Watchdog Timer but never clear it in the main loop.
   The Watchdog timeout = 18 ms * 128 prescaler = 2.304 sec.
Without executing the CLRWDT(); instruction before the timeout, you MCU is resetting and starting over causing at least part of your problem.
 

Online macboy

  • Super Contributor
  • ***
  • Posts: 2265
  • Country: ca
Re: PIC - can't toggle GP1 and GP2
« Reply #18 on: September 09, 2015, 04:50:38 pm »
Then I have no idea, why my example code doesn't work and I see all the pins high all the time. Do I have to clear the watchdog somehow with an extra command?

Here is another example. It never stops blinking, although it should enter an infinite while loop where all pins are low.

I'm sure I'm missing something incredibly stupid, I just don't see what it is.
Your code example pasted here for reference:
Code: [Select]
#include <xc.h>
#pragma config CP    = OFF   // Code protection off
#pragma config MCLRE = OFF   // GP3/MCLR pin fuction is digital I/O
#pragma config WDTE  = ON    // Watchdog Timer enabled
#define _XTAL_FREQ 4000000

void main(void) {
    int ita;
    OPTION = 0b11011111;
    TRISGPIO = 0b00000000; // set all to output

    // toggle bin fast (blink)
    for(ita=0; ita<10; ++ita) {
        GP0 = 0;   GP1 = 0;   GP2 = 0;
        __delay_ms(50);
        GP0 = 1;   GP1 = 1;   GP2 = 1;
        __delay_ms(50);
    }

    // keep it high for about 2s
    GP0 = 1;   GP1 = 1;   GP2 = 1;
    __delay_ms(1000);
    __delay_ms(1000);

    // all pins low for about 20s
    while( 1 ) {
        GP0 = 0;   GP1 = 0;   GP2 = 0;
        SLEEP(); // 1.8 and 2.3s
    }
}
Consider:
The MCU can wake up in four ways (if each is enabled):
1. WDT Reset
2. MCLR Reset
3. Change in GPIO 1, 2, or 3
4. Comparator output change
You have enabled #1.
(see section 9.9.2)

Consider:
A WDT Reset or a WDT wake-up Reset will result in a device reset regardless of whether the device is running normally or sleeping. (see section 9.6)

Consider:
The reset vector is 0x000. (This is the instruction executed after a device reset. see section 4.1).

Your simple blinky code has enabled the WDT, assigned the prescaler of 128 to it, and gone to sleep. After ~ 2.3 seconds, the WDT will expire and generate a WDT wake-up Reset.

Now, why does your example code not wait forever inside the while(1) loop?
« Last Edit: September 09, 2015, 05:03:08 pm by macboy »
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2556
  • Country: us
Re: PIC - can't toggle GP1 and GP2
« Reply #19 on: September 09, 2015, 04:59:13 pm »
Check the pic10f200 errata (This seems to apply to you):
Quote
MPLAB® IDE, Revision 6.61 and Earlier
The MPLAB IDE 6.61 does not look for or set the
Configuration Word in the hex file at the
conventional logical location of 0xFFF.

Work around
The CONFIG data must be assigned in two
locations within the assembly code to ensure
proper Configuration Word placement in the hex
file. This is only required for MPLAB IDE version
6.61 and earlier.

Sorry.  I miss read your 1st post.
« Last Edit: September 09, 2015, 05:03:48 pm by MarkF »
 

Online macboy

  • Super Contributor
  • ***
  • Posts: 2265
  • Country: ca
Re: PIC - can't toggle GP1 and GP2
« Reply #20 on: September 09, 2015, 05:02:23 pm »
Without executing the CLRWDT(); instruction before the timeout, you MCU is resetting and starting over causing at least part of your problem.
Executing SLEEP will reset the WDT and its prescaler.
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2556
  • Country: us
Re: PIC - can't toggle GP1 and GP2
« Reply #21 on: September 09, 2015, 05:04:57 pm »
Without executing the CLRWDT(); instruction before the timeout, you MCU is resetting and starting over causing at least part of your problem.
Executing SLEEP will reset the WDT and its prescaler.

No.  CLRWDT()  will just restart the WDT count.  Not the prescaler.
I don't think SLEEP resets the WDT. 
See the macros in my example code.  I believe they match the Micochip versions.
His example will never reach the SLEEP instruction.  The WDT will timeout long before that.
« Last Edit: September 09, 2015, 05:10:29 pm by MarkF »
 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #22 on: September 09, 2015, 05:09:03 pm »
Okay. Thanks for all your replies, I really appreciate all the help and you're great. It's just that now you are confusing me alot.

So one guy says, the uC just continues, where it left of, the other one says (as I suspected earlier) that after a wakeup the uC resets and executes the program from the start. Now which of the two is the case? If the latter, how do I keep a bit of data after a wakeup from sleep, to have the program act differently? E.g. spend more time than one WDT timer cycle in sleep, say five and then do something new. (How) Is that at all possible?

 

Offline con-f-useTopic starter

  • Supporter
  • ****
  • Posts: 807
  • Country: at
Re: PIC - can't toggle GP1 and GP2
« Reply #23 on: September 09, 2015, 05:23:22 pm »
His example will never reach the SLEEP instruction.  The WDT will timeout long before that.

That is exceedingly correct.  :palm:

In this example with CRLWDT, the pins are actually turned off until the WDT resets the uC after about 2s. Then the program starts over again. All I did was putting CLRWDT(); in after long delays. That is a step further.

Now, can the WDT jump back into the infinite loop after reset? Or maybe can I set a variable that persists after the reset and jump into the loop? Something like that would be needed.
 

Online macboy

  • Super Contributor
  • ***
  • Posts: 2265
  • Country: ca
Re: PIC - can't toggle GP1 and GP2
« Reply #24 on: September 09, 2015, 05:35:38 pm »
Without executing the CLRWDT(); instruction before the timeout, you MCU is resetting and starting over causing at least part of your problem.
Executing SLEEP will reset the WDT and its prescaler.

No.  CLRWDT()  will just restart the WDT count.  Not the prescaler.
I don't think SLEEP resets the WDT. 
See the macros in my example code.  I believe they match the Micochip versions.
His example will never reach the SLEEP instruction.  The WDT will timeout long before that.
His code will reset before hitting the while loop, since the CLRWDT is never called, and the total of all delays is 3 seconds. A CLRWDT must be done before every delay statement. If a longer delay than 1 second is needed, it should be broken into 1 second chunks with a CLRWDT between them.

The datasheet clearly states that the SLEEP instruction resets the WDT prior to sleeping. The text of the datasheet is a little ambiguous as to what happens on SLEEP or CLRWDT, it says it will "reset the WDT" but does not elaborate. To know exactly what happens when either of these instructions are executed, refer to the instruction set summary section. Under the CLRWDT instruction, it states that the WDT timer and prescaler are cleared (page 49). Same is true under the SLEEP instruction (page 51). Also refer to 31026a.pdf which states "The CLRWDT and SLEEP instructions clear the WDT and the postscaler (if assigned to the WDT)".
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf