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

Bootloader>main soft: interrupts stop working

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



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

Bootloader>main soft: interrupts stop working
PostPosted: Tue Jan 16, 2007 8:42 am     Reply with quote

Hi,

this topic is a continuation of the discussion in http://www.ccsinfo.com/forum/viewtopic.php?t=24301
Now this is my own topic on this issue.

I am implementing the CCS bootloader which is at the beginning of ROM space. I am able to download code and to reset and restart the bootloader. PIC16F877A and pcwh 3.226

bootloader.c:
Code:
#include <16F877A.h>
#fuses XT, PUT, NOWDT, NOPROTECT, NOLVP, NOCPD, NOWRT, NOBROWNOUT, NODEBUG

#define _bootloader
#include "bootloader.h"

#define LOADER_ADDR 0x0006

#org LOADER_ADDR, LOADER_END default
#use delay (clock=4000000)
#use rs232 (baud = 9600, parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, ERRORS)

#include "my_loader.c"

void application (void);

#int_global
void pass_interrupt (void)
{
   #asm
      goto LOADER_END+5
   #endasm
}

void main (void)
{
   long timeout = 0;
   int8 i, triggers_found = 0;

   delay_us (50);                // Transmit Buffer clearen
   putc ('L');

   for (i = 2; i > 0; i--)
   {
   // while ( !kbhit() && (++timeout < 50000) ) // 5 seconds
      while ( !kbhit() && (++timeout < 0xFFFF) ) // 0xFFFF i.s.o. 50000 saves 5 bytes
         delay_us (100);

      if ( kbhit() )
      {
         if ( getc() == 170 )
            triggers_found++;
         else
            break;       // invalid char received, stop waiting.
      }
      else
         break;
   }

   if ( triggers_found == 2 )
   {
     real_load_program ();
   }
   application ();             // Jump to real application
}

#org LOADER_END+1,LOADER_END+100
void application(void)                      // Dummy functie, eigenlijk staat hier de échte main
{
   while (TRUE);
}


bootloader.h:
Code:
#define LOADER_END   0x1FF
#define LOADER_SIZE   0x17F
#ifndef _bootloader
#build ( reset = LOADER_END+1 , interrupt = LOADER_END+5 )
#org 0, LOADER_END {}
#endif


When I download my main program via the ICD (without bootloader) everything works OK. However when I download my program via the bootloader some strange things happen:

* at the beginning of the program interrupts are enabled/seem working. I can receive bytes of the serial port, but when I enter my while (1) loop; interrupts seem to get disabled at a certain moment. Also some variables get changed after a couple of times looping and I don't understand why.

Does anybody have got an idea what's going on here? My main program can be downloaded;( it's quite large ):

http://users.[spam].be/chs/Werk/mainsoft.zip

grt
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Tue Jan 16, 2007 9:07 am     Reply with quote

by Ttelmah:

Quote:
Again, the problem of your 'adding' this problem to an existing thread, rather than launching a new one. The original posts were about a 18 chip, not a 16 chip.
Now, seriously, your interrupt handlers are damnably long. On the 16 chip, the edge of the first bank, is 0x7FF in the program memory. My guess, would be that something, is going over this boundary, and causing a problem with the bootloader present. Look to see if you can simplify what you are doing in the handler (both in terms of code volume, and tme involved...).
I'd suggest that you just run one software timer routine in timer_1, that perfoms the 32bit arithmetic, with the required 'wraps', to give seconds, and then do the tests inside this, for the individual counters being enabled, and handle their timers. Though 32 bit arithmetic is not 'too bad' inside an interrupt, it still takes about 20 instruction times, and adding up if all five routines trigger at once, you have something over 300 instructions in this interrupt alone, making it both large, and relatively slow. My suspicion is that with the bootloader present, one or more of the routines, is ending up having to perform a bank switch, and is becoming both larger, and slower as a result, leading to the problem. This is why it does not immediately occur, but takes a few characters.
Now, the number of characters you mention as the point where the problem shows, is suspiciously close to the size of your serial buffer. I'd again suggest altering the code for this. Either expanding the buffer to 16 characters, or if it will still be large enough, reducing it to 8. Then in the serial routine, instead of:

