Electrical – pic12F683 not behaving as expected

mplabxpic

I have this weird problem. When one part of the code is enabled, my GP4 pin can be used as an output to control a relay. It is toggled to 0 and 1 based on a variable that is switched from 0 to 1.

I bit banged a DS18b20 chip to get temperature readings. It works. I can check using an analogic analyzer or my oscilloscope that data is getting through.

The problem that I have is both of these part of the code works independently. The temperature is read on GP5 and the relay controlled through GP4. GP4 is always an output.

The problem arise when I try to read the temperature and control the relay at the same time. When I do that, GP4 is only raised to 1 for a 1us or less. And at the same time, reading temperature seems to stop working. But I could have solved this already.

schematic

simulate this circuit – Schematic created using CircuitLab

I was wondering if there was some limitation on the chip that makes it unable to keep the GP4 pin as an output and high. I don't use any interrupt and each part of the code touch the TRIS bits they need without overriding the whole register.

Here's a snippet of main code.

#define _XTAL_FREQ 8000000L

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>
#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */
#include "onewire.h"

void main(void)
{
    ConfigureOscillator();

    TRISIObits.TRISIO5 = 0;
    TRISIObits.TRISIO4 = 0;

    struct OneWire ow;

    ow_reset(&ow);
    ow_search(&ow);

    __delay_ms(1);

    float real_temp = 0;
    bool ok = true;
    uint8_t res;
    GP4 = 1;

    while(1)
    {
        __delay_ms(1);

        ow_start_conversion(&ow);

        __delay_ms(1000);

        real_temp = ow_read_temperature(&ow) / 16.f;

        if (ok) {
            GP4 = 1;
        } else {
            GP4 = 0;
        }
        ok = ok ^ true;
    }
}

If I remove all lines related to OneWire the relay can be controlled. Thought the one wire par isn't changing GP4 or TRISbits for GP4. The OW library is written by me based on the Arduino one.

I read somewhere that there was a limit of function call and and some limit on the stack. I'm wondering if it's not some kind of issue that the compiler just doesn't pick and when I'm using both part of the code I go above the limits.

With that current code, the compiler tells me I'm using around 80%-90% of the code space and ram space.

Also the libraries were moved to individual libraries and unfortunately mplabx doesn't seem to be able to debug "libraries project". It could be an issue too.

I'm a bit confused as to why both "feature" work independently but together they fails.

This works:

#define _XTAL_FREQ 8000000L

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>
#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */
#include "onewire.h"


void main(void)
{
    ConfigureOscillator();

    TRISIObits.TRISIO5 = 0;
    TRISIObits.TRISIO4 = 0;

    float real_temp = 0;
    bool ok = true;
    uint8_t res;
    GP4 = 1;

    while(1)
    {
        __delay_ms(1000);

        if (ok) {
            GP4 = 1;
        } else {
            GP4 = 0;
        }
        ok = ok ^ true;
    }
}

And this works:

#define _XTAL_FREQ 8000000L

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>
#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */
#include "onewire.h"

void main(void)
{
    ConfigureOscillator();

    TRISIObits.TRISIO5 = 0;
    TRISIObits.TRISIO4 = 0;

    struct OneWire ow;

    ow_reset(&ow);
    ow_search(&ow);

    __delay_ms(1);

    float real_temp = 0;
    bool ok = true;
    uint8_t res;
    GP4 = 1;

    while(1)
    {
        __delay_ms(1);

        ow_start_conversion(&ow);

        __delay_ms(1000);

        real_temp = ow_read_temperature(&ow) / 16.f;
    }
}

I'll be able to show some screen from the oscilloscope later or from the logic analyzer.

Edit:

Configuration settings:

// CONFIG
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown Out Detect (BOR disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

And the Oscillator settings:

IRCF0 = 1;
IRCF1 = 1;
IRCF2 = 1;

After changing the first __delay_ms in the loop to 2sec, I can see my relay turning on for 2sec and before that it would be high for 1ms as the delay_us was configured to. Temperature capture works but the relay gets low (GP4) as soon as the GP5 pin is turned as input or its output changes.

uint8_t ow_read_bit(struct OneWire* self) {
    uint8_t r;
    GP5 = 0;
    TRISIO5 = 0;
    __delay_us(3); // 3
    TRISIO5 = 1;
    __delay_us(10); // 10
    r = GP5;
    __delay_us(53); //53
    return r;
}

void ow_write_bit(struct OneWire* self, uint8_t value) {
  if (value & 1) {
      GP5 = 0;
      TRISIO5 = 0;
      __delay_us(6); // 6
      GP5 = 1;
      __delay_us(64); // 64
  } else {
      GP5 = 0;
      TRISIO5 = 0;
      __delay_us(60); // 60
      GP5 = 1;
      __delay_us(5); // 10
  }
}

uint8_t ow_reset(struct OneWire* self) {
    uint8_t res = 0;
    uint8_t retries = 255;
    TRISIO5 = 1;

    do {
        if (--retries == 0) return 0;
        __delay_us(1);
    } while(!GP5);

    GP5 = 0;
    TRISIO5 = 0;
    __delay_us(480); // 480
    TRISIO5 = 1;
    __delay_us(125); //25
    res = GP5;
    __delay_us(410); // 410
    return res;
}

Those are the three methods in play that read/write to the DS18B20, no other function touches the TRIS bits or GP5.

EDIT2:

A fix, I added a check after the ow_start_conversion that reset GP4 whatever the value of ok was and added a cap between the base/vdd of the the transistor. It is just enough to prevent the transitor to turn off and the relay can be up continuously. It doesn't really fix the issue as why GP4 goes low but the relay can be controlled as expected. In my more complex setup, the pin is controlled by a PID and it does work. So I see that the chip isn't reset from there.

Also GP4 goes low everytime GP5 and TRISIO5 are changed.

Best Answer

I finally found the problem... This is weird considering the Datasheet says that any pin set as analog will still work as digital output (which is what GP4 is).

I finally found while testing on the simulator that my GP4 pin was set as a AnalogOUT. I set the ANSEL.ANS3 bit to 0 to make it a digital pin and now the GP4 is working as expected. No need for the "reset" hack and the GP4 is always kept to 1 no matter what happen on the other pins.