Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

PIC16F877A freezes after a certain event

Status
Not open for further replies.

abicash

Member level 3
Member level 3
Joined
Jun 26, 2007
Messages
60
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,288
Activity points
1,772
Hello forum

My setup:
I am using a 16f877a with 11.0592MHz crytal and MPLAB IDE ver 8.92
Programmer is PICkit3.
Configuration :
HS OSC , WDT-disabled , PWRT-disabled, BOR-disabled,RB3-dig i/o,&MCLR pulled up to VCC=5v
All memory protections are off

I am driving 8 nos of 7 segment displays and 4 keys as input (all keys individual and not in a 2x2 matrix)

I am using a couple of unsigned long variables and no re-entrants in ISR's.
I also have an LED toggling in a one second TMR0 interrupt to show that the MCU is alive.

I am trying to display an 8-digit BCD number on the display on few key-presses.
Simulation works fine in proteus.

Display shows 0 0 0 0 0 0 0 0 - on reset
Press SET key
Display shows S E t
Press ENTER key
Display shows 1 2 3 4 5 6 7 8 (converted from decimal 12345678 or 0xBC614E)

On actual hardware
Display shows 0 0 0 0 0 0 0 0 - on reset
Press SET key
Display shows S E t
Press ENTER key
Display turns blank
MCU freezes
One second tick LED stops ticking.

I thought that this might be related to stack overflow , but I don't have re-entrant levels in ISR as I mentioned earlier.

I am now unable to understand this phenomenon, so requesting some learned members help on this one.

Thanks in advance
 

According to the description, this sounds like a pure software problem. I presume that the said "Enter" key press doesn't trigger an unique hardware action, e.g. enabling more LED segments so that the power supply is overloaded.

Generally all kind of software faults, including stack overflow can be caught with MPLAB or MPLAB-X debugger.
 

Thanks for replying

Well , I forgot to mention that I have a very robust 2A power supply to power the board.
Just now checked , on a DSO, there is no glitch on the Power during the key-press.

One observation that i failed to note in my original post is that , randomly the display will show the 8 digits on the key-press.
Although most of the times, they turn blank, and the MCU freezes (Timer Led stops toggling)

You said that all kinds of software faults can be caught with MPLAB.
How to do that? ( First time working on a PIC)
 

Hi,

Maybe the keys are not debounced.
And the ENTER key causes multiple events within very short time.
Depending on software multiple scenarios can make the PIC to hang. Stack overflow for example.

If you want some more assistance you should show your complete documented code.

Klaus
 

Hello and thanks for replying
:smile:

I have a key debounce.
I am sharing my code here , but it is a lot of mess since yesterday.
Please excuse me for all that mess in the code.

Code:
#include <pic.h>
#include "stdio.h"

const unsigned char SET_KEY_PRESSED = 0x30;
const unsigned char UP_KEY_PRESSED = 0x24;
const unsigned char ENTER_KEY_PRESSED = 0x14;
//-----------------------------------------------------------------------------------------------------------------------------
const unsigned char seg_sel[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
const unsigned char seg[15]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x77,0x7C,0x39,0x5E,0x71};
const unsigned char set[8]  ={0xFF,0xFF,0xFF,0xFF,0xFF,0x92,0x86,0x87};
const unsigned char rst[8]  ={0xFF,0xFF,0xFF,0xFF,0xFF,0xAF,0x92,0x87};
const unsigned char out[8]  ={0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0xC1,0x87};
const unsigned char yes[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0x91,0x86,0x92};
const unsigned char Noo[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xAB,0xC0};
const unsigned char test[8] = {0xFF,0xFF,0x92,0x86,0x87,0xFF,0xAB,0xC0};
//-----------------------------------------------------------------------------------------------------------------------------
unsigned int count=0;
unsigned char seg_counter;
unsigned char val[10];
unsigned char Key_Scan_Value=0,Key_Value=0;
unsigned char Key_Pressed=0;
unsigned int set_delay,delay_count=0,start_delay=0;
unsigned char Chk_All_Key_Open=0;
unsigned char Start_Set_Timer=0,Setting_mode=0;
unsigned int Set_Timer_Count=0,Set_timer_complete=0;
unsigned char display_string=0;
unsigned char Setting_Case=0;
unsigned char position_couter=0;
unsigned int Start_Blinking=0,Blink_Count=0,Blink_Value=0;
unsigned char Disp_Position=0;
unsigned long Set_Count_Value=0;
unsigned char temp1=0,temp2=0,temp3=0,temp4=0;
//unsigned long temp=0 ;
 signed char index=0 ;
