0
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ I don't see your configuration word settings. Did you remove them from your code before posting here? \$\endgroup\$ – Dan Laks Mar 31 '18 at 22:47
  • \$\begingroup\$ Ah you mean the configuration bits? \$\endgroup\$ – Loïc Faure-Lacroix Mar 31 '18 at 22:50
  • \$\begingroup\$ What's the actual voltage of VDD? You've got 1V in your schematic, which I'm sure is a typo. I'm assuming 5V because that's what you labeled one of the pins in the DS18B20. \$\endgroup\$ – Dan Laks Mar 31 '18 at 23:11
  • \$\begingroup\$ Yes, it's 5v I'll fix the schematic \$\endgroup\$ – Loïc Faure-Lacroix Mar 31 '18 at 23:19
1
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

Two things about your schematic stand out to me:

  1. You're floating the MCLR pin. Since you have "#pragma config MCLRE = ON", the MCLR pin (GP3) needs to be pulled high to prevent the PIC from resetting itself. A floating MCLR pin may act unpredictably or be influenced by local electric fields in its proximity.

  2. You have no bypass capacitor on the VDD and VSS pins. Bypass capacitors are necessary on any IC, including microcontrollers.

It's possible that there's some localized affect happening within the PIC when that part of the code is executing that is causing the MCLR pin to suddenly read low, thus resetting the program. A simple test would be to put a 10kOhm resistor between the MCLR pin and VDD and see if that fixes it.

Edit:
One other comment. You're sourcing about 22mA out of GP4 to drive the transistor: $$\frac{V_{DD}-V_{BE}}{R_b} = \frac{5V-0.6V}{200\Omega}=0.022A$$ The absolute maximum source current out of any one IO pin is 25mA. That's not much overhead. Further, I bet the PIC is not able to hold GP4 at 5V when it's sourcing 22mA. GP4's output is probably dipping down quite a bit, which is underdriving your transistor, and thus starving the relay coil of current. You might want to consider redesigning your drive circuit.

\$\endgroup\$
  • \$\begingroup\$ Ah, that could make sense. Wouldn'T disabling MCLR be an other fix. I didn't add a cap on between VDD and VSS because the datasheet says the pic12F can be connected as is without additional parts. But I guess adding one probably wouldn't hurt. \$\endgroup\$ – Loïc Faure-Lacroix Mar 31 '18 at 23:21
  • \$\begingroup\$ Bypass caps aren't fundamentally necessary for the PIC to power up and run a program. However, without one, you are subject to random, unpredictable behavior that is caused by the complex interactions of current flow in fast-switching microelectronics. \$\endgroup\$ – Dan Laks Mar 31 '18 at 23:27
  • \$\begingroup\$ Yes, you could disable MCLR, but it's typically recommended to keep that functionality enabled unless you're very familiar with PICs and you know what you're doing. \$\endgroup\$ – Dan Laks Mar 31 '18 at 23:30
  • 1
    \$\begingroup\$ 8-Bit PIC® Microcontroller Design Recommendations "The use of decoupling capacitors on every pair of power supply pins (VDD and VSS) is required" \$\endgroup\$ – Bruce Abbott Mar 31 '18 at 23:52
  • \$\begingroup\$ Is the abosulte maximum current a global maximum or per pin? Because I found something interesting. I realized the relay could be high only for 1ms, so I increase the first delay of the loop to 2 sec. And now the relay is up for 2sec. GP4 become low as soon as GP5 start changing. \$\endgroup\$ – Loïc Faure-Lacroix Apr 1 '18 at 0:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.