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

trying to force scratch variables to specific locations

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







trying to force scratch variables to specific locations
PostPosted: Tue Aug 22, 2006 1:47 pm     Reply with quote

Hello,

I am trying to force the scratch variables generated by the compiler to be in specificed locations. By default, it puts the scratch variables randomly.

I have tried "#locate @SCRATCH=0x44" (for example) but the compiler barfs on the "@" sign.

Thanks!

Bill
Ttelmah
Guest







PostPosted: Tue Aug 22, 2006 2:51 pm     Reply with quote

There are two distinctly different types of scratch variable used by CCS. The first are the true 'system' scratch variables. These are located at the bottom of memory, and are global/static in nature. The location for these, can be defined from the device editor, under the 'memory' tab, and they will be located at the defined point, and grow upwards, normally occupying just five locations.
The second type, are _dynamic_ scratch variables, and these are allocated the same way as local variables, using the memory 'heap'. Their location, will depend on the memory available to the subroutine calling the routine using them. Trying to locate these to a fixed location, will result in a massive waste of memory, since the same memory can be re-used, when the particular routine is not being called. So:
Code:

077     EEPROM_PUT.addr
077     EEPROM_GET.@SCRATCH
077     @PRINTF_LU_334.@SCRATCH
077     @PRINTF_L32D_334FPFPF.@SCRATCH
077     @FLT.@SCRATCH

This program has the same location, being used for five scratch variables, and a variable inside a subroutine...

Best Wishes
Guest








PostPosted: Wed Aug 23, 2006 12:05 am     Reply with quote

Thanks, Ttelmah,

Unfortunately, I definitely have the need to locate the local scratch registers as fixed, even though there will be a waste of memory.

Bill
ckielstra



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

View user's profile Send private message

PostPosted: Wed Aug 23, 2006 1:11 am     Reply with quote

I can't think of any reason why you would want to locate the local scratch registers to a fixed address. Just imagine you were not using a PIC processor but a processor with a normal stack pointer, than nobody would even consider to locate a variable on the stack to a fixed location because it would be plain impossible. Now you are using a PIC processor where things are organized a bit different, but still the same principles apply and I think it is a very strange idea.

Can you explain why you want to locate a local variable to a fixed memory address? Most likely we than can suggest a more elegant solution to your problem.
Guest








PostPosted: Fri Aug 25, 2006 1:24 pm     Reply with quote

Hi Ckielstra,

We have a complex bootloader, and the code in the bootloader uses scratch variables. The problem is that when a new "application" is loaded, the scratch variables used by the application can collide those previously used by the bootloader, unless we can force the bootloader to always use the same locations.

Bill
Ttelmah
Guest







PostPosted: Fri Aug 25, 2006 3:07 pm     Reply with quote

Er. That shouldn't matter a jot.
When the bootloader is working it uses the memory. Once the bootloader has completed, and the code is running, it uses the same memory. This si normal, and acceptable...

Best Wishes
ckielstra



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

View user's profile Send private message

PostPosted: Fri Aug 25, 2006 4:40 pm     Reply with quote

I agree with Ttelmah, the use of the same memory for scratch variables by the bootloader and your main application shouldn't matter. Remember why these variables are called scratch variables... when your function (or bootloader) has finished this memory is free for other uses.
Santiago Moronho Arenas



Joined: 18 Oct 2006
Posts: 4
Location: Galicia

View user's profile Send private message

locating dynamic varaibles
PostPosted: Tue Dec 12, 2006 2:06 pm     Reply with quote

Hey guys/[spam]

I don't now if your are still there with this topic, but I have the same need for locating the _dynamic_ scratch variables to a certain position (bank 0).

Despite of the waste of memory, could you please tell me how can this location be done?

Best regards
_________________
Santi - Itelsis
ckielstra



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

View user's profile Send private message

Re: locating dynamic varaibles
PostPosted: Tue Dec 12, 2006 3:37 pm     Reply with quote

Santiago,

I still can't think of an application requiring the dynamic variables to be located in a fixed memory location. Tell us more about your problem and I'm sure we can come up with a more elegant solution.
Santiago Moronho Arenas



Joined: 18 Oct 2006
Posts: 4
Location: Galicia

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 9:14 am     Reply with quote

Ok Ckielstra, I will be very glad to tell you, and take your suggestions in account.

It's a 16LC717 runnng at the 4MHz internal clock, and acting as a slave i2c device at 100Kbit/s. There are two irq enabled: i2c and a task dispatcher timer.

The slave i2c isr has to leave the reception buffer ready in a maximum of 90 instruction cycles, and could happen to interrupt just after the timer interrpt has started. The interrupt manager takes about 40 cycles to get into the isr user's code, and the isr timer is very short: 1 instruction.

The i2c isr is:
Code:

