|
|
View previous topic :: View next topic |
Author |
Message |
nickdc
Joined: 19 Sep 2018 Posts: 15
|
PIC16F1828 WDT and I2C write behaviour |
Posted: Mon Dec 02, 2019 9:55 am |
|
|
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: 9226 Location: Greensville,Ontario
|
|
Posted: Mon Dec 02, 2019 10:24 am |
|
|
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
|
|
Posted: Mon Dec 02, 2019 10:41 am |
|
|
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: 9226 Location: Greensville,Ontario
|
|
Posted: Mon Dec 02, 2019 10:51 am |
|
|
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
|
|
|
nickdc
Joined: 19 Sep 2018 Posts: 15
|
|
Posted: Mon Dec 02, 2019 11:49 am |
|
|
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: 19506
|
|
Posted: Mon Dec 02, 2019 12:33 pm |
|
|
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?. |
|
|
|
|
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
|