View previous topic :: View next topic |
Author |
Message |
dan king
Joined: 22 Sep 2003 Posts: 119
|
code not exiting case properly |
Posted: Wed Nov 08, 2006 4:12 pm |
|
|
I have a switch/case routine that I use frequently while debugging new code that allows me to start functions via the serial port using hyperterm. For some reason the latest code I'm working on has decided to exit one of the case selections improperly and hangs my code.
I have placed some debug statements to check how far the code progresses before hanging by turning on a led. The code in question is located below:
Code: | void execute_cmd(){
int loop_counter;
disable_interrupts(int_rda);
switch (bgetc()){
case 'h': fprintf(PC,"HELP\r\n");
fprintf(PC,"p - to print dos buffer\r\n");
fprintf(PC,"s - to retrieve song data from SD card\r\n");
fprintf(PC,"d - to read the directory contents from the SD card\r\n");
break;
case 'p': print_buf(); //manual buffer print
break;
case 's': get_song(0); //manual buffer print
//for (loop_counter=0; loop_counter<index; loop_counter++){
// fprintf(PC,"%u ",song[loop_counter]);
//}
//fprintf(PC,"\r\n");
sysled = 1;
break;
case 'd': printf(flow_putc,"i\r"); //get DIR info
delay_ms(5);
print_buf();
break;
}
sysled = 1;
enable_interrupts(int_rda);
//sysled = 1;
} |
The problem is in the 's' selection. The sysled = 1 after calling get_song works, but if I comment that out the same sysled = 1 after the break does not and the code hangs (or seems to since the RDA interrupt may simply not be enabling). The other case statements fall through and execute the sysled = 1 and enable the RDA int, only the 's' option does not. I'm really confused by this.
I have also included the .lst for the resulting code and haven't found an issue yet but thought someone might be able to shed some light on this before I run out of hair.
.................... case 's': get_song(0); //manual buffer print
0520: BSF 03.5
0521: CLRF 5D
0522: BCF 03.5
....................
.................... //for (loop_counter=0; loop_counter<index; loop_counter++){
.................... // fprintf(PC,"%u ",song[loop_counter]);
.................... //}
.................... //fprintf(PC,"\r\n");
.................... sysled = 1;
*
06A1: BSF 07.3
.................... break;
06A2: GOTO 6B9
.................... case 'd': printf(flow_putc,"i\r"); //get DIR info
06A3: MOVLW 69
06A4: BSF 03.5
06A5: MOVWF 61
06A6: BCF 03.5
06A7: CALL 483
06A8: MOVLW 0D
06A9: BSF 03.5
06AA: MOVWF 61
06AB: BCF 03.5
06AC: CALL 483
.................... delay_ms(5);
06AD: MOVLW 05
06AE: BSF 03.5
06AF: MOVWF 60
06B0: BCF 03.5
06B1: CALL 2A0
06B2: CLRF 27
06B3: BTFSC 0B.7
06B4: BSF 27.7
.................... print_buf();
06B5: CALL 24F
06B6: BTFSC 27.7
06B7: BSF 0B.7
.................... break;
06B8: GOTO 6B9
.................... }
.................... sysled = 1;
06B9: BSF 07.3
.................... enable_interrupts(int_rda);
06BA: BSF 03.5
06BB: BSF 0C.5
06BC: BCF 03.5
06BD: BCF 0A.3
06BE: BCF 0A.4
06BF: GOTO 72F (RETURN)
Sorry if this post is too long, but any help would be appreciated.
compiler ver = CCS PCM C Compiler, Version 3.130, 17162
using a 16f877
Thanks Dan |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Nov 08, 2006 4:37 pm |
|
|
If the code hangs as soon as you enable INT_RDA interrupts, you
probably have an overrun condition in the UART receiver. Check if
this is happening by adding the ERRORS parameter to your #use rs232()
statement. (You should always add this parameter). |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Nov 08, 2006 6:02 pm |
|
|
Thanks for the reply, I do indeed have the errors parameter for the HW uart. I also have it specified for the SW stream that is used with the EXT interrupt on PORT B0. Any other suggestions?
Rgds,
Dan |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Nov 08, 2006 6:27 pm |
|
|
Actually, the ERRORS parameter doesn't have any effect in software
UART. The compiler ignores it.
I don't understand your statement here:
Quote: |
The sysled = 1 after calling get_song works, but if I comment that out
the same sysled = 1 after the break does not and the code hangs |
There are three "sysled = 1" statements in your posted code.
Which one are you referring to, when you say "the same sysled = 1" ?
It seems to me that you have one of two types of problems:
1. There's a problem with the compiler, where the switch-case
statement is not being generated correctly in some instances.
2. The code is locking up for some other reason and it's not the
compiler's fault.
What happens if you comment out the call to get_song(0) ?
Does the program still lock up ?
Post the declaration statement for 'sysled'. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Nov 08, 2006 7:14 pm |
|
|
I never thought about what the errors would do with a soft uart, good thing the compiler ignores it then.
What I meant about the statement you questioned was that when the code reaches SYSLED=1 after returning from get_song the LED tied to that port lights up. If I comment out the SYSLED line mentioned, the same statement that would follow the BREAK statement (just before the enable_interrupts(int_rda);) doesn't light the led.
SYSLED is a bit corresponding to PORTC.3
I have a lot of the SYSLED=1 statements at various points to determine how far the code is progressing. I comment them out to see where the problem hangs.
Your idea to comment out the get_song routine is a really good idea. I'll try that in the morning as I don't have the code with me right now. Never thought to try it, getting a bit punchy looking through everything.
Thanks again for your input.
Dan |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Nov 08, 2006 10:33 pm |
|
|
Make sure that you are not enabling any interrupts which you do not have a handler for. The handler is declared with the #int_XXXX pragma. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
problem solved :) |
Posted: Thu Nov 09, 2006 7:47 am |
|
|
OK, I finally got to the source of the problems after a good nights sleep and some good direction from PCM and mark.
After commenting out my get_song(0); function I found the hang wasn't occuring so I dug into that function. I found the hang was occuring when I enabled my INT_EXT interrupt.
I believe what was happening was that the EXT interrupt wasn't clear when I was enabling it and therefore after enabling immediately was being serviced. As a result of the interrupt happening unexpectedly, my servicing routine was hanging waiting for data from the sw uart. I modified the handler to check for kbhit and fall through otherwise and all is well. I suppose I could have cleared the interrupt before enabling but this should prevent unexpected EXT interrupts from hanging else where.
Code: | ///////////////////////////////////////////////////
// Soft serial port ISR
#int_ext
ext_isr(){
int temp;
temp =0;
//not circular, just captures up to buffer size and when full prints it
if (kbhit(sd)){ //added to prevent hangup
temp = fgetc(sd);
cts=1;
sd_buff[sdnext_in] = temp;
sdnext_in ++;
if (sdnext_in == SDBUFFER_SIZE-1)
//sdnext_in --; // buffer full
print_buf();
cts = 0;
}
cts=0;
}
|
Thanks for the help/suggestions.
Dan |
|
|
|