CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

What is causing Stack underflow on inline assembly

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kein



Joined: 23 Jul 2007
Posts: 103

View user's profile Send private message

What is causing Stack underflow on inline assembly
PostPosted: Thu Feb 05, 2015 9:16 am     Reply with quote

Gents,
I'm having stack underflow issue with my code. I've written an inline assembly code as shown below. For some reasons, it generates "stack underflow executing return instruction". When I ran the program, it never goes pass the inline assembly function and never execute the last two functions:"delay_ms(50); output_b(0x00);"

Code:
#include <16F877A.h>
#use delay(crystal=20MHZ)
#FUSES HS,NOWDT,NOLVP,NODEBUG,PUT,BROWNOUT //No Watch Dog Timer
#define Porta 0x05 //clock PIN_A1

void paralIn165(byte buff);
unsigned char rcvReg;
void main()
{
   unsigned char cntrlWord;
   set_tris_a(0b00000001); //porta are all outputs; pin 1 is input
   set_tris_b(0b00000000); //all buits of port is set for output

   cntrlWord = 0x04;
   rcvReg = 0x00;
   output_b(0b00000000);
   output_high(PIN_A2);
   
   while(1)
   {
      //TODO: User Code
     delay_ms(5);
     output_b(rcvReg);
     paralIn165(cntrlWord);
     delay_ms(50);
     output_b(0x00);
     delay_ms(200);
   }

}

void paralIn165(int8 buff)
{
   unsigned char tmp;
   unsigned char counter;
   #asm
      clrf rcvReg ; clear receive register
      movlw 0x08 ;w = 8
      movwf counter ;counter = w = 8
      bcf porta, 2 ;clear bit number 2
      bsf porta, 2 ;set bit number 2
    getBit:
      movlw 0b00000001 ;
      movwf tmp ;save in temp
      rrf tmp, f ;rotate bit into carry flag
      rlf rcvReg,f ;rotate the received bit into received buffer
      decfsz counter,f ;decrement counter skip next instruction if 0
      goto shift
      return
   shift: ;clock in the data
      bsf porta, 1
      bcf porta, 1
      goto getBit ;get another bit
   #endasm
}


I will appreciate your help with this.

Thanks. Exclamation Exclamation Exclamation Exclamation Exclamation
Jerson



Joined: 31 Jul 2009
Posts: 125
Location: Bombay, India

View user's profile Send private message Visit poster's website

PostPosted: Thu Feb 05, 2015 10:48 am     Reply with quote

Code:
void paralIn165(int8 buff)
{
   unsigned char tmp;
   unsigned char counter;
   #asm
      clrf rcvReg ; clear receive register
      movlw 0x08 ;w = 8
      movwf counter ;counter = w = 8
      bcf porta, 2 ;clear bit number 2
      bsf porta, 2 ;set bit number 2
    getBit:
      movlw 0b00000001 ;
      movwf tmp ;save in temp
      rrf tmp, f ;rotate bit into carry flag
      rlf rcvReg,f ;rotate the received bit into received buffer
      decfsz counter,f ;decrement counter skip next instruction if 0
      goto shift
      ;*****return****** problematic
      goto endroutine   ;; this is added
   shift: ;clock in the data
      bsf porta, 1
      bcf porta, 1
      goto getBit ;get another bit
endroutine:     ;; this is added
   #endasm
}

This should fix your problem. I leave it as an exercise for you to understand why.
kein



Joined: 23 Jul 2007
Posts: 103

View user's profile Send private message

PostPosted: Thu Feb 05, 2015 11:49 pm     Reply with quote

Thank you so much. I guess return causes stack issues - program returns to random location.
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Fri Feb 06, 2015 12:30 am     Reply with quote

When you "call" a subroutine, it pushes the return address on the stack - where is the "call" with your inline assy? Wink

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Fri Feb 06, 2015 1:50 am     Reply with quote

It is more complex than that....

If you have a 'function' like this, and use it from only one location, the compiler will not 'call' it. Instead it'll use a goto. Even from multiple locations, if the function is small, the compiler may 'inline' it (generating different versions each time it is used). So 'assuming' you can 'return' from a function, is always dangerous. It then gets worse, since on processors that have a variable stack (PIC24's etc.), the function may also have data on the stack, not just a return address. Jerson's solution lets the compiler do it's own housekeeping, and is a good way to go. There are ways to force the compiler to 'call' the function, but it's safer really to let it keep track of it's housekeeping itself.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Fri Feb 06, 2015 2:54 am     Reply with quote

