reentracy trick

General discussion on mikroC.
Post Reply
Author
Message
ronnym
Posts: 2
Joined: 24 Jan 2008 17:50

reentracy trick

#1 Post by ronnym » 24 Jan 2008 18:15

Hi,
I have found a trick to avoind reentrancy check of mikroC compiler.
It seems works

here is an example:

Code: Select all

void Led(unsigned int cOn){
    PORTH.F3 = cOn;
}

void Led_Fake(unsigned int cOn){}

#pragma funcall Led_inter Led_Fake
// this pragma tell to MikroC that Led_inter will call
// only the function Led_Fake using indirect call (function pointers)

void Led_inter(unsigned int cOn){
    void (*pLed)(unsigned int cOn);
    pLed = &Led;
    pLed(cOn);
}

#pragma funcall Led_main Led
// this pragma tell to MikroC that Led_main will call
// only the function Led using indirect call (function pointers)

// So MikroC belive that the 2 functions will call different function
// and so thinks that there is not reentrancy

void Led_main(unsigned int cOn){
    unsigned char cSaveGIE;
    void (*pLed)(unsigned int cOn);

    cSaveGIE = INTCON.GIE;
    INTCON.GIE = 0;

    pLed = &Led;
    pLed(cOn);

    INTCON.GIE = cSaveGIE;
}

// Led_main call led using function pointer but do that disabling
// interrupts (and saving the state in order to restore at the end
// of the funtcion)
// This is important, because if during that function execution, 
// an interrupt that executes LED starts through LED_INTER wrapper,
// there would be problems with local variables and parameters. 
// In fact, these aren't allocated by compiler at runtime: 
// they are statically allocated

// Now into interrupt you can use function Led
// calling the wrapper function Led_inter

void interrupt(void){
    Led_inter(0);
}

// And into main you can use function Led
// calling the wrapper function Led_main


void main(){
    Led_main(1);
}

I hope this will help.

Ronny

Epik srl
www.epik.it

telknarf
Posts: 7
Joined: 20 Jan 2009 07:33

#2 Post by telknarf » 02 Feb 2009 09:18

Hi..Thanks for the tip..
Just want to ask, does this dont have any constraints or limitations?

Dany
Posts: 3854
Joined: 18 Jun 2008 11:43
Location: Nieuwpoort, Belgium
Contact:

#3 Post by Dany » 02 Feb 2009 19:40

telknarf wrote:Hi..Thanks for the tip..
Just want to ask, does this dont have any constraints or limitations?
Hi, some info on re-entry: http://www.ganssle.com/articles/begincornerent.htm :D
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)

telknarf
Posts: 7
Joined: 20 Jan 2009 07:33

#4 Post by telknarf » 04 Feb 2009 12:35

Hi Dany, thanks for the reply. Ill also try this one out.
By the way, you might have known this technique but for those who dont know this yet and met the same problem as mine, I also found another solution to this one and that is by having flags. By means of this, I dont need to put function calls to interrupts but instead have flags(or variables) within it and the function calls or actions for it will be done in the main loop. So, in this case, if there will be interrupts occuring in an instant, it will just set a value to my flags so that when the program exits the interrupt function, it will go back to the main loop, and when the program sees that the flag meets its condition(because the interrupt changes its value, thereby meeting the condition), the actions(or function calls) for that interrupt will occur or execute.

Dany
Posts: 3854
Joined: 18 Jun 2008 11:43
Location: Nieuwpoort, Belgium
Contact:

#5 Post by Dany » 04 Feb 2009 17:23

telknarf wrote:By the way, you might have known this technique but for those who dont know this yet and met the same problem as mine, I also found another solution to this one and that is by having flags. By means of this, I dont need to put function calls to interrupts but instead have flags(or variables) within it and the function calls or actions for it will be done in the main loop. So, in this case, if there will be interrupts occuring in an instant, it will just set a value to my flags so that when the program exits the interrupt function, it will go back to the main loop, and when the program sees that the flag meets its condition(because the interrupt changes its value, thereby meeting the condition), the actions(or function calls) for that interrupt will occur or execute.
Nice! This is of course much better than calling the same routine in the main and the interrupt routine. :D :D
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)

Kalain
Posts: 1093
Joined: 11 Mar 2005 18:26
Location: Aubenas, France

#6 Post by Kalain » 15 May 2009 22:59