//unsigned char msec_complete;
//--------------------------------------------------------------------------------------------------------------------
void delayms(unsigned int count);
unsigned char Check_Key_Pressed(void);
//-----------------------------------------------------------------------
void timer0_init(void)
{
	OPTION = 0x83;//option reg as 0x83
	TMR0 = 83;
	T0IE = 1;//timer 0 interrupt enable flag
	GIE = 1;
}

/*void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data);
unsigned char eeprom_read1(unsigned char addr);

void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data)
{
    GIE = 0;
    EEADR = eeprom_add;    // set the address location in EEADR
    EEDATA = eeprom_data; // data to be written is taken in EEDATA
    WREN = 1;    //enable write cycle
    EECON2 = 0x55;
    EECON2 = 0xAA;
    WR = 1;  //start of write cycle
    WREN = 0;    //write data to eeprom
    while(WR == 1);    // wait until write procedure gets completed.
    GIE = 1;
}
unsigned char eeprom_read1(unsigned char addr)
{
    unsigned char rd_data;
  GIE = 0;     //disable globle interrupts
    EEADR = addr;           //move address in eeadr reg
    EEPGD = 0;   //read eeprom pointer
   RD = 1;      //enable read cycle
    while(RD == 1);//wait here till read cycle completes
    rd_data = EEDATA;       //read data from eeprom data reg
    GIE = 1;
    return rd_data;
}
*/
//--------------------------------------------------------------------------------------------------------
void timer1_init(void)
{
	T1CON = 0x01;
	TMR1H = 0xF5;
	TMR1L = 0x33;
	TMR1IE = 1;
}/**/
//--------------------------------------------------------------------------------------------------------
void delayms(unsigned int count)
{
     delay_count = 0;
     set_delay = count;
      start_delay = 1;
      while(start_delay == 1);/**/
}
//---------------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------------
void display_number_upto_99(unsigned char value)
{
	unsigned char k;
	k = value;
	val[0] = k/10;
	k = k%10;
	val[1] = k;
}
//--------------------------------------------------------------------------------------------------------
/*void BCD_convert( unsigned long num )
 {
 
 unsigned char temp_Val[10];
 
    for ( index=0; num>0; index++  ) {
        temp = num / 10 ;
        val[index] = num-10*temp ;
        num = temp ;
    }
    for ( ; index>=0; index-- )
        val[index] = 0 ;
 }*/
