|
|
View previous topic :: View next topic |
Author |
Message |
dan king
Joined: 22 Sep 2003 Posts: 119
|
code doesn't work on every 16f688 |
Posted: Thu May 24, 2007 9:55 am |
|
|
I recently posted a problem where I was sharing some I/O pins between and LCD module and rs-232 access. I thought I had resolved the problem but it doesn't appear to be a code related issue because the problem came back. After further examination, I'm finding that the same exact code works in some of my stock of 16f688's but not in others. This is the same code without modification acting differently using the same test hardware by simply pulling the part out of the socket and trying another in the same hardware.
When I get a part that fails, LCD display is blank, if I remove access to the uart in the test code the LCD begins to work properly with that part but if I remove the comments to re-enable the uart the failed parts fail again to display on the LCD.
Has anyone seen this before? I'm really confused on how this could be happening. I have included my final test code for reference as I made some changes after my last post that I though had fixed the problems.
The test simply involves powering up the chip and LCD without any serial connections, no level shifters - nothing, and waiting for the LCD to display something. The LCD does appear to init as the telltale blocks disappear but other than that no display. The code is executing the main loop as I have tested that with simple port = high type tests. The LCD simply remains blank.
any help is much appreciated.
Thanks
Code: |
#include <16f688.h>
#fuses INTRC_IO //internal rc osc with i/o ra4 and i/o on ra5
#fuses NOWDT //no watchdog
#fuses NOMCLR //internal MCLR
#fuses NOPROTECT //no code protect
#fuses NOPUT //disabled power up timer
#fuses BROWNOUT //disabled brownout detect/reset
#fuses NOCPD //no EE read protect
#fuses NOIESO //no internal/external switchover mode
#fuses NOFCMEN //no monitor clock failsafe mode (auto switch if no clock)
#use delay(clock=8000000,INTRC_IO) //after fuse to set intrc clock speed or use
//setup_oscillator( );
#use rs232(baud=9600,parity=N,xmit=PIN_C4,rcv=PIN_C5,errors)
#use fast_io(A)
#use fast_io(C)
////////////////////////////////////////////////////
// Constants and variables
//PortA 0
// 1
// 2 LCD - enable
// 3 not used
// 4
// 5
//PortC 0 LCD data bit0
// 1 LCD data bit1
// 2 LCD data bit2
// 3 LCD data bit3
// 4 LCD rd - rs-232 TX
// 5 LCD rs - rs-232 RX
#byte PORTA = 5 // port a = 0x05, b = 0x06, c = 0x07, d = 0x08, e = 0x09 address
#byte PORTC = 7
#byte RCSTA = 0x17
#bit SPEN = RCSTA.7
#bit CREN = RCSTA.4
#bit TXEN = 0x16.5
#bit RCIE = 0x8c.5
//#byte TRISC = 0x187
struct {
BYTE data:4; // bits 0 - 3
} LCD_PORT;
#BYTE LCD_PORT = 7 //PORTC
#BIT LCD_E = PORTA.2
#BIT LCD_RD = PORTC.4
#BIT LCD_RS = PORTC.5
#bit alarm = PORTA.4
#define LCD_DATA LCD_PORT.data
#define DATA_TO_LCD set_tris_c(0)
#define DATA_FROM_LCD set_tris_c(0x0f)
#define WORD unsigned long // Data type definitions
#include <lcd_custom_pins.h>
///////////////////////////////////////////////////////////////////
int16 result;
float meas;
float alarm_val;
int1 config;
int1 message_flag;
int i;
//////////////////////////////////////
#define BUFFER_SIZE 8
#define bkbhit (next_in != next_out)
int buffer[BUFFER_SIZE];
int next_in = 0;
int next_out = 0;
///////////////////////////////////////////////////////
// General prototypes //
// local prototypes
void execute_cmd();
int bgetc();
int16 get_16b_num();
///////////////////////////////////////////////////
// serial port ISR
#int_rda
rda_isr(){
static int t;
if(kbhit()){
buffer[next_in] = getc();
if (buffer[next_in] == 'C')
config = 1;
t = next_in;
next_in = (next_in + 1) % BUFFER_SIZE;
if (next_in == next_out)
next_in = t; // buffer full
}
}
////////////////////////////////////////////////////
/////////////////////////////////////////////////////MAIN
void main(){
alarm = 0;
message_flag = 0;
config = 0;
LCD_E = 0;
setup_oscillator(OSC_8MHZ); //sets the sw selectable internal rc clock speed
SETUP_ADC_PORTS(NO_ANALOGS); // no adc's
setup_comparator(NC_NC_NC_NC);
set_tris_a(0b11000001); //a.3 is input only so can't use, ignores 0 for tris
set_tris_c(0b00100000);
enable_interrupts(INT_RDA);
enable_interrupts(global);
delay_ms(2000);
while (config){
if (!message_flag){
message_flag = 1;
printf("\r\n ready for config\r\n");
}
if (bkbhit)
execute_cmd();
}
disable_interrupts(INT_RDA); //no serial comms so no int
disable_interrupts(global);
SPEN = 0;
TXEN = 0;
CREN = 0;
RCIE = 0;
set_tris_c(0b00000000);
LCD_E = 1;
init_lcd(); // Init LCD
LCD_data = 0;
printf(displays,"test");
lcd_gotoxy(2,2);
printf(displays,"test 2");
delay_ms(2000);
// loop until reset
while(1){
lcd_cmd(0x01); //clear the display
lcd_gotoxy(1,2);
printf(displays,"Temp");
delay_ms(500);
}
}
///////////////////////////////////////////////////////////////////////////////
// function interprets commands received through the serial port
void execute_cmd(){
int temp,i;
disable_interrupts(int_rda);
temp = bgetc();
switch (temp){
case 'h': printf("HELP\r\n");
printf(" S to set a new alarm value\r\n");
printf(" Q to quit config and start measuring\r\n");
printf(" \r\n");
break;
case 'S': printf("Set alarm value\r\n");
printf("enter alarm temperature \n\r");
enable_interrupts(int_rda);
meas = get_16b_num();
disable_interrupts(int_rda);
printf("\r\nalarm value is %3.1f\r\n",meas);
break;
case 'Q':
printf("exiting, please unplug serial cable\r\n");
delay_ms(1000);
config = 0;
SPEN = 0;
TXEN = 0;
CREN = 0;
RCIE = 0;
set_tris_c(0b00000000);
LCD_E = 0;
init_lcd(); // Init LCD
LCD_data = 0;
break;
default:
break;
}
if (config)
enable_interrupts(int_rda);
}
///////////////////////////////////////////////////
// function retrieves data from the buffer
int bgetc() {
int c;
while(!bkbhit);
c = buffer[next_out];
next_out = (next_out+1) % BUFFER_SIZE;
return(c);
}
// Get a 8-bit decimal number from the console
// Return it when any non-numeric key is pressed (except backspace)
WORD get_16b_num(void)
{
int16 val=0;
char c, buff[5];
int n=0, i=0;
do {
c = bgetc();
if (c>='0' && c<='9')
{
if (n < sizeof(buff))
{
buff[n++] = c;
putchar(c);
}
}
else
c = 0;
} while (c);
while (n--)
val = (val * 10) + buff[i++] - '0';
return(val);
}
|
|
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Thu May 24, 2007 10:29 am |
|
|
I don't know if this will help but I, recently, made a small project using a 16F688 part. It was running off of a battery pack and simply cycling some LED's for a fancy show (made a Knight Rider pinewood derby car). Sometimes the PIC would work, sometimes it wouldn't. I couldn't figure out what was going on. I thought I would take a shot in the dark and put a filter cap across VCC and GND of the PIC. It started working every time. I didn't think I need any filtering since I was running from a battery.
This one made my forehead a little flatter after I smacked it a few times over this one. If you don't have any filter caps you might want to try adding them. They definitely make a difference even if the supply is a battery.
Ronald |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 24, 2007 10:32 am |
|
|
Also, the Rev. A3 silicon has a large number of erratas on the USART.
You should try to get the A4 silicon. Check the rev of the chips that
you have. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Thu May 24, 2007 11:32 am |
|
|
Ok, this is probably a stupid question, but how do I know what rev of silicon I have? I've been looking through the data sheet, reviewed the erata notice and I can't seem to find it.
I would be disappointed to find out that I received old silicon since I just purchased these through Digikey recently. On the other hand, it sure would make me happy to know the cause of these issues.
Thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 24, 2007 11:54 am |
|
|
I know how to do it with MPLAB and ICD2. Plug in the ICD2 to your
board, and in the Programmer menu of MPLAB, select "Connect".
Look at the messages in the Output window of MPLAB.
One of them will show the silicon revision. Example:
Quote: | Connecting to MPLAB ICD 2
...Connected
Setting Vdd source to target
Target Device PIC18F452 found, revision = b5
...Reading ICD Product ID
Running ICD Self Test
...Passed
MPLAB ICD 2 Ready |
|
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Thu May 24, 2007 12:58 pm |
|
|
Well, I guess that's not the problem. I have silicon rev-6 according to my ICD2. Took a bit to finally get connected because I've been using a pictstart plus to program the parts since debugging is only possible with another connector - that I don't have
Ronald,
Thanks for the suggestion but I do have typical filtering in place as well as running the power off of a lab supply until I get this ironed out.
Anything else, I'm glad to try anything at this point. The only way I was able to get the part that's failing to drive the LCD was to comment out the rs-232 parts of the code and then it would work. Keep in mind that some other parts work just fine with the full code in test.
Thanks,
Dan |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 24, 2007 1:21 pm |
|
|
Your code doesn't compile, as posted. Can you post the missing parts
(lcd driver) ? |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Thu May 24, 2007 1:28 pm |
|
|
Sorry, here's the lcd driver:
Code: |
//#define LCD_LINES 0x01
#define LCD_LINES 0x02 // set number of rows here to match LCD(2 and 4 supported)
//#define LCD_LINES 0x04
#define BOOL short // 'short' is very short (1 bit) in this compiler
#define ALL_OUT 0
#define ALL_IN 0xff
#define LCD_SETPOS 0x00
BOOL disp_lcd, disp_serial; // Flags to enable display O/Ps
Bool IsLumex1x16; //bool flag for unique display
/* Local prototypes */
void lcd_gotoxy(unsigned int x, unsigned int y);
void lcd_cmd(BYTE b);
void lcd_char(BYTE b);
void lcd_byte(BYTE &b);
void lcd_nybble(BYTE b);
void lcd_getposition(byte &msb,byte &lsb);
/* Display handler; redirects to LCD and/or serial
*/
void displays(BYTE b)
{
byte MSB,LSB;
if (disp_lcd)
{
if (b == '\n') // home position
lcd_cmd(0x02);
else if (b == '\r') // carriage return
// lcd_cmd(0xc0);
{
lcd_getposition(msb,lsb); // read cursor position from LCD controller
switch (MSB)
{
case 0:
if (LCD_LINES == 0x01)
{
lcd_cmd(0x80);
break;
}
else
{
lcd_cmd(0xc0); break; //if line 1, a carriage return goes to line 2
}
case 4: // if line 2, a carriage return goes to .....
{
if (LCD_LINES == 0x02)
{
lcd_cmd(0x80); break; //line1
}
else if (LCD_LINES == 0x01)
{
lcd_cmd(0x80); break;
}
else {
lcd_cmd(0x90); break; //line3
}
}
case 1: // if line 3, a carriage return goes to ....
{
if (lsb == 0)
{
lcd_cmd(0xc0);break;
}
else
{
lcd_cmd(0xd0);break; //line 4
}
}
case 5: // if line 4, a carriage return goes to ....
{
if (lsb == 0 && LCD_LINES == 0x02)
{
lcd_cmd(0x80); break;
}
else if (lsb == 0 && LCD_LINES == 0x04)
{
lcd_cmd(0x90);break;
}
else
{
lcd_cmd(0x80);break; //line 1
}
}
default:
lcd_getposition(msb, lsb);
//printf("%u %u \r\n",msb,lsb);
//printf("no match\n");
}
}
// else if (b == '\c')
// lcd_cmd(0x01); // clear the display, has a bug. Any c sent (instead of \c) clears the display
else
{
if (IsLumex1x16)
{
lcd_getposition(msb,lsb);
if (lsb == 8)
lcd_gotoxy(2,0);
}
lcd_char(b);
}
}
// if (disp_serial)
// {
// if (b == '\n')
// putchar('\r');
// putchar(b);
// }
}
/* Display a byte in unsigned decimal format */
void disp_decbyte(BYTE b)
{
printf(displays, "%u", b);
}
/* Initialise the LCD */
void init_lcd(void)
{
int i;
LCD_E = 0; /* Clear LCD clock line */
DATA_TO_LCD; /* Ensure RS and RD lines are O/Ps */
LCD_RD = LCD_RS = 0;
delay_ms(15); /* Ensure LCD is stable after power-up */
for (i=0; i<3; i++) /* Force into 4-bit mode */
{
lcd_nybble(0x3);
delay_ms(5);
}
lcd_nybble(0x2);
delay_ms(5);
lcd_cmd(0x28); /* Set 4-bit mode, 2 lines, 5x7 dots */
lcd_cmd(0x08); /* display off */
lcd_cmd(0x01); /* clear display */
lcd_cmd(0x06); /* incrementing cursor, cursor */
delay_ms(10);
lcd_cmd(0x0c); /* display on,no cursor blink, no char blink, to home pos */
}
/* Send a command byte to the LCD as two nybbles */
void lcd_char(BYTE b)
{
DATA_TO_LCD;
LCD_RD = 0;
LCD_RS = 1;
lcd_byte(b);
}
/* Send a command byte to the LCD as two nybbles */
void lcd_cmd(BYTE b)
{
DATA_TO_LCD;
LCD_RD = LCD_RS = 0;
lcd_byte(b);
if ((b & 0xfc) == 0)
delay_ms(2);
}
/* Send a command byte to the LCD as two nybbles */
void lcd_byte(BYTE &b)
{
lcd_nybble(b >> 4);
lcd_nybble(b);
DATA_FROM_LCD;
delay_us(40);
}
/* Send a command byte to the LCD as one nybble */
void lcd_nybble(BYTE b)
{
DATA_TO_LCD;
LCD_E = 1;
LCD_DATA = b;
LCD_E = 0;
}
/* Go to an X-Y position on the display, top left is 1, 1
For the Samsung/Hitachi IC's the address for the start of each row is
1 00 1aaa aaaa = 1000 0000 = 0x80
2 40 1aaa aaaa = 1100 0000 = 0xc0
3 10 1aaa aaaa = 1001 0000 = 0x90
4 50 1aaa aaaa = 1101 0000 = 0xd0
*/
void lcd_gotoxy(unsigned int x, unsigned int y)
{
int position;
if (x == 1)
position = 0x80;
else if (x == 2)
position = 0xc0;
else if (x == 3)
position = 0x90;
else
position = 0xd0;
position += y;
lcd_cmd(position);
}
//////////////////////////////////////////////////////
/* get the current cursor position from the LCD controller.
if the last printed position is on the end of a line, the cursor increments to the next
location which may not be the next row down. check address mapping for lcd controller
*/
void lcd_getposition(byte &MSB, byte &LSB)
{
DATA_FROM_LCD;
LCD_RD = 1;
LCD_RS = 0;
LCD_E = 1;
MSB = LCD_DATA; // MSB of address of current position
LCD_E = 0;
LCD_E = 1;
LSB = LCD_DATA; // LSB of address of current position
LCD_E = 0;
}
|
Dan |
|
|
w2drz
Joined: 27 Dec 2006 Posts: 55 Location: Western New York - USA
|
code doesn't work on every 16f688 |
Posted: Thu May 24, 2007 4:28 pm |
|
|
Had simular problem with new PICC's failing to operate.
suggest to look at xtal overdrive problem.
tom |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 24, 2007 6:03 pm |
|
|
What specific line (or lines) in main() do you have to comment out,
to get the LCD to display something ?
(To answer the post above, he's not using a crystal. He's using the
internal 8 MHz oscillator. There's no overdrive issue in that case). |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Thu May 24, 2007 7:48 pm |
|
|
One of the last things I did before finishing up for the day was to back out the code until the display started working again. I had commented out ALL references to serial comms except the #use Rs232 ... and the display still didn't work, I then commented out the #use rs232 and the display started working.
I will re-verify this tomorrow when I get back in, but I'm pretty sure that was the case.
Your previous comment regarding the errata made so much sense because I have been witnessing a lot of strange cases where code that finally works on one micro doesn't necessarily work on all of them (all being 16f688's). Even so, I look forward to finding a solution but I running out of places to look.
Thanks for your help on this.
Dan |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Fri May 25, 2007 6:29 am |
|
|
Ok, I think I'm going to chalk this last issue up to a bad chip since I broke out 5 fresh parts and they all program and operate correctly. Not sure what could have become damaged as the uart and the LCD work independently?? Just not together.
I'm very wary about using this part though as I did observe fresh parts operating differently with the same hex files prior to this. This last round of problems I had continued to use the same parts over and over again so my bad there I guess.
Any ideas on what could damage the part so certain ports get tri-stated? This was the first time I tried a 2 transistor interface (BS170's) to rs-232 instead of the maxim level shifters.
Many thanks to all.
Dan |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Fri May 25, 2007 7:48 am |
|
|
Trying not to beat a dead horse but I was able to modify the test code to make minimal changes to get the LCD to display. I simply commented out the INT_RDA code segment, every other segment of code relating to the uart is in place including the #use rs232:
Code: |
///////////////////////////////////////////////////
// serial port ISR
/*
#int_rda
rda_isr(){
static int t;
if(kbhit()){
buffer[next_in] = getc();
if (buffer[next_in] == 'c')
config = 1;
t = next_in;
next_in = (next_in + 1) % BUFFER_SIZE;
if (next_in == next_out)
next_in = t; // buffer full
}
}
*/
|
and the LCD started to work again. Not sure if this helps, maybe it might spark a thought |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri May 25, 2007 7:55 am |
|
|
just for giggles, try taking out the if(kbhit){} part. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Fri May 25, 2007 7:59 am |
|
|
Acutally, I added that code for haha's. It's not there normally but in deperate times .....
Thanks though, I'm willing to try anything as my curiosity is killing me more than anything else at this point. I wonder if I should try a crystal osc instead of the internal RC, since the RC tolerance could vary from chip to chip?
It's starting to look as though binary is no longer just 0's and 1's |
|
|
|
|
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
|