Read_Pointer = ( Read_Pointer + 1 ) % BUFFER_SIZE;

Use:

Read_pointer = (Read_pointer+1) & (BUFFER_SIZE-1);

The former, takes around 100 instruction cycles, and is relatively large. The latter takes only a handful of instructions, but will only work for 'binary' buffer sizes (8, 16 etc., characters).

Best Wishes


1. I've tried it with reducing the timer_1 and timer_2 interrupt handlers with only 1 software timer; so having small ISR code. That gives the same problems.

2. However your comment sets me thinking that I have functions that are quite large. Perhaps that is a problem?

3.
Quote:

Read_Pointer = ( Read_Pointer + 1 ) % BUFFER_SIZE;

Use:

Read_pointer = (Read_pointer+1) & (BUFFER_SIZE-1);

gives 0 change in ROM code.

4. BUFFER_SIZE is 64
Ttelmah
Guest







PostPosted: Tue Jan 16, 2007 9:14 am     Reply with quote

Don't look at the ROM size, but look at the running length of the routine. Use the MPLAB simulator, and set the code up to jump to the interrupt handler. Record the stopwatch value at the entry to the routine, then at the exit. You should find something over 100 instruction times difference. If you do, it makes another important point. It implies that the integer division routine (used by the % function), is already being called in the main code. As such, interrupts will have automatically been disabled in the main code, whenever this function was being called....
The reason the ROM size didn't change, was that the routine was already 'present', so the interrupt handler just calls this routine, doesn't have to 'add' it.

Best Wishes
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Tue Jan 16, 2007 9:34 am     Reply with quote

Code:
....................    //Read_Pointer = ( Read_Pointer + 1 ) % BUFFER_SIZE;       // Verhoog read-pointer
....................    Read_pointer = (Read_pointer+1) & (BUFFER_SIZE-1);
0388:  MOVLW  01
0389:  BCF    03.6
038A:  ADDWF  4F,W
038B:  ANDLW  3F
038C:  MOVWF  4F


vs

Code:
....................    Read_Pointer = ( Read_Pointer + 1 ) % BUFFER_SIZE;       // Verhoog read-pointer
0388:  MOVLW  01
0389:  BCF    03.6
038A:  ADDWF  4F,W
038B:  ANDLW  3F
038C:  MOVWF  4F
....................    //Read_pointer = (Read_pointer+1) & (BUFFER_SIZE-1);


I'm sorry I don't understand why this gives exactly the same code then. Being faster does mean using lesser instructions, no?

Despite, this does not help the interrupt bug..
Ttelmah
Guest







PostPosted: Tue Jan 16, 2007 10:53 am     Reply with quote

What has happened here, is that the optimiser has been very smart, and because you are using a binary size, and it is a constant, has converted to the '&' form. This is very good work by the optimiser (hurrah). Smile

Best Wishes
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Wed Jan 17, 2007 2:02 am     Reply with quote

Is it possible to move the CCS bootloader in order to reside at the end of the ROM? What should be changed?
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Wed Jan 17, 2007 7:45 am     Reply with quote

Is it a problem to call a function inside a function that is also inside a function?
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

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

PostPosted: Thu Jan 18, 2007 9:27 am     Reply with quote

It shouldn't be a problem. What you look at is the call stack depth. Look in the *.lst file and it show the worst case stack. compair that to the spec for the 16F877A
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Thu Jan 18, 2007 10:15 am     Reply with quote

Code:
CCS PCM C Compiler, Version 3.226, 28499               18-jan-07 17:13

               Filename: C:\DOCUME~1\CHRIST~1.SEY\MYDOCU~1\Hardware\PIC\NE1A15~1\NS.LST

               ROM used: 7223 words (88%)
                         Largest free fragment is 486
               RAM used: 220 (60%) at main() level
                         264 (72%) worst case
               Stack:    8 worst case (6 in main + 2 for interrupts)


What does a stack of '8' mean?
What is the stack actually?
What if the stack is too big?
Can their be problems bootloader related?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jan 18, 2007 7:55 pm     Reply with quote