//--------------------------------------------------------------------------------------------------------
void display_set_on_display()
{
	unsigned char i;
    display_string = 1;
	for(i=8;i>0;i--)
	 val[i-1] = set[8-i];
}
//--------------------------------------------------------------------------------------------------------
void display_test_on_display()
{
	unsigned char i;
    display_string = 1;
	for(i=8;i>0;i--)
	 val[i-1] = test[8-i];
}
//--------------------------------------------------------------------------------------------------------
void display_rst_on_display()
{
	unsigned char i;
    display_string = 1;
	for(i=8;i>0;i--)
	 val[i-1] = rst[8-i];
}
//--------------------------------------------------------------------------------------------------------
void display_out_on_display()
{
	unsigned char i;
    display_string = 1;
	for(i=8;i>0;i--)
	 val[i-1] = out[8-i];
}
//--------------------------------------------------------------------------------------------------------------------------
void interrupt any_ISR(void)
{
//--------------------------------------------------------------------------------------------------------
	if (T0IF==1)
	{
		seg_counter++;
		if(seg_counter > 7) 
			seg_counter = 0;
		PORTD = 0x00;
		PORTD = seg_sel[seg_counter];
		PORTB = 0xFF;
		if(display_string == 0)
		{
			//if((Start_Blinking == 1))
				{
					
						PORTB = seg[val[seg_counter]];
				}
		//	else
			//if((Blink_Value == 1) && (seg_counter == Disp_Position)&&(Start_Blinking == 1))
			//	PORTB = seg[val[seg_counter]];
		//	else if((Blink_Value == 0) && (seg_counter == Disp_Position)&&(Start_Blinking == 1))
		//		PORTB  = 0xFF;
		//	else
		//		PORTB = seg[val[seg_counter]];	
		}
		else
			PORTB = val[seg_counter];
		
		T0IF=0;
		TMR0 = 83;
	}
//--------------------------------------------------------------------------------------------------------
	if(TMR1IF)
	{
		count++;
		if(count > 1000)
		{
			count = 0;
			RC3 ^=1;
		}
		if(Start_Set_Timer==1)
		{
			Set_Timer_Count++;
		if(Set_Timer_Count > 1000)	
			{	
				Set_Timer_Count = 0;
				Start_Set_Timer = 0;	
				Set_timer_complete = 1;	
			}	
		}
		
		if(start_delay == 1)  
			delay_count++;
	    if(delay_count > set_delay)
	    {
	           set_delay = 0;
	           start_delay = 0;
	    }

		TMR1IF = 0;
		TMR1H = 0xF5;
		TMR1L = 0x33;
	}
}
//--------------------------------------------------------------------------------------------------------
void soft_delay(void)
{
	unsigned int i;
	for(i=0;i<10000;i++);
}
//-------------------------------------------------------------------------------------------------------------------------
unsigned char Check_Key_Pressed(void)
{
	 	Set_Timer_Count = 0;
		Start_Set_Timer = 0;
		Key_Value = 0;
		Key_Scan_Value = 0;
		Key_Scan_Value = PORTA & 0x34;
		if(Key_Scan_Value != 0x34)
			{
				Key_Scan_Value = PORTA & 0x34;
				soft_delay();//soft_delay();//soft_delay();
				Key_Scan_Value = PORTA & 0x34;
				if(Key_Scan_Value != 0x34)
				{
					Chk_All_Key_Open = 1;
					Key_Value  = Key_Scan_Value;
				}
			}
	if(Chk_All_Key_Open == 1)
	{
		do
		{
			Key_Scan_Value = PORTA & 0x34;
		}while(Key_Scan_Value != 0x34);
		 Chk_All_Key_Open = 0;	
	}
		return(Key_Value);
}
//--------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
void main(void)
{
	unsigned long temp_i=0;
	unsigned char k=0;
	//unsigned long mem_va,mem_val1=0,mem_val2=0;//,mem_val3,mem_val4;
	TRISC = 0x00;
	TRISD = 0x00;
	TRISB = 0x00;
	timer0_init();
	timer1_init();
	ADCON1 = 0x04;
	TRISA = 0x3F;
		
	delayms(250);	

	display_string = 0;
	Setting_Case = 0;
	position_couter = 0;
	
	/*FLASH_WRITE(0x00,0xFF);
	soft_delay();
	FLASH_WRITE(0x01,0xE0);
	soft_delay();
	FLASH_WRITE(0x02,0xF5);
	soft_delay();
	FLASH_WRITE(0x03,0x05);
	soft_delay();
	mem_val1 = 	FLASH_READ(0x00);
	mem_val2 = 	FLASH_READ(0x01);
	mem_val = mem_val2*0x100;
	mem_val += mem_val1;
//mem_val = (mem_val2*100)+mem_val1;
	mem_val1 = 	FLASH_READ(0x02);
	mem_val2 = 	FLASH_READ(0x03);
	mem_val1 *= 0x10000;
	mem_val2 *= 0x1000000;
//	mem_val1 = (((mem_val2*0x1000000)+(mem_val1*0x10000)));
	mem_val += mem_val1+mem_val2;*/
//-----------------------------------------------------------------------------------------------------
//Set_Count_Value = 	mem_val;
	//BCD_convert(mem_val);
	while(1)
	{
	/*	if(Start_Blinking == 1)
		{
			Blink_Count++;
			if(Blink_Count > 300)
			{
				Blink_Count = 0;
				Blink_Value ^=1;
				RC4 ^= 1;
			}
		}*/

			Key_Pressed = Check_Key_Pressed();
         	if((Key_Pressed == SET_KEY_PRESSED) && (Setting_mode ==0))
			{
				Key_Pressed = 0;
					Setting_mode = 1;
				display_set_on_display();
			}

		/**/	if(Setting_mode == 1)
			{
				switch(Setting_Case)
				{
					case 0:	
									
									if(Key_Pressed == UP_KEY_PRESSED)
										{
											Key_Pressed = 0;
											position_couter++;
											if(position_couter > 2)
												position_couter = 0;
										
										if(position_couter == 0)
										  display_set_on_display(); //display_setting_on_display(&set);
				                        else if(position_couter == 1)
										  display_rst_on_display();// display_setting_on_display(&rst);
				                        else if(position_couter == 2)
										  display_out_on_display();
								}
										if(Key_Pressed == ENTER_KEY_PRESSED)
										{
											Key_Pressed = 0;
											if(position_couter == 0)
											{
												Setting_Case = 1;
												Blink_Value = 0;
												Blink_Count = 0;
												Start_Blinking = 1;
											}
										}
									k=0;
							break;

					case 1:		display_string = 0;
								if(k==0){
									k=1;	
								//if(Start_Blinking == 0)
								Set_Count_Value = 12345678;
								{
							    /**/	for ( index=0; Set_Count_Value>0; index++  ) 
									{
								        temp_i = Set_Count_Value / 10 ;
								        val[index] = Set_Count_Value-10*temp_i ;
								        Set_Count_Value = temp_i ;
								    }
										//Start_Blinking = 1;
								}//display_test_on_display();
	}
							
							break;
				}
			}
			Key_Pressed = 0;
	}
}
 
