|
|
View previous topic :: View next topic |
Author |
Message |
davidbue
Joined: 05 Nov 2007 Posts: 28 Location: Denmark
|
Interrupts disabled warning drives man crazy |
Posted: Thu Dec 13, 2012 3:42 am |
|
|
Dear all.
Please see the code example below. I cannot get rid of the compiler warning:
interrupts disabled during call to prevent re-entrancy (@DIV88)
Commenting out the line printf(bputc,"start\r\n"); magically makes the compiler warning go away.
I have now spent 3 days reading discussion forums to no prevail, thus a cry for help is due! Arhm so... help... h..h.. help! Help HELP!
Header:
Code: |
#opt 10 //Optimization level when compiling the code. 11 is the highest level for pic18xx
#include <18F2620.h>
#device adc=10 //All ADC calculations are done as 10 bit integers (0-1023)
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES NOPUT //No Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES BORV20 //Brownout reset at 2.0V
#FUSES PBADEN //PORTB pins are configured as analog input channels on RESET
#FUSES LPT1OSC //Timer1 configured for low-power operation
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOCPB //No Boot Block code protection
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#use delay(int=32000000) //Running @ 8mhz on internal oscilator x 4PLL = 32mhz
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORT1)
|
Program:
Code: |
#include <main.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
//Transmit buffer setup:
#define T_BUFFER_SIZE 255
byte t_buffer[T_BUFFER_SIZE];
byte t_next_in = 0;
byte t_next_out = 0;
//Recieve buffer setup:
#define R_BUFFER_SIZE 1024
byte r_buffer[R_BUFFER_SIZE];
long r_next_in = 0;
long r_next_out = 0;
#int_RTCC
void RTCC_isr(void)
{
set_timer0(64716); //Will timeout each 100 microsec.
}
#int_RDA
void RDA_isr(void)
{
int t;
r_buffer[r_next_in]=getc();
t=r_next_in;
r_next_in=(r_next_in+1) % R_BUFFER_SIZE;
if(r_next_in==r_next_out)
r_next_in=t; // Buffer full !!
}
#int_TBE
void TBE_isr(void)
{
if(t_next_in!=t_next_out)
{
putc(t_buffer[t_next_out]);
t_next_out=(t_next_out+1) % T_BUFFER_SIZE;
}
else
disable_interrupts(int_tbe);
}
//This function puts a character into the outbound serial buffer.
void bputc(char c) {
short restart;
int ni;
restart=t_next_in==t_next_out;
t_buffer[t_next_in]=c;
ni=(t_next_in+1) % T_BUFFER_SIZE;
while(ni==t_next_out);
t_next_in=ni;
if(restart)
enable_interrupts(int_tbe);
}
#define bkbhit (r_next_in != r_next_out)
//This function reads a character from the inbound serial buffer.
BYTE bgetc() {
BYTE c;
// The following line is not needed so long as bkbhit() is polled before calling bgetc().
// while(!bkbhit) ; //this line can freeze the system if called when no data exists and none is coming in.
c = r_buffer[r_next_out];
r_next_out = (r_next_out + 1) % R_BUFFER_SIZE;
return(c);
}
//This helper-function returns the length of a character arry.
int length(char string[]) {
int index;
for (index = 0; string[index] != '\0'; ++index)
continue;
return (index);
}
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
enable_interrupts(INT_RDA);
enable_interrupts(INT_TBE);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
setup_adc_ports(AN0_TO_AN1|VSS_VDD);
setup_adc(ADC_CLOCK_INTERNAL|ADC_TAD_MUL_0);
setup_oscillator(OSC_8MHZ|OSC_TIMER1|OSC_31250|OSC_PLL_ON);
// Wait till all subsystems of the controller board are ready
delay_ms(100);
// Report system ready:
printf(bputc,"start\r\n");
while(1){
//TODO: Awesome stuff
}
}
|
|
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Thu Dec 13, 2012 4:20 am |
|
|
There's nothing magic about it. A simple understanding of what the compiler does is enough.
The warning message is telling you that a routine that's called in the ISR is also called from mainline code, and that to prevent re-entrancy (which most PICs cannot support) code to disable interrupts has been placed aroung the calls in mainline code.
So which routine is it? Its perhaps not immediately obvious, but if you think about its the % operator, which is implemented by a call to a built-in routine. It is not an intrinsic operation of the hardware and is not implmented inline. Its that printf calls bputc, which includes % to buffer the characters. No magic. Well there is, sort of. There isn't just one % routine there are many possible ones that the compiler might use, depending on data type. You could probably have a unsigned 8 bit % in an ISR and a 32 bit % in mainline code happily co-existing, but here both uses are of the same unsigned 8 bit version. The warning message tells you the name of the actual routine involved: DIV88, which sounds like divide 8 bits by 8 bits to me....
The example code is example code, not fully finished drivers that can be used in all cases and in all combinations. What you have done, sensibly, is take EX_SISR.C and EX_TISR.C and put them together in one bit of code. That doesn't quite work. In ex_sisr % in the ISR, in ex_tisr its in mainline code. They work fine on their own but are not quite compatible with each other.
Also the code is not optimal: its just an example, not gold standard certified optimal driver code. It uses the modulus operator, that involves a divide - which is not implemented by hardware and so needs to be done as a routine. That allows the buffer to be any length, which is fine for an example. Real buffers are more commonly powers of two lengths, and so simple shifts or bit comparisions can be used instead of the expensive modulus. The simplest is to make your buffers 256 bytes long and use an int8 as the buffer index. Then it wraps round totally automatically without any code overhead at all. Simple comparisons are generally the better solution for generic, non-power of two, buffer lengths.
RF Developer |
|
|
davidbue
Joined: 05 Nov 2007 Posts: 28 Location: Denmark
|
|
Posted: Thu Dec 13, 2012 4:49 am |
|
|
You are brilliant! Thank you SO much for the reply.
You made understand the cause and how to fix it.
Big kudos! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Dec 13, 2012 5:40 am |
|
|
As a solution, worth using the alternative way of solving the calculation:
Code: |
if (++r_next_in==R_BUFFER_SIZE) r_next_in=0;
|
Instead of performing the modulus operation, you just add one to the pointer, and test if it is now at the end. If it is, load it with zero.
Obviously same for the transmit buffer.
No % involved.
Best Wishes |
|
|
davidbue
Joined: 05 Nov 2007 Posts: 28 Location: Denmark
|
|
Posted: Thu Dec 13, 2012 6:07 am |
|
|
That is indeed a beautiful solution to the problem. Thank you!!! It's now implemented. |
|
|
|
|
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
|