For starters: Read the PIC manual, it has some good info on the stack.
Short: When you call a function there is a return statement at the end. How does the program know what address to return to? This is achieved by saving the address at time of calling the function. The address is saved into a special buffer memory, called the stack.
PIC processors have a limited size for the stack buffer, on PIC16 processors this is 8, larger on PIC18 processors.
Result of this is that you can only have a total of 8 'nested' functions (a function calling a function, calling a function, calling ... total 8x).

If the stack gets too large you are in trouble, it overflows into the first item (like a circular buffer). You than have a corrupted stack and your program will jump to unexpected memory locations. PIC18 has optional hardware for detecting an overflow, PIC16 will do nothing.


I ran your program in the simulator and there were strange program jumps after the Timer2 interrupts was activated. This was related to a corruption of the PCLATH register, a known bug and fixed somewhere between your v3.226 and v3.235 by introducing the jump_to_isr() function. For an explanation read http://www.ccsinfo.com/forum/viewtopic.php?p=75095

Change the interrupt function in your bootloader.c to
Code:
#int_global
void pass_interrupt (void)
{
#if 0 // select this for compiler versions v3.235+
   jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
#else  // older compiler versions
   #asm
      MOVWF  0x7F
      SWAPF  0x03,W
      CLRF   0x03
      MOVWF  0x21
      MOVF   0x0A,W         // Save PCLATH
      MOVWF  0x20
      CLRF   0x0A
      MOVLW  0x02
      MOVWF  0x0A
      goto LOADER_END+5
   #endasm
#endif
}

Because of the increased code size also change
Code:
#define LOADER_ADDR 0x00010
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Fri Jan 19, 2007 2:41 am     Reply with quote

Hi,

thanks for the effort.. however the problem remains. I' ve tried your solution and it has no effect.

edit: I found that the modification does something wrong. The main program acts strange and delay_ms () function does not delay the exact time ( much longer )..

Also strange is ( also on prev bootloader ) that right after the download the program jumps to my application, then _no_ interrupts are working ( meaning I cannot receive any data on the serial port == serial interrupts ). When I reset, I can receive data a couple of times ( to leave the booting_00 () function and to go into my main function ) After that interrupts stop working.
ferrumvir



Joined: 01 Feb 2006
Posts: 64
Location: England

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

PostPosted: Tue Jan 23, 2007 3:14 pm     Reply with quote

You might have seen that I've also been working on a bootloader.

Certain things I found may be your problem, I found the following did not work or caused problems.

1/

Code:

#org LOADER_ADDR, LOADER_END default
#use delay (clock=4000000)
#use rs232 (baud = 9600, parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, ERRORS)


I could not get the above to work, I had to keep the #use statments after the #device statment. I also moved them to the same location as you because otherwise certain "functions" inserted by the compiler were being located outside of boot load space, but the application then failed to run at all, so I was forced to move them back. I cured this my sequentially removing functions from the "main", once I'd found out which function it was I altered the logic so that I effectively moved the function into loader.c.

2/ There is also a "#org default" statment at the end of loader.c which does something, don't ask me what this does, but it must be important because this statment is also critical for the application to function afterward it's bee bootloaded. I removed it at one point because I thought it was being overridden by the next #org statement before being used, and things started to fail. I eventually checked the HEX files with and without this statement and as surprised by the difference.

3/ One test is to compile with a dummy application which just says "while(true);", there should only be 4 bytes of instructions for the application, no more. If there are then you need to look at the lst file and discover where they are being created.

4/ Another useful tip in finding the source of instructions is to remove the "#nolist" from the 16F877A.h file. This will provide you with additional information about instruction generation.

5/ Having had a look at your code, I also can't see a "#org" statement before the "main" routine. My best guess at your original question is that at some point your boot loader starts overwriting this function and that's why communications stop. This main routine must reside inside the boot loader.

6/ I found the most useful thing was writing a hex file interpretter, for the PC. Just going through the motion of parsing out the information and writing a humanly legible map of the PICs memory. Firstly this boosted my understanding of what was happening and secondly provided me a way of checking what was going on.

7/ PCM_Programmer also had a few tips see http://www.ccsinfo.com/forum/viewtopic.php?t=29573

Hope some of that helps.

Cheers Scott
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