|
|
View previous topic :: View next topic |
Author |
Message |
jmb1539
Joined: 29 Mar 2010 Posts: 11
|
PIC18F2620 locking up with serial data |
Posted: Mon Mar 29, 2010 10:26 am |
|
|
I have a PIC project running on a PIC18F2620 that receives one serial data stream with two distinct data messages (received once a second). The two data messages are parsed and repackaged to a single data stream and retransmitted (from a software UART about once every 3 seconds). The serial data stream is received through a MAX232A. The TTL data is received by the RX line at the PIC and a TX line at a second MAX232A where the raw received data is rebroadcast out to a second application. I have built and tested this circuit on a breadboard and an initial PCB and it worked flawlessly. Recent builds using the same components and PCB's have resulted in inconsistent behavior. The cards power up and I receive my heartbeat indicator fine, however, when incoming serial data is received, the PIC locks up (heartbeat stops). When locked up, I can scope the incoming serial data and it is still present. The odd thing is that when the PIC locks up, the second MAX232A "listening" on the TTL RX line also has problems. Even though the input is still being seen on the TX input line, the output is railed solid at -9V. With serial data being present during power-up, I’ve been having about a 99% lock-up rate (basically, every time). My bench power supply is a BK Precision 1666 DC-Regulated Power Supply set at 28V and my board power is supplied by a Lucent (or Motorola) MC010A DC-DC convertor (18-36V in & 5V out).
I have compiled and loaded the code using IDE 4.065, PCB 4.065, PCM 4.065, PCH 4.065 and more recently, I have updated to IDE 4.104, PCB 4.104, PCM 4.104, PCH 4.104 and still have problems.
Additional info: (1) I have switched to a different manufacture date code of PIC18F2620's and they seem to be more reliable, yet not perfect
(2) I removed the second MAX232A and the problem still exists
(3) I have a similar circuit running perfectly on a PIC16F876. The code on the PIC16F876 has additional lines of code for an LCD, no MCLR #fuse, and a different header file.
(4) I have recently executed the exact code on a PIC16F876, minus the MCLR #fuse, and have had no problems.
(5) I reassembled the circuit on a breadboard and I'm seeing the same issues with the PIC18F2620 and not the PIC16F876
My code is shown below with some calculations removed:
Code: |
#include <18f2620.h>
#device *=16 // Sixteen bit pointer definition
#device icd=TRUE
#use delay(clock=20MHZ)
#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP, DEBUG, MCLR
#use rs232(STREAM=IN, XMIT=PIN_C6, RCV=PIN_C7, BAUD=19200, ERRORS)
#use rs232(STREAM=OUT, XMIT=PIN_C2, RCV=PIN_C5, BAUD=19200, ERRORS)
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
////////////////////////////////////////////////////////////////////////////////
// Pin Definitions
////////////////////////////////////////////////////////////////////////////////
// Port B Definition
#define RX_VALID_IND PIN_B0 // PIN #21 RX Valid Heartbeat Indicator
#define RX_ERROR_IND PIN_B1 // PIN #22 RX Error Heartbeat Indicator
////////////////////////////////////////////////////////////////////////////////
// Global Variables
////////////////////////////////////////////////////////////////////////////////
char msg[38]; // rx message temp buffer array
char inputData[38]; // rx message array
char no_rx_data[20]; // default no rx data array
char wstatus; // status of data in output stream
char output[20]; // output stream of data
char dlimitr[2]={'='}; // delimiter token is "="
float speed; // speed value
float direction; // direction value
float temp; // air temp value
float pres; // atm value
float rh; // rh value
int1 gotMsg=FALSE; // Received Message from Modem flag
int1 gotMsg2=FALSE; // Packed message flag
int1 hrttogl=TRUE; // Heartbeat LED status flag
int1 error=TRUE; // rx data timeout flag
int8 i=0; // Index for serial_isr()
int8 j=0; // Index for heartbeat_isr()
int16 t=0; // Data Timeout counter
typedef union // union used to facilitate packaging of output
{
int8 x08[2];
int16 x16;
}data1;
data1 param[7];
////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////
#define DATAOUT_TIMEOUT 3500 // Time constant for Data Timeout
#define INTERRUPT_COUNT 50 // Interrupt count for Heartbeat toggle
////////////////////////////////////////////////////////////////////////////////
// Function Prototypes
////////////////////////////////////////////////////////////////////////////////
void serial_isr();
void timer0_isr();
void main();
void parseData();
void packData();
void init_system();
void heartbeat();
////////////////////////////////////////////////////////////////////////////////
// Interrupts
////////////////////////////////////////////////////////////////////////////////
// Serial Interrupt Service Routine
// Interrupt entered when incomming serial data detected (HW USART only)
// Read port 1 char at a time, do not save unless sync is present (0xFAF320)
// If SYNC detected, record next 16 chars and set 'gotMsg'.
#int_RDA
void serial_isr()
{
msg[i]=fgetc(IN);
if(i<3) // check for sync...msg header '0R1' or '0R2'
{
switch (i)
{
case 0:
if(msg[0]=='0')
i=1;
break;
case 1:
if(msg[1]=='R')
i=2;
else
i=0;
break;
case 2:
if((msg[2]=='1') || (msg[2]=='2'))
i=3;
else
i=0;
break;
default:
i=0;
}
}
else
{
if(msg[i++]==0x0D) // end of ASCII message
{
gotMsg=TRUE; // complete message received
strcpy(inputData, msg); // transfer temp buffer to INPUTDATA
i=0; // reset index for next message
}
if(i>=37)
i=0; // error if > 35 characters...reset
}
}
// Timer0 Interrupt Service Routine
// Interrupt entered when TIMER0 overflows. Generates a heartbeat toggle of
// approximately 500ms. Heartbeat LED is green with valid rx data and red
// if data isn't rx from
// (Timeout period is determined by DATAOUT_TIMEOUT constant)
#int_TIMER0
void timer0_isr()
{
j++; // increase timer for heartbeat
t++; // increase timer for dataout_timeout
}
////////////////////////////////////////////////////////////////////////////////
// MAIN()
// Wait for serial message indicated by 'gotMsg' = TRUE (received through
// RDA interrupt). If 3 sec elapse with no message, zero-out data stream to
// DAS. If message received, parse and package data then send out to the DAS
// on PIN_C2.
////////////////////////////////////////////////////////////////////////////////
void main()
{
int8 k;
init_system(); // initialize system
while(TRUE)
{
t=0; // reset timeout counter value
while(!gotMsg) // wait until data message received
{
if(t>DATAOUT_TIMEOUT) // check for correct number of timer interrupts
{
i=0; // reset isr index
t=0; // reset timeout counter value
error=TRUE; // set error status flag
for(k=0;k<=19;k++)
{
fprintf(OUT, "%c", no_rx_data[k]); // output no_rx_data stream
}
}
heartbeat(); // toggle LED for heartbeat
}
gotMsg=FALSE; // Reset gotMsg bit for next message
parseData(); // extract data & apply EU conversions
if(gotMsg2) // execute if full data stream is rx
{
error=FALSE; // reset error flag if set
gotMsg2=FALSE; // Reset gotMsg2 bit for next message
packData(); // assemble serial output message
for(k=0;k<=19;k++)
fprintf(OUT, "%c", output[k]);// Transmit packaged data to DAS
heartbeat(); // toggle LED for heartbeat
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Functions
////////////////////////////////////////////////////////////////////////////////
// init_system()
// Initialize system routine enables the controller system interrupts and
// defines the no_rx_data array used when the no data is received
// within 3 seconds
void init_system()
{
setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256); // setup timer interupt
enable_interrupts(int_rda); // Enable interrupt for USART serial data
enable_interrupts(int_TIMER0); // Enable Timer0 for Heartbeat flashing
enable_interrupts(GLOBAL); // Enable interrupts
//format "no rx" data output
return;
}
// heartbeat()
// Generates a heartbeat toggle of approximately 500ms when TIMER0 interrupt
// overflows. Status of LED (On/Off) is set by hrttogl flag
// Heartbeat LED is green with valid rx data and red if valid data
// isn't rx within 3.5 seconds. error flag is set within
// main program. (Timeout period is determined by DATAOUT_TIMEOUT constant)
void heartbeat()
{
if(j>INTERRUPT_COUNT) // check for correct number of timer interrupts
{
j=0; // reset counter for next use
hrttogl^=1; // toggle heartbeat LED status 1=ON, 0=OFF
}
if(error) // is error flag set?
{
output_bit(RX_ERROR_IND,hrttogl); // yes, toggle error indicator (red)
output_low(RX_VALID_IND); // turn off rx valid Indicator (grn)
}
else // No error flag
{
output_bit(RX_VALID_IND,hrttogl); // toggle rx valid indicator (GRN)
output_low(RX_ERROR_IND); // turn off rx error indicator (red)
}
return;
}
// parseData()
// Transfer incomming message data 'msg[]' to parameter array 'param[]'.
// Param is a union array used to facilitate conversion of two 8bit words
// into one 16bit word.
void parseData()
{
float wxData[4];
int8 *dataPtr;
int8 *nPtr;
int8 k=0;
dataPtr=strtok(inputData,dlimitr); // move pointer to first delimiter "="
dataPtr=strtok(0,dlimitr); // ignore first parce (address header 0R1,0R2)
while((dataPtr != 0) && (k <= 4))
{
wxData[k++]=strtod(dataPtr, &nPtr); // save parce data into temp wxData
dataPtr=strtok(0,dlimitr); // move pointer to next delimeter
}
if(k<5)
{
if(inputData[2]=='1') // data received is speed & direction data
{
//format message 1 EU data
}
else if(inputData[2]=='2')// data received is temp, rh & press data
{
// format message 2 EU data
gotMsg2=TRUE;
}
}
return;
}
// packData()
// Format output stream with required data in preparation for transmission
void packData()
{
// format outpt data
return;
}
|
Thanks,
Justin |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Mar 29, 2010 12:59 pm |
|
|
What's the silicon rev. of the 18F2620 that you're currently using ?
Earlier revs had problems with the EUSART. Knowing the exact rev
you're using is critical. The rev is reported by the programmer (ICD)
when it "connects" to the PIC. In MPLAB, it's given in the Output window. |
|
|
jmb1539
Joined: 29 Mar 2010 Posts: 11
|
|
Posted: Mon Mar 29, 2010 3:23 pm |
|
|
I'm using the Mach X ICD and if I'm reading it correctly, I get the following:
Device PIC18F2620
Status Good
Device ID 0C80
Revision 07 --> I believe this is my silicon version?
Program 32768 instructions
Configuration 300000-30000D
Data F00000-7801FF
etc |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Mar 29, 2010 3:45 pm |
|
|
Quote: | Revision 07 --> I believe this is my silicon version?
|
I'm not sure if that's the revision. Your Device ID word is 0C80:
Look at the erratas on the 18F2620 page:
http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010284#1
They contain the silicon rev numbers. Here is a summary:
Code: |
Silicon rev Device ID Rev ID ID (hex)
A3 0000 1100 100 0 0011 0C83
A4 0000 1100 100 0 0100 0C84
A5 0000 1100 100 0 0110 0C86
A6 0000 1100 100 0 0111 0C87
|
It's possible that CCS is masking off the bottom 4 bits of the Device ID
and just reporting "0C80" as the ID. Then they may be taking the
bottom 4 bits and reporting that raw number as the Revision. So their
"rev 7" is really silicon rev A6. That interpretation might make sense. |
|
|
jmb1539
Joined: 29 Mar 2010 Posts: 11
|
|
Posted: Tue Mar 30, 2010 12:31 pm |
|
|
It looks like I have the B5 silicon revision. I've looked through the errata for this silicon and all others and I'm not coming across a solution. For issues concerning the USART, I see modules for synchronous transmission, 9-bit mode, and auto-baud modes. I'm not using any of those configurations. I've used the ICD to try and track down where my processor is going out to lunch, but the only thing I'm seeing is that once I enable my serial interrupt, i'm done. |
|
|
jmb1539
Joined: 29 Mar 2010 Posts: 11
|
|
Posted: Wed Mar 31, 2010 1:20 pm |
|
|
Just FYI for anyone following this thread, the problem I encountered was do to the strcpy function that was called in the serial ISR. My incoming data wasn't null terminated so this function would just hang. The fact that the code worked on the PIC16F876 was simply a matter of luck. Once I terminated my received data, the code worked fine. |
|
|
|
|
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
|