I've not analysed the assembly code in any detail, but from a quick glance its seems to be essentially some sort of SPI-style bit bashing. it seems likely that the hardware of the PIC might well offer a better, faster and less prone to error solution. If not, then software emulation provided by the compiler might well be available.

So, and seeing that there are redundant tris settings (the compiler manages port direction automatically by default), I have to ask, why the assembler?
kein



Joined: 23 Jul 2007
Posts: 103

View user's profile Send private message

PostPosted: Fri Feb 06, 2015 6:38 am     Reply with quote

Thanks guys for your support. On the question of why assembly? My options are very limited as it's a requirement of my school assignment.
Having said that, I'm having problem with MPLABX simulator reading data from PIC16F877A EEPROM. I can write to EEPROM correctly as shown on attached image, but reading always returns value stored at the address 0x00. Why is that?

Code:

#include <16F877A.h>
#use delay(crystal=20MHZ)
#FUSES HS,NOWDT,NOLVP,NODEBUG,NOPUT,NOBROWNOUT,NOCPD,NOPROTECT                 //No Watch Dog Timer

#define Porta      5           //clock      PIN_A1
#define LdPin      2
#define ClkPin     1
#define CLOCK      3
#define CLEAR      5
#define SER_INP    5
#define BIT7       7
#define buffSize   11
#define STATUS     3        //Status register
#define RP0        5
#define RP1        6
#define INTCON     0x18B        //interrupt control register
#define GIE        7        //Global interrupt enable bit
#define EEDATA     0x10C
#define EEADR      0x10D
#define EECON1     0x18C
#define EECON2     0x18D
#define EEPGD      7
#define WREN       2
#define WR         1
#define RD         0
unsigned char rcvReg;
unsigned char arr[buffSize] = {0x37, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x07,0x7E,0x6F};
void main()
{
   unsigned char buff[buffSize];
   set_tris_a(0b00000001);       //porta are all outputs; pin 1 is input
   set_tris_b(0b00000000);       //all buits of port is set for output
   unsigned char i;
   for (i = 0; i < buffSize; i++)
   {
      writeToEEPROM(arr[i], i);
      buff[i] = 0x00;
      delay_ms(10);
   }
   for (i = 0x00; i < buffSize; i++)
   {
        buff[i]= ReadFromEEPROM(i);
   }
   delay_ms(50);
   while(TRUE)
   {
      //TODO: User Code         
   }

}
//this function read from EEPROM memory and return value stored at that address
unsigned char ReadFromEEPROM(int8 address)
{
   unsigned char temp;
   #asm
       clrf      temp           ;clear temp
       bsf      STATUS, RP1     ;switch to Bank2
       bcf      STATUS, RP0   
       movf   address, w      ;w = address
       movwf  EEADR           ;EADR = address
       bsf       STATUS, RP0     ;switch to Bank3
       bcf       EECON1, EEPGD   ;point to Data memory       
       bsf       EECON1, RD      ;Initiate read from EEPROM 
       nop
       nop
       bcf    STATUS, RP0     ;switch to Bank2       
       movf   EEDATA, w       ;copy data to working register, w
       movwf  temp            ;move to temp                 ;
   #endasm
   return temp;
}

http://postimg.org/image/nk3yvkts3/

kein



Joined: 23 Jul 2007
Posts: 103

View user's profile Send private message

PostPosted: Fri Feb 06, 2015 7:24 pm     Reply with quote

Guys, I solved it. For those who may be interested, here is the solution.

Code:
unsigned char ReadFromEEPROM(int8 address)
{
   unsigned char temp;
   #asm
       movf   address, w   ;w = address
       bsf      STATUS, RP1     ;switch to Bank2
       bcf      STATUS, RP0   
       ;******move this line up ---> "movf   address, w      ;w = address"
       movwf  EEADR           ;EADR = address
       bsf       STATUS, RP0     ;switch to Bank3
       bcf       EECON1, EEPGD   ;point to Data memory       
       bsf       EECON1, RD      ;Initiate read from EEPROM
       nop
       nop
       bcf    STATUS, RP0     ;switch to Bank2       
       movf   EEDATA, w       ;copy data to working register, w
       movwf  temp            ;move to temp                 ;
   #endasm
   return temp;
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Sat Feb 07, 2015 1:58 am     Reply with quote

and the reason is that you should have the assembler section marked #ASM ASIS.

As written the compiler will attempt to bank switch for you. So you don't actually need the bank switch instructions. However then because you have changed banks, and it doesn't 'know' the bank has been changed, the wrong bank gets selected. The ASIS statement tells the compiler _you_ are going to control the banks, and to leave them unchanged.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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