telknarf wrote:Hi Dany, thanks for the reply. Ill also try this one out.
By the way, you might have known this technique but for those who dont know this yet and met the same problem as mine, I also found another solution to this one and that is by having flags. By means of this, I dont need to put function calls to interrupts but instead have flags(or variables) within it and the function calls or actions for it will be done in the main loop. So, in this case, if there will be interrupts occuring in an instant, it will just set a value to my flags so that when the program exits the interrupt function, it will go back to the main loop, and when the program sees that the flag meets its condition(because the interrupt changes its value, thereby meeting the condition), the actions(or function calls) for that interrupt will occur or execute.
Interesting point of view.
Can someone post small code to show the idea. (I'm not sure to understand correctly everything.

Thanks
Alain

Kalain
Posts: 1093
Joined: 11 Mar 2005 18:26
Location: Aubenas, France

#7 Post by Kalain » 29 May 2009 12:14

telknarf wrote:Hi Dany, thanks for the reply. Ill also try this one out.
By the way, you might have known this technique but for those who dont know this yet and met the same problem as mine, I also found another solution to this one and that is by having flags. By means of this, I dont need to put function calls to interrupts but instead have flags(or variables) within it and the function calls or actions for it will be done in the main loop. So, in this case, if there will be interrupts occuring in an instant, it will just set a value to my flags so that when the program exits the interrupt function, it will go back to the main loop, and when the program sees that the flag meets its condition(because the interrupt changes its value, thereby meeting the condition), the actions(or function calls) for that interrupt will occur or execute.
Hi,

just ten lines of example to show the idea would be nice.

Thanks
Alain

naknak
Posts: 82
Joined: 14 Feb 2008 20:35
Location: The Earth

#8 Post by naknak » 03 Jun 2009 19:10

The above example shows a way to create a #pragma entry in the mcu Defs file (re-creation of a library). It is a great idea, but what about recreating the built-in functions such as VDelay? I need to re-create the VDelay function to avoid the re-entrancy error. Any idea? Thanks.

bobx
Posts: 115
Joined: 14 Mar 2010 08:35

Re: reentracy trick// RE1;Reentrancy Problem

#9 Post by bobx » 10 May 2010 14:35

Hi,ronnym.I also have reentrancy problem in my program.My compiler
mikroC PRO V2.50,give me these error messages;


184 365 Reentrancy is not allowed: function 'Lcd_Out' called from two threads __Lib_Lcd.c
184 365 Reentrancy is not allowed: function 'Lcd_Out' called from two threads __Lib_Lcd.c
50 365 Reentrancy is not allowed: function 'Lcd_Chr_CP' called from two threads __Lib_Lcd.c
18 365 Reentrancy is not allowed: function 'Lcd_Cmd' called from two threads __Lib_Lcd.c
0 102 Finished (with errors): 10 May 2010, 17:39:42 t4x.mcppi


I read your trick but I do not know how I must modified and used that for my program.
Would you please help me to apply and write that?

Here are my code firmware and program;

Code: Select all

       
#define stepsize  98
int  t4=0,index;
char *tc;
int  adcvalmax[8];
int  interb0=0;

void Display_AdcX(int adcvalmax[8] ) {
   int i=0,m=0;
   char ch[8];
 extern int adcvalmax[8];// 16 1504 Initialization of extern object 'adcvalmax' t1x.c //
   memset(adcvalmax,0,8*sizeof(int));
   memset(ch,0,8*sizeof(int));

  for(i,m=0;i,m<8;i++,m++){ //IS THIS FOR STATEMENT RIGHT? ****************

  ch[i] = adcvalmax[m] /1000; //prepare value for display in A
  Lcd_Chr(2, 1, 48 + ch[i]); //write ASCII at 2nd row,1st column
  Lcd_Chr_Cp('.');

  ch[i]    = (adcvalmax[m] /100) % 10;
  Lcd_Chr_Cp(48 + ch[i]);

  ch[i]   = (adcvalmax[m] /10) % 10;
  Lcd_Chr_Cp(48 + ch[i]);

  ch[i]    = adcvalmax[m] % 10;
  Lcd_Chr_Cp(48 + ch[i]);
  Lcd_Chr_Cp('A');

  }

}//~


void MR_CHNS(int adcvalmax[8]){

    long longadc=0;
  extern int adcvalmax[8];// 43 1504 Initialization of extern object 'adcvalmax' t1x.c//
    int ch[8];//declares a array of 8 integers
    int m=0,i=0;
    int Px=0,P1st=0,P2nd=0;

    memset(adcvalmax,0,8*sizeof(int));
    memset(ch,0,8*sizeof(int));

  for(i=0;i<8;i++){

     for(m=0;m<8;m++){

       do{
          ch[i]=ADC_Read(i);
          Px=ch[i];
         }while(Px!=0);

      P1st=ADC_Read(m);
      Delay_ms(10);//10 ms pause
      P2nd=ADC_Read(m);

       while(P1st<=P2nd){
            P1st=P2nd;
            P2nd=0;
         P2nd=ADC_Read(m);
       }

   adcvalmax[m] = P1st;// if (vf>vn)
   index = (stepsize);
   ADRESH = (ADRESH)&&(0b00000011);
   longadc = ADRESH + ADRESL;
   adcvalmax[m] = longadc * index;//in mA or mv

     }
  }

}//~



void update_pwm(unsigned short int rp2val){
    rp2val=0;

    t4  = Adc_Read(4);
    rp2val = ADRESL;


    PWM1_Set_Duty(rp2val);//Set & change duty ratio due to the VRP2 value
                                                         //from 0 -255;(ADRESL)


    LCD_Out(2,14,&rp2val);// 96 1508 Implicit conversion of int to ptr t1x.c //

                //(127: 50% duty ratio)
    if(rp2val == 127) PORTC.F5=1;//Turn the LED on (RC5/pin24)

}//~



void interrupt() {

  static int interb0;
                            //Turn off charger interrupt via INTO/RB0
  INTCON.INT0IF=0;//Clear INT0(INTCON)external interrupt Flag bit to detect
                                                                 //next inter.
  interb0++;//interb0 = interb0+1

  while(interb0 ==1){

    PWM1_Stop();//Stop PWM


  LCD_Cmd(_LCD_CLEAR);// send command  to LCD (clear LCD)
  tc = "STAND BY!";// assign a text to string
  LCD_Out(1,1,tc);// print a string  on LCD, 1st row, 1st column

    PORTC.F3=1;//Turn the LED on (RC3/pin18):LED stand by state indicator
    Delay_ms(1000);//One second pause
    PORTC.F3=0;//Turn the LED off (RC3/pin18)
   }

 if(interb0!=1){
  PWM1_Start();//Start PWM ,(interb0!=1)
  interb0 = 0;
  PORTC.F3=0;//Turn the LED off (RC3/pin18)
  }

}//~


// LCD module connections
sbit LCD_RS at RD2_bit;
sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;

sbit LCD_RS_Direction at TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
// End LCD module connections


void main() {

  PORTA=0;//Clear port A
  TRISA=0XFF;//Port A is input
  PORTD=0;//Clear port D
  TRISD=0;//Port D is output
  PORTC=0;//Clear port C
  TRISC=0;//port C is output
  PORTB=0;//Clear port B
  TRISB=0XFF;//port B is input
  PORTE=0;//Clear port E
  TRISE=0XFF;//Port E is input
  TRISC = PORTC = 0;

  INTCON.GIEH = 1; // When IPEN = 1,enables all high priority interrupts
  INTCON.GIEL=1;//When IPEN = 1,enables all low priority peripheral interrupts
  RCON.IPEN = 1;//Enable priority levels on interrupts
  INTCON.INT0IE=1;//Enables the INT0 external interrupt
  INTCON2.INTEDG0 = 0;// Interrupt on falling edge


  LCD_Init();// initialize(4-bit interface connection)
  LCD_Cmd(_LCD_CURSOR_OFF);// send command to LCD (cursor off)
  LCD_Cmd(_LCD_CLEAR);// send command  to LCD (clear LCD)
  tc = "Hi!";// assign a text to string
  LCD_Out(1,1,tc);// print a string  on LCD, 1st row, 1st column



  PWM1_Init(500);//500HZ but should Initialize PWM module at 50HZ ;
                                //using frequency divider with D-Flip_Flop IC.
  PWM1_Set_Duty(127);//Set duty ratio to 50%



  update_pwm(t4);
  PWM1_Start();//Start PWM


  //Not required to determine ADCON0;it is asked by uC compiler on NEW Project
  // icon bar at the top at first automatically &done via:Adc_Read() Library

  ADCON1=0x80;//configure VDD=Vref+,Vss=Vref-,8-analog channels&Right justified
                                                           //A/D Result Format
  Delay_ms(2000);


  MR_CHNS(adcvalmax);
  Display_AdcX(adcvalmax);



  }//~!






              0 1 mikroCPIC1618.exe -MSF -DBG -pP18F452 -DL -O11111114 -fo8 -N"E:\XT1\t4x.mcppi" -SP"E:\Bob's File\mikroC PRO PIC 2009 V2.50\MikroCProV2.50\defs\" -SP"E:\Bob's File\mikroC PRO PIC 2009 V2.50\MikroCProV2.50\uses\P18\" -SP"E:\XT1\" "t4x.c" "__Lib_Math.mcl" "__Lib_MathDouble.mcl" "__Lib_System.mcl" "__Lib_Delays.mcl" "__Lib_CType.mcl" "__Lib_CString.mcl" "__Lib_CStdlib.mcl" "__Lib_CMath.mcl" "__Lib_Conversions.mcl" "__Lib_Sprintf.mcl" "__Lib_PrintOut.mcl" "__Lib_Sprinti.mcl" "__Lib_Sprintl.mcl" "__Lib_Time.mcl" "__Lib_Trigonometry.mcl" "__Lib_Button.mcl" "__Lib_Keypad4x4.mcl" "__Lib_Manchester.mcl" "__Lib_OneWire.mcl" "__Lib_PS2.mcl" "__Lib_Sound.mcl" "__Lib_SoftI2C.mcl" "__Lib_SoftSPI.mcl" "__Lib_SoftUART.mcl" "__Lib_ADC_A_C.mcl" "__Lib_EEPROM_256.mcl" "__Lib_FLASH_w8_e64.mcl" "__Lib_I2C_c34.mcl" "__Lib_PWM_c21.mcl" "__Lib_SPI_c345.mcl" "__Lib_UART_c67.mcl" "__Lib_PortExpander.mcl" "__Lib_CANSPI.mcl" "__Lib_CF.mcl" "__Lib_CFFat16.mcl" "__Lib_GlcdFonts.mcl" "__Lib_Glcd.mcl" "__Lib_LcdConsts.mcl" "__Lib_Lcd.mcl" "__Lib_Mmc.mcl" "__Lib_MmcFat16.mcl" "__Lib_RS485.mcl" "__Lib_T6963C.mcl" "__Lib_SPIGlcd.mcl" "__Lib_SPILcd.mcl" "__Lib_SPILcd8.mcl" "__Lib_SPIT6963C.mcl" "__Lib_EthEnc28j60.mcl"  
0 125 All files Preprocessed in 15 ms  
0 121 Compilation Started t4x.c
223 122 Compiled Successfully t4x.c
0 126 All files Compiled in 157 ms  
184 365 Reentrancy is not allowed: function 'Lcd_Out' called from two threads __Lib_Lcd.c
184 365 Reentrancy is not allowed: function 'Lcd_Out' called from two threads __Lib_Lcd.c
50 365 Reentrancy is not allowed: function 'Lcd_Chr_CP' called from two threads __Lib_Lcd.c
18 365 Reentrancy is not allowed: function 'Lcd_Cmd' called from two threads __Lib_Lcd.c
0 102 Finished (with errors): 10 May 2010, 17:39:42 t4x.mcppi





Thanks & Regards,











ronnym wrote:Hi,
I have found a trick to avoind reentrancy check of mikroC compiler.
It seems works

here is an example:

Code: Select all

void Led(unsigned int cOn){
    PORTH.F3 = cOn;
}

void Led_Fake(unsigned int cOn){}

#pragma funcall Led_inter Led_Fake
// this pragma tell to MikroC that Led_inter will call
// only the function Led_Fake using indirect call (function pointers)

void Led_inter(unsigned int cOn){
    void (*pLed)(unsigned int cOn);
    pLed = &Led;
    pLed(cOn);
}

#pragma funcall Led_main Led
// this pragma tell to MikroC that Led_main will call
// only the function Led using indirect call (function pointers)

// So MikroC belive that the 2 functions will call different function
// and so thinks that there is not reentrancy

void Led_main(unsigned int cOn){
    unsigned char cSaveGIE;
    void (*pLed)(unsigned int cOn);

    cSaveGIE = INTCON.GIE;
    INTCON.GIE = 0;

    pLed = &Led;
    pLed(cOn);

    INTCON.GIE = cSaveGIE;
}

// Led_main call led using function pointer but do that disabling
// interrupts (and saving the state in order to restore at the end
// of the funtcion)
// This is important, because if during that function execution, 
// an interrupt that executes LED starts through LED_INTER wrapper,
// there would be problems with local variables and parameters. 
// In fact, these aren't allocated by compiler at runtime: 
// they are statically allocated

// Now into interrupt you can use function Led
// calling the wrapper function Led_inter

void interrupt(void){
    Led_inter(0);
}

// And into main you can use function Led
// calling the wrapper function Led_main


void main(){
    Led_main(1);
}

I hope this will help.

Ronny

Epik srl
www.epik.it

Hamda binte Ajmal
Posts: 2
Joined: 20 May 2011 20:01

Re: reentracy trick

#10 Post by Hamda binte Ajmal » 21 May 2011 12:28

Hey, i am making a system , the where MCU (PIC18F452) continously reads data from GPS via Soft_UART, and whenever an interrupt on UART1 Rx pin occurs, it starts reading data from UART1. the thing is, how can i avoid reentrancy errors ? Since im totally new in this field, can you please help me out in modifying my code? also is there an option i can disable the interrupt just before calling the re entrant function in main() ? PLease HELP

Code: Select all

void interrupt() {
/*if(timer==1)
  {cnt++;}               // Increment value of cnt on every interrupt
  TMR0L  = 96;
  INTCON = 0x20;       // Set T0IE, clear T0IF*/
   if (PIR1.RCIF)
   {
  if(UART1_Data_Ready())
{
UART1_Read_Text(junk,"\r\n",255);
//Lcd_Chr_Cp('a');
UART1_Read_Text(header, "\r\n",255);
//Lcd_Chr_Cp('b');
UART1_Read_Text(message, "\r\n",255);
//Lcd_Chr_Cp('c');
Lcd_Out(2,12,header);
 Lcd_Out(3,12,message);
 if(header[0]=='+' && header[1]=='C' && header[2]=='M' && header[3]=='T')
 {
 Lcd_Out(1,10,"new message");
 new_message=1;
 }
 else
     {
     new_message=0;
     }
 }
 }
}

void main()
{
Lcd_Init();
Lcd_Cmd(_Lcd_CLEAR);
Lcd_Cmd(_Lcd_CURSOR_OFF);

i=Soft_UART_Init(&PORTC, 4,5,4800,0);
UART1_Init(9600);
UART1_Write_Text("AT+cmgf=1");
delay_ms(1000);
UART1_Write(13);
while(!UART1_Data_Ready())
{}
if(UART1_Data_Ready())
{

UART1_Read_Text(junk,"OK\r\n",255);

}


UART1_Write_Text("AT+ cnmi=0,2,2,1");
delay_ms(1000);
UART1_Write(13);
while(!UART1_Data_Ready())
{}
if(UART1_Data_Ready())
{
UART1_Read_Text(junk,"OK\r\n",255);
}
cnt = 0;              // Initialize cnt
 INTCON.GIE = 1;
INTCON.PEIE = 1;
PIE1.RCIE = 1; //enable interrupt.
TRISD.f2=1;
TRISD.f3=1;
PORTD=0x00;
while(1)
{
 while(!UART1_Data_Ready())   //read from GPS
 {
//process this data }

}
} 



User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: reentracy trick

#11 Post by filip » 23 May 2011 09:18

Hi,

I believe I have answered you on the Support desk.

Regards,
Filip.

cclinus
Posts: 4
Joined: 09 Jul 2012 05:22

Re: reentracy trick

#12 Post by cclinus » 12 Jul 2012 15:34

Hi,

Thanks for posting this trick.
I found that this trick can be further simplified.

Code: Select all

void LED_ON(int c){
     RD0_bit=1;
}

#pragma funcall interrupt

void interrupt(){
     void(*pFun)(int c);
     pFun=&LED_ON;
     pFun(1);
}

void main() {
     void(*pFun)(int c);
     pFun=&LED_ON;
     
     TRISD=0;
     PORTD=0;
     
     pFun(1);
     
     while(1);
}
Tested on Pro V5.61.

janni
Posts: 5373
Joined: 18 Feb 2006 13:17
Contact:

Re: reentracy trick

#13 Post by janni » 13 Jul 2012 13:25

Yes, it works with last versions of mC. Don't think it worked while ronnym posted his trick, though.

Anyway, while it's possible to force full reentrancy (with all it's risks), it's in some cases impossible to convince compiler that there's no reentrancy when there in fact isn't. Pragma funcall works kind of in reverse. Easily accepts false information while rejecting a true one.

Imbalanc3
Posts: 7
Joined: 27 Dec 2014 09:28

Re: reentracy trick

#14 Post by Imbalanc3 » 05 Feb 2015 16:30

cclinus wrote:Hi,

Thanks for posting this trick.
I found that this trick can be further simplified.

Code: Select all

void LED_ON(int c){
     RD0_bit=1;
}

#pragma funcall interrupt

void interrupt(){
     void(*pFun)(int c);
     pFun=&LED_ON;
     pFun(1);
}

void main() {
     void(*pFun)(int c);
     pFun=&LED_ON;
     
     TRISD=0;
     PORTD=0;
     
     pFun(1);
     
     while(1);
}
Tested on Pro V5.61.
will this work on library funtions such as atoi???

Post Reply

Return to “mikroC General”