Last edited:

You said that all kinds of software faults can be caught with MPLAB.
How to do that? ( First time working on a PIC)
I presume you have a programming/debugging adapter like PICkit II. You can load and run the code in debug mode, setting breakpoints or stopping code execution manually, reading and possibly changing register content.

First simple thing would be to check which code is actually executed when the processor freezes, or to single step from "Enter" key recognition.
 

I have been debugging the code with a Pickit3 for some time now.

And i have found that the debugger shows the variable <temp_i> as <out of scope> after one pass through the <for ( index=9; Set_Count_Value>0; index-- )> loop.

Is this of some relevance?
 

I have been debugging the code with a Pickit3 for some time now.

And i have found that the debugger shows the variable <temp_i> as <out of scope> after one pass through the <for ( index=9; Set_Count_Value>0; index-- )> loop.

Is this of some relevance?

No, at that point of time, the temp variable would have been deleted and so the debugger say that it is out of scope, it is usual, it doesnt have any direct relation with that

I have suggested certain possible reasons for your problem


* Stack Overflow (Check RAM)
* ROM/Flash Overflow (Check Program Space)
* Source Code not optimized
* Basic Logical Mistake (Code absence for event handling)
* Un-mapped interrupt triggering


If you press button for SET, it is working well until that.
So try displaying ENTER instead of SET for the previous button press
Check what happens now

I am sure you are going to laugh at last after finding the issue, it should be a small thorn inside the bush



Congrats !!!!
 

Thanks bala for your reply

Ok so I understood that <temp_i> is deleted, since some time back i declared it as a global and a volatile variable, still problem persisted.

About your suggestions..
1)Stack Overflow -- I am not sure how that's done in MPLAB (I am new to this environment and Microchip)
2)ROM/FLASH Overflow -- I am sure that its within bounds
3)Source code not optimised -- I think that's the job of the compiler , and since code is relatively quite small I did not find any area for optimisation.
4)Basic Logical mistake -- Yes that could be the reason, and I am struggling to find that
5)Unmapped interrupt triggering -- I have only 2 interrupts (timer) and both have been serviced appropriately if you see my code
 

Hi abicash,

Sorry, I haven't went through your code
Just replied so that you can get a quick idea

I will look into your code, late today and get to you back

Wishing you to find the bug well before me !!!
 

No, at that point of time, the temp variable would have been deleted and so the debugger say that it is out of scope, it is usual, it doesnt have any direct relation with that

Out-of-scope message refers to a debugging problem, not a code error. It happens if the actual stack frame is different from the context where a local variable is defined.

temp_i is defined in main and thus will be never "deleted", because main isn't terminated during program execution. But it's still a local variable that won't be visible outside the main function context. If the value is of general interest for your debugging task, make it a global static variable.

Keep on learning debugging techniques.
 

None of these are necessarily the cause of your problems but they should be looked at anyway.
In the ISR, you should check for both the IE and the IF bits (you only check the IF bit). If all (expected) interrupt sources are always enabled then you might get away with this but if not then consider what happens when you disable an interrupt (which does NOT stop the IF bit from being set by the hardware) and then some other trigger occurs that executes the ISR: the code will only check that the (supposedly disabled) IF bit is set and will (incorrectly) execute the corresponding bit of code.
Don't rely on the C compiler to correctly generate code for the special 'unlock' sequences. The MCU must see the instructions as sequential with no intervening code (or interrupts) and the C compiler need not generate the correct code (the code is logically correct within the rules the compiler has but it does not know about the special requirements of the hardware). It is better to use in-line assembler to ensure the correct instruction sequence is seen by the processor.
I'm not sure how your 'delayms' function is supposed to work. The variables used in the function are updated in the ISR BUT the variables (in particular 'start_delay') are not declared as 'volatile'. Therefore when the compiler generates code for the 'while' loop in that function, it is perfectly OK for it to copy the 'start_delay' value into a register and then continuously check that. You need to declare it is volatile to tell the compiler that its value can change at any time and so it must be re-read each time through the loop.
Your 'soft_delay' function may not be providing any delay at all as the compiler can see that it actually does not alter anything and so can remove the whole thing. Again this is within the rules of compilers in that it is creating logically correct code - just not code that you want it to as a side effect. It is better to use the 'delay' functionality provided by the compiler.
Be careful of using FLASH memory in the way you do. The data sheet states that there is a minimum of 10K erase/write cycles for that memory and if you are not careful you can easily exceed this. (I know the 'typical' value is 100K erase/write cycles but this can still be exceeded if you are not careful, especially in production situations.) Do you really need to write to the FLASH memory every time the code starts? Why not check to see if a memory value is 0xff (i.e. erased) and write the values only if it is. Otherwise simply read them each time.
The MCU only has an 8-level stack so stack overflows need to be carefully watched (as others have mentioned). Don't forget to account for the function calls created by the compiler for such things as multiply and divide (and a whole lot more).
Susan
 

Hello Susan

Thank you so much for an elaborate explanation. Much appreciated.

All my problems vanished after i switched to MPLAB-X IDE.

One comment worth making about the flash memory initialisation.
It is initialised this way for testing alpha phase. It is not supposed to write at every MCU reset.

regards
abicash
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top