#int_SSP
void IsrSlaveI2cA() {

//int istate, iincoming;           //These local variables have been declared
                                          //as globals to stick them to bank 0.

  istate = i2c_isr_state(A);     //Reports about recent byte interrupting.
   if (istate != 0x00) {                 //DISCARD ADDRESS   
      if (istate < 0x80) {               //I2C SLAVE RX (MASTER WR)
        iincoming = i2c_read(A);    //Read first, critical timing.
         if (istate == 0x01) {                 
            RegIdx = iincoming;      //1st data byte: the index.
            FirstIdx = iincoming;     //Save. Decides actions PicDDS&E2P
            FlagWasI2cMasterWr = 1; //Signal R/W to PicDDS & E2P tasks
         }
         else
            Reg.Buf[RegIdx++]=iincoming;  //2nd save & prep next.             
      }
      else {                                   //I2C SLAVE TX (MASTER RD)
        i2c_write(A, Reg.Buf[RegIdx++]);
           FlagWasI2cMasterWr = 0;  //Signal R/W PicDDS & E2P tasks     
      }
   }
}

Thiose dynamic scratch variables make the code longer because os bank swithcing. The system is now working, but as far as I have calculated it very close to overflow, so I would loke to have a little bit relaxed.

Best regards!
_________________
Santi - Itelsis
ckielstra



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

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 11:48 am     Reply with quote

Tweaking your code to get the last bit performance out of it could indeed be a reason for desperate measures. Making the local variables as you did is one way to get more control over memory allocation.

Did you have a look at the symbol table, the *.sym file, for your program? You will see that the compiler tries to locate all dynamic variables at the start of memory, than all other variables are mostly added in sequence thay appear in your program. For minimizing bank switching it is good practice to put your large buffer variables at the end of the program. Some fiddling and shuffling with where you declare the variables in your program can save a lot of bank switches, in my program this gave me about 10% code size reduction!

In your application saving a few instructions by getting rid of the bank switching is nice, but will it do the job? A much larger improvement can be gained from getting rid of the interrupt routines. Yes, I know, this sounds strange but let me explain. The CCS compiler generates standard interrupt handler code which saves and restores all the registers you might possibly change in an interrupt routine, for a PIC16C717 and compiler v3.249 this is about 60 instructions overhead. Now for very tight timing applications you might be better of by polling the interrupt flags from the main loop, this will reduce the overhead with almost 60 instructions. Just make sure the loop is fast enough and doesn't get stalled by a function like printf.

Code:
#include <16C717.h>
#FUSES HS, NOWDT
#device *=16
#use delay(clock=4000000)

#byte INTCON= 0x000B
#byte PIR1  = 0x000C
#bit T0IF   = INTCON.2
#bit SSPIF  = PIR1.3

void Handle_Timer0_Interrupt()
{
  // Do here your timer stuff

  clear_interrupt(INT_TIMER0);
}

void Handle_I2C_Interrupt()
{
  // Do here your I2C stuff

  clear_interrupt(INT_SSP);
}

void main()
{
  enable_interrupts(INT_TIMER0);
  enable_interrupts(INT_SSP);
  clear_interrupt(INT_TIMER0);
  clear_interrupt(INT_SSP);
  // enable_interrupts(GLOBAL);    Do not enable this line! We call the interrupt service routines from main().
  while(1)
  {
    if (T0IF)
      Handle_Timer0_Interrupt();
    if (SSPIF)
      Handle_I2C_Interrupt();
  }
}
Santiago Moronho Arenas



Joined: 18 Oct 2006
Posts: 4
Location: Galicia

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 2:58 pm     Reply with quote

Thank's for the suggestion, but I'm afraid it's not feasible because there are a lot more things to be done in the main loop of the application (including a 2nd master i2c bus, adc readings, etc)

As far as I've tested now the system is working properly, It's only that I estimate margins are quite tight, and the immediate consequence of an overflow is the MSSP getting stuck until someone clears the SSPOV bit.

So, on one side I'm trying to loosen the tight margins with a faster isr and on the other side I'll put in a monitoring task to recover any eventual overflow.

I've just received a VERY INTERESTING answer from the CCS support:

Quote:
Inside a function you can do:
#locate AUTO=address
And all the local automatically located variables will start at the specified address.


But I was told to update my PCM compiler version from 4.011 to 4.018. If it works, it's quite nice for this kind of things. In fact I did't even realize that the locate directive can allso be invoked for local variables inside functions, I thought it was only for globals.

So, thank's a lot

Santi
_________________
Santi - Itelsis
ckielstra



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

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 7:47 pm     Reply with quote

Just two more tips
Make sure the most critical interrupt is serviced first, using the #priority directive.

Consider writing your own interrupt dispatcher code, check the manual for the paragraph on #int_global. Just copy the dispatcher as generated by the CCS compiler and then strip the saving of all registers that are untouched by your code. Not easy to do as this requires manual inspection of your interrupt handler code but for each register save/restore operation you can strip you will save 4 instructions.
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