|
|
View previous topic :: View next topic |
Author |
Message |
bwgames
Joined: 21 Jul 2005 Posts: 36
|
Interrupts disabled during call to prevent re-entrancy |
Posted: Fri Jul 14, 2006 2:20 am |
|
|
Getting the above error in my code, is there anyway to determine where interrupts are being disabled.
My int_rda getch()s, and based on what character it is/what flags are set, either writes it to a command buffer or sets flags, or discards
When compiling it, I get 'interrupts disabled to prevent re-entrancy', yet my int_rda only calls the fgetc(), and sets some other flags....
I do use delay_ms(); in other functions called from main() though - could this be the cause? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
bwgames
Joined: 21 Jul 2005 Posts: 36
|
|
Posted: Fri Jul 14, 2006 2:34 am |
|
|
I've seen that, but I wasn't sure if:
"There must be some function that you're calling from inside the isr
and outside as well. It would help if you could post a small but
complete test program."
relates to functions called from functions?
I.e. I call fgetc from the int_rda, which I believe has delay_ms in it? Even though I haven't called delay_ms specifically in my interrupt, it would still say interrupts disabled due to fgetc using it, and also my using delay_ms in my other code?
This is my int_rda - Am I doing too much in it?
Code: |
#int_rda
void serial_isr() {
int t;
buffer[next_in]=fgetc(Wireless);
t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
if((buffer[next_in] =='~')&&(cmdflag==1)&&(cmdbfr_size==14)&&(px_cmd==0))
{
//Signifies END OF COMMAND
output_low(PIN_E2); //Flashes debug LED
cmdflag =0;
dataflag=1;
cmdrx=1;
cmdbfr_size=0;
error_cmdrx=0;
// In the command buffer will be: "RX001DATATX001" (or whatever)
}//End of Command IF
if((cmdflag==1)&&(px_cmd==0))
{
if(cmdbfr_size==14)
{
//BUFFER FULL, EITHER CMD TOO LONG, OR ~ CHARACTER LOST - SET CMDFLAG = 0
cmdflag=0;
error_CMDRX=1;
cmdbfr_size=0;
} //end of errror buffer if
cmdbuffer[cmdbfr_size]=buffer[next_in];
cmdbfr_size++;
}//end of cmdflg=1
if((buffer[next_in] == '$')&&(px_cmd==0))
{
// $ signifies START OF COMMAND
output_high(PIN_E2); //debug LED
cmdflag = 1;
cmdbfr_size=0;
cmdrx=0;
}
}//end of int_RDA
|
Also, I read of people just having a while(1) loop in main, whilst everything else is handled by interrupts. I'm keen to do this this way - however, in my main I have
Code: |
void main() {
//Store a variable that has the TYPE in a fprint'able format
if(TYPE==1) //TX
{
ttype[0]='T';
ttype[1]='X';
ttype[2]=NULL;
}
if(TYPE==2) //RX
{
ttype[0]='R';
ttype[1]='X';
ttype[2]=NULL;
}
fprintf(Computer, "\r\n\Running...\r\n");
enable_interrupts(global);
enable_interrupts(int_rda);
while(1)
{
if((cmdrx==1)&&(error_cmdrx==0)&&(cmdflag==0))
{
//IF CMD RX
px_cmd=1; //FORCE INT_RDA TO NOT ACCEPT ANY MORE *COMMANDS* WHILST PROCESSING THIS ONE
process_cmd();
}//end of cmdrx
} //end of while 1
} //end of main
|
It is mostly just initialisation, which I can't put anywhere else, I don't think... but my if((cmdrx==1)&&(error_cmdrx==0)&&(cmdflag==0)), I'd like to get rid of.
Those variables (cmdrx,error_cmdrx, cmdflag) are set in int_rda.
Is there any way to remove that if from main and place it elsewhere.
The logical place would be int_rda, but calling a function would be a big no-no?
px_cmd is a variable that int_rda checks to see whether the routine is processing any command at the moment, so it knows whether or not it can touch the command buffer.
I guess what I'm looking for is "interrupt-on-variable-change"..? |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
Posted: Fri Jul 14, 2006 5:10 am |
|
|
You did not submit your #use rs232 statement
You can rule out fgetc() simply by using your own RS232 Uart handler. A quick and dirty test (dirty because it does not handle errors) is replace your fget(c) with a your variable = RCREG (read the UART directly). You will need to specify the address of the register with a #byte RCREG 0x0Fxx where 0xFxx is the address of this register for your processor.
Quote: | Also, I read of people just having a while(1) loop in main, whilst everything else is handled by interrupts. I'm keen to do this this way - however, in my main I have |
That's because they do not understand how to write good interrupt handlers. Its obvious if you think about it - the mainline is doing nothing - the only thing the processor does is handle interrupts. In which case interrupts are of no value - may as well put the code in the mainline and make everything simpler.
Are you doing too much in the handler? Absolutely. You are doing stuff that does not need to be done in the handler and it provides you no value with it being there. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
bwgames
Joined: 21 Jul 2005 Posts: 36
|
|
Posted: Fri Jul 14, 2006 5:35 am |
|
|
Thanks for the info...
What I'm not too clear on....
You seem to be saying that most of the stuff I'm doing in int_rda I could do somewhere else, I agree with this.
What I'd like to do, is simply have int_rda read into a buffer, set a flag to signify new data received in the buffer, and for a routine to do all the 'post-processing' - i.e. if(buffer[next_in... e.g.
Code: |
#int_rda
void rda_isr()
{
buffer[buffersize++] = fgetc(Wireless);
buffer_new=1;
}
|
What I don't get, is how to run this other routine when that flag is set.
I could keep checking the buffer as I go through my program, i.e. if(buffer_new==1) processbuffer();, but ideally what I want is for a routine to be ran when a flag is set, e.g. a command indicator ($ etc) is received on the buffer.
All my ISR does is check if the input matches a certain character, then sets some flags, or if a flag is set, it puts it into the corronsponding buffer.
I would prefer to have int_rda like above, and have another routine sorting it into the correct sub-buffer (command/data etc) depending on character/flags previously set.
But, I don't see any other way of doing this apart from putting it all in int_rda?
Perhaps I should explain what I am trying to do...
The UART is connected to a wireless receiver, with several other devices that will also be transmitting. The start of a command is signified by $ and the end by ~, when the command buffer that int_rda is reading into has a complete command, the if( in main sends it to process_cmd(); which looks at the command to check if it is for that device, if it is, it processes it, if it isn't, it gets discarded.
Ideally I would like process_cmd to be ran straight after a full command is received (signified by cmdrx==1, which is set in int_rda), rather than having to keep checking whether one is received as I am now. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
Posted: Fri Jul 14, 2006 6:01 am |
|
|
What you are trying to do is a pretty common requirement.
Here is an example of how to code an interrupt handler to read into a ring buffer.
Code: | #int_RDA
void serial_isr()
{
// ; test for overrun error
if (bit_test(RCSTA, OERR))
{
bit_clear(RCSTA, CREN); // clear continous receive bit
bit_set(RCSTA, CREN); // set continous receive bit
}
RxBaseC[RxHeadC++]=getc();
RxHeadC %= RxCQsize;
} |
Here's an example of a function you call from your main while loop:
Code: | void ServiceRxQConsole()
///////////////////////////////////////////////////////////////////////////
// ServiceRxQConsole
//
// Basic polled Console Rx Q service subroutine (NON BLOCKING)
// Receives a byte from the Console Rx buffer and queues it to the
// console command buffer.
//
// Once a <CR> has been detected SrvCMD is invoked.
//
///////////////////////////////////////////////////////////////////////////
{
char LastC;
while (RxTailC != RxHeadC)
{
LastC = getc_QConsole();
switch (LastC)
{
case 0x0d: // <CR>
CCRC[CntCmdC] = 0; // terminate the string with a NULL
SrvCmd(CCRC); // go service the command
CntCmdC = 0; // initialise number of characters in the command buffer
break;
case 0x0a: // <LF>
break;
default :
CCRC[CntCmdC] = LastC; // put into the command construction register
CntCmdC = (CntCmdC + 1) % CCRSize; // ensure command register does not overflow
break;
}
}
} |
This code extracts a sequence from a ring buffer to a linear buffer based on your start and end character delimiter. Once you have it all the function SrvCmd is invoked with the string in a linear buffer. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
|
|
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
|