CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PIC16F1828 WDT and I2C write behaviour

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
nickdc



Joined: 19 Sep 2018
Posts: 15

View user's profile Send private message

PIC16F1828 WDT and I2C write behaviour
PostPosted: Mon Dec 02, 2019 9:55 am     Reply with quote

Hi,

My device is a PIC16F1828 and I use compiler version 5.076.
When I block PIC and then send something using I2C, the processor will freeze, causing another watchdog timeout.

These are my settings:
Code:

#fuses HS,WDT_SW,PROTECT,NOLVP,BROWNOUT,
#use delay(clock=18.432M, CRYSTAL) // xtal-frequency
#use rs232(STREAM = UART_Display, baud=115200,UART1,parity=N,bits=8, ERRORS)
#use i2c(master, scl=PIN_B6, sda=PIN_B4)


I use a string command to execute the following function:

Code:

void block(void){
    printf("\r\nStart block\r\n");
    while(TRUE){
        printf("\r\nBlocking\r\n");
        delay_ms(1000);
    }
}


After executing this function, the WDT will react and reset the device. But after this, it will timeout at executing i2c_write(byte).
I haven't found a similar topic , except this:
https://www.ccsinfo.com/forum/viewtopic.php?t=26558

This is self-contained code example that demonstrates the problem. Enter "BLOCK" into the terminal to block the PIC.

The I2C device is a MCP4725.

Code:

#include <16F1828.h>
#fuses HS,WDT,PROTECT,NOLVP,BROWNOUT
#use delay(clock=18.432M, CRYSTAL) // xtal-frequency
#use rs232(STREAM = UART_Display, baud=115200,UART1,parity=N,bits=8, ERRORS)
#use i2c(master, scl=PIN_B6, sda=PIN_B4)
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#define bkbhit (next_in!=next_out)
short newLineFlag = 0;
void block(void);

#int_rda
void serial_isr() {
    int t;
    buffer[next_in] = getc();
    if (buffer[next_in] == '\r') {
        buffer[next_in + 1] = '\0';
        newLineFlag = 1;
    }
    t = next_in;
    if (++next_in == BUFFER_SIZE) {
        next_in = 0;
    }
    if (next_in == next_out) {
        next_in = t; //Buffer full
    }
}

BYTE bgetc() {
    BYTE c;
    while (!bkbhit);
    c = buffer[next_out];
    next_out = (next_out + 1) % BUFFER_SIZE;
    return (c);
}

void block(void) {
    printf("\r\nStart block\r\n");
    while (TRUE) {
        printf("\r\nBlocking\r\n");
        delay_ms(1000);
    }
}

void parseCommand(char* text) {
#ifdef DEBUG
    printf("text: %s\r\n", text);
#endif
    int *ptrBlockFound;
    char blockCommandPrefix[6];
    blockCommandPrefix = "BLOCK";
    ptrBlockFound = strstr(text, blockCommandPrefix);
    if (ptrBlockFound != NULL) {
        printf("OK!\r\n");
        block();
    } else {
        printf("ERROR\r\n");
    }
}

void main(void) {
    switch (restart_cause()) {
        case WDT_TIMEOUT:
        {
            printf("\r\nRestarted processor because of watchdog timeout!\r\n");
            break;
        }
        case NORMAL_POWER_UP:
        {
            printf("\r\nNormal power up!\r\n");
            break;
        }
    }
    delay_ms(100);
    setup_wdt(WDT_2S);
    restart_wdt();
    setup_timer_1(T1_FOSC | T1_DIV_BY_8);
    printf("start\r\n");
    enable_interrupts(INT_RDA); //Interrupt to receive serial data (RS232 incoming)
    enable_interrupts(GLOBAL);
    char inputBuffer[BUFFER_SIZE];
    int i = 0;
    i2c_start();
    i2c_write(0xCC);
    i2c_stop();
    while (TRUE) {
        restart_wdt();
        while (bkbhit) {
            inputBuffer[i] = bgetc();
            i++;
        }
        if (newLineFlag) {
            parseCommand(inputBuffer);
            disable_interrupts(GLOBAL);
            next_in = next_out;
            int j = 0;
            while (inputBuffer[j] != '\0') {
                inputBuffer[j] = '\0';
                j++;
            }
            enable_interrupts(GLOBAL);
            i = 0;
            newLineFlag = 0;
        }
    }
}


I'm trying the option FORCE_SW now to see if it helps. It seems to work, but I don't know the reasons for why it was a problem and why this solution helps

Kind regards,
Nick


Last edited by nickdc on Mon Dec 02, 2019 10:36 am; edited 1 time in total
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 10:24 am     Reply with quote

OK, I can't see anywhere what kind of I2C peripheral you have attached to the PIC. Also, what are the I2C pullups ? If I assume a 5 volt VDD, I'll use 4K7 pullups.
Without pullups , it's possible the internal I2C section is 'locking up' ? I can't test as I don't have that PIC, it might be PIC specific ??
Those pins should be HW I2C ,so compler should NOT be using SW,just access HW registers.
Hopefully someone with that PIC can test...

Jay
nickdc



Joined: 19 Sep 2018
Posts: 15

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 10:41 am     Reply with quote

The I2C device is the MCP4725 DAC.
Connected to the SDA and SCL are two 22 ohm resistors. Vdd is 5 V.
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 10:51 am     Reply with quote

What are the pullup resistors connected to VDD ?
surely NOT 22ohms !
Are you using a chip or a module? If a module, it may have pullups ??


also
this...
i2c_start();
i2c_write(0xCC);
i2c_stop();

won't actually control the DAC peripheral.

I downloaded the uC datasheet and it has a device address of 0XC0. You then need to send 2 bytes with 'control'(how to use the DAC) and 'DAC value'(12 bits).
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 11:40 am     Reply with quote

The schematic on page 23 of the MCP4725 data sheet shows pull-ups,
not series resistors.
http://ww1.microchip.com/downloads/en/DeviceDoc/22039d.pdf
Recommended pull-up values are 4.7K for 5v circuits and 3.3K for 3.3v
circuits.
nickdc



Joined: 19 Sep 2018
Posts: 15

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 11:49 am     Reply with quote

Thanks temtronic and PCM programmer for looking into this.
Sorry, I looked at a wrong pair of resistors.
I also see a pair of 4k7 resistors in my schematic connected to 5V.
The MCP4725 is an IC on a custom made PCB.
I'm writing the firmware for this PCB.

temtronic wrote:

this...
i2c_start();
i2c_write(0xCC);
i2c_stop();

won't actually control the DAC peripheral.

I downloaded the uC datasheet and it has a device address of 0XC0. You then need to send 2 bytes with 'control'(how to use the DAC) and 'DAC value'(12 bits).


I assumed that which byte is sent for the address is not the point.
I have succeeded in sending and receiving in main other project (the actual firmware).
I used another byte value here, I overlooked the actual value when I was making that example.
I wanted to demonstrate that i2c_write blocks after a timeout reset without FORCE_SW.
I assumed that i2c_write() blocks on any byte value, after a timeout reset, when not using FORCE_SW.
I will check that tomorrow.

But it also blocks in my main firmware project, with the correct address/command byte.
It works when I use the FORCE_SW solution.
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 12:33 pm     Reply with quote

i2c_start, must have as the next byte sent, the address of the device to
talk to. If this is not correct there will not be a reply.
So using the wrong byte is critically 'wrong'....

On software I2C, the software will just drop out if there is a problem,
but the hardware peripheral will wait if there is an issue. The hardware
will only hang, if the slave device is holding the clock, and it tries to do
another write. You can always test for the clock having been released
by simply reading input_state on the line corresponding to SCL. However
is the line is being held, it really implies you are doing something wrong
in the command your are sending the chip. So show your real code.
Or that there is an issue with your hardware. Are both the SDA and SCL
high when nothing has been sent?.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group