This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Pointer/Function help

So, I am trying to put together two (rather involved) functions that calculate the DAC. My processing routine for CalcDAC1 and CalcDAC2 are more or less the same, but with different variables. Currently, I'm using global variables that are directly called from the routine. I would like to use the same functionality but send it the variables I want the program to use to process so instead of:

global variables:
unsigned int var1a;
unsigned int var2a;
unsigned int var3a;
unsigned int var1b;
unsigned int var2b;
unsigned int var3b;

void main(void)
{

     while(1)
     {
          CalcDAC1();
          CalcDAC2();
     }
}

void CalcDAC1(void)
{

//Do stuff with var1a
//Do stuff with var2a
//Do stuff with var3a

}

Void CalcDAC2(void)
{

//Do stuff with var1b
//Do stuff with var2b
//Do stuff with var3b

}

I instead would like to do

void main(void)
{

     while(1)
     {
          CalcDAC(var1a, var2a, var3a);
          CalcDAC(var1b, var2b, var3b);
     }
}

void CalcDAC(unsigned char var1, unsigned char var2, unsigned char var3)
{

     //Do stuff with var1
     //Do stuff with var2
     //Do stuff with var3

}

Unfortunately, my particular function has about 7-10 variables (complicated equation with lots of variables) so it requires me to create a LOT of local variables for each iteration, which I don't have the local space for (if that's the right term). Instead, I would like to send it pointers to local variables (if possible).

I ASSUME it would look something like this:

void main(void)
{

     while(1)
     {
          CalcDAC(*var1a, *var2a, *var3a);
          CalcDAC(*var1b, *var2b, *var3b);
     }
}

void CalcDAC(unsigned char *var1, unsigned char *var2, unsigned char *var3)
{

     //Do stuff with var1
     //Do stuff with var2
     //Do stuff with var3

}

Is this correct or is this even possible in C? Is this something you can only do in C++? Any help with implementation you can give me would be greatly appreciated. Thanks!

Parents
  • Well, I'm about maxxed out on global variables as well. I've had to start using the idata register because the first 128k is more or less used up. This is how I was creating the struct:

    struct
    {
            signed short var1;
            signed short var2;
            signed short var3;
    
    } DACStruct;
    

    I am now getting an address overflow error. I tried to change these to idata like this:

    struct
    {
            signed short idata var1;
            signed short idata var2;
            signed short idata var3;
    
    } DACStruct;
    

    but got the following error(s):

    SRC\VARS.C(40): error C258: 'var1': mspace illegal in struct/union
    SRC\VARS.C(40): error C258: 'var2': mspace illegal in struct/union
    SRC\VARS.C(40): error C258: 'var3': mspace illegal in struct/union

    Is there a way to place the entire struct in the idata rather than trying to break up individual parts of the struct? Or will I need to free up some space by moving other variables to idata to make room for this struct?

    Also, when I want to send a pointer to the struct, I assume I'll want to do the following:

    void main(void)
    {
         DACStruct->var1 = 1;
         DACStruct->var2 = 2;
         DACStruct->var3 = 3;
    
         CalcDAC(*DACStruct);
    }
    
    void CalcDAC(struct *DACStruct)
    {
    // do stuff with struct here
    }
    

    I think I'm implementing the second part wrong but I'm not sure. At this point, I'm trying to get the basics down.

    Does it look like this is the best approach for what I'm trying to do?

Reply
  • Well, I'm about maxxed out on global variables as well. I've had to start using the idata register because the first 128k is more or less used up. This is how I was creating the struct:

    struct
    {
            signed short var1;
            signed short var2;
            signed short var3;
    
    } DACStruct;
    

    I am now getting an address overflow error. I tried to change these to idata like this:

    struct
    {
            signed short idata var1;
            signed short idata var2;
            signed short idata var3;
    
    } DACStruct;
    

    but got the following error(s):

    SRC\VARS.C(40): error C258: 'var1': mspace illegal in struct/union
    SRC\VARS.C(40): error C258: 'var2': mspace illegal in struct/union
    SRC\VARS.C(40): error C258: 'var3': mspace illegal in struct/union

    Is there a way to place the entire struct in the idata rather than trying to break up individual parts of the struct? Or will I need to free up some space by moving other variables to idata to make room for this struct?

    Also, when I want to send a pointer to the struct, I assume I'll want to do the following:

    void main(void)
    {
         DACStruct->var1 = 1;
         DACStruct->var2 = 2;
         DACStruct->var3 = 3;
    
         CalcDAC(*DACStruct);
    }
    
    void CalcDAC(struct *DACStruct)
    {
    // do stuff with struct here
    }
    

    I think I'm implementing the second part wrong but I'm not sure. At this point, I'm trying to get the basics down.

    Does it look like this is the best approach for what I'm trying to do?

Children
  • You can't use idata on individual members of a struct data type - it's the struct type or the struct variable that should be idata.

    Next thing is that DACStruct isn't a pointer. So no -> to access the member fields in main. It is only your function that receives a pointer to DACStruct that needs to perform pointer indirection.

  • So you're saying the declaration should look like this:

    idata struct
    {
            signed short idata var1;
            signed short idata var2;
            signed short idata var3;
    
    } DACStruct;
    
    void main(void)
    {
         DACStruct NewDACStruct;
    
         NewDACStruct->var1 = 1;
         NewDACStruct->var2 = 2;
         NewDACStruct->var3 = 3;
    
         CalcDAC(NewDACStruct);
    }
    
    void CalcDAC(DACStruct NewDACStruct)
    {
    
    // do stuff with struct here
    
    }
    

    Is that correct?

    It doesn't appear that creating a struct locally would save you a lot of local variables. Would it make more sense to create a global variable like this:

    idata struct
    {
            signed short idata var1;
            signed short idata var2;
            signed short idata var3;
    
    } DACStruct;
    
    DACStruct idata NewStruct;
    
    void main(void)
    {
    
         NewDACStruct->var1 = 1;
         NewDACStruct->var2 = 2;
         NewDACStruct->var3 = 3;
    
         CalcDAC(*NewDACStruct);
    }
    
    void CalcDAC(DACStruct idata *NewDACStruct) // not sure if the idata portion is necessary here
    {
    
    // do stuff with struct here
    
    }
    

  • Note that struct { ... } xx creates a variable xx - not a data type xx.

    You create a type with struct xx { ... } or with typedef struct { ... } xx;

    Next thing - no use to have local variable in main() since variable lives full program time and still have to b e made global.

    SO make a global variable ( not pointer) and access it in main.

  • I don't completely follow. Can you show me what you're referring to in reference to the example code I've given? It's pretty basic code and would help me understand what you mean a lot easier. This is mainly because I don't know what you're referring to when you mention

    { ... } xx

    or

    xx { ... }

    or

    typedef struct { ... } xx

    Thanks for your help!

  • Is this what you're referring to?

    idata struct
    {
            signed short idata var1;
            signed short idata var2;
            signed short idata var3;
    
    } DACStruct;
    
    void main(void)
    {
    
         DACStruct->var1 = 1;
         DACStruct->var2 = 2;
         DACStruct->var3 = 3;
    
         CalcDAC(DACStruct);
    }
    
    void CalcDAC(idata struct DACStruct) // not sure if the idata portion is necessary  here
    {
    
    // do stuff with struct here
    
    }
    

    Also, are the idata portions (highlighted in bold/red) necessary?

  • struct {
        int a;
        int b;
    } my_struct_variable;    // <= this is a variable.
    
    struct my_struct_type {  // <= this is a data type - not a variable.
        int a;
        int b;
    };
    
    struct my_struct_type a_variable;  // <= create a variable of this type.
    
    typedef struct {
        int a;
        int b;
    } my_struct_type2;  // <= also a data type.
    
    my_struct_type2 settings_1,settings_2;  // <= two variables of this custom type.
    
    int my_special_function(my_struct_type2* settings) {
        return settings->a + settings->b;   // now have a pointer to a struct, so -> for pointer indirection.
    }
    
    void main(void) {
        settings_1.a = 1;  // <= my_struct_variable is not a pointer, so no ->.
        settings_1.b = 1;
        my_special_function(&settings_1);
        settings_2.a = 2;
        settings_2.b = 3;
        my_special_function(&settings_2);
        for (;;) ;
    }
    

  • idata struct
    {
            signed short idata var1;  // <= what would idata mean here?
            signed short idata var2;  // <= you can't split the inside of a struct into
            signed short idata var3;  // <= multiple memory regions...
    
    } DACStruct;
    

    You just can not have idata inside a struct - if you could, then you would be able to specify different memory specifiers for different fields. But how would a linker be able to explode a struct to store the data all over the place?

    The only time you can play with memory modifiers inside a struct, is if that struct has pointer members. Because the pointer can point at data in another memory region.

  • So for my example, this is what it would look like:

    typedef struct // I'm creating a data type here
    {
            signed short var1;
            signed short var2;
            signed short var3;
    } DACStruct;
    
    DACStruct idata DACStructVar; // I'm creating a variable based on the DACStruct here.  This will create it in the idata register 
    
    void main(void)
    {
    
         DACStructVar.var1 = 1;
         DACStructVar.var2 = 2;
         DACStructVar.var3 = 3;
    
         CalcDAC(&DACStructVar); // Should I be using a pointer here or should I be directly calling DACStructVar here?
    }
    
    void CalcDAC(DACStruct idata* MyDACStruct) // Did I want a pointer here? 
    {
    
    // do stuff with struct here
    
    }
    

    Am I using the idata sections correctly? Did I want to use pointers with this or should I be directly calling the DACStructVar in the CalcDAC routine (DACStruct or &DACStruct)? Thanks for your help, I think I'm getting closer now!

  • Ok, that makes sense. So my last post is probably the correct way of doing it? Create the struct type with just signed shorts and then create a new variable of struct data type in the idata portion?

  • You are asking a lot of questions - aren't you spending time reading the compiler manual, or writing code and testing?

  • To answer your question, yes, I spend a lot of time writing code and testing it. The whole reason I originally came here is because I am maxed out on global variables in the data register and need to start using the idata register. Unfortunately, I don't know the correct way to setup things like structs in the idata register (which I think I understand a bit now).

    Most of my recent questions have been clarifying what you're suggesting for me. I don't fully understand some of what you're asking so I'm creating example code to demonstrate this (my code looks nothing like the examples I'm giving. My current code is about 6k).

    I have a number of different projects I am working on at the same time. At this point, I'm doing research on the best way to approach this portion of it. While I've been asking questions here, I've been working on other parts of my code. I didn't realize posting in these forums was going to be such a nuisance.

    My experience with forums has typically been as long as it's for learning and you're not expecting other people to write your code for you, people are generally pretty helpful. My questions have fallen into that category for the most part (with the only request for code pertaining to suggestions I didn't fully understand the implementation of).

    Is it a problem to ask a lot of questions in a forum that is, for the most part, pretty dead? Or is there a better place to ask these questions?

  • because I am maxed out on global variables in the data register and need to start using the idata register.
    they are not registers, they are memory areas

    Is it a problem to ask a lot of questions in a forum that is, for the most part, pretty dead? Or is there a better place to ask these questions?
    For a '51 question not related specifically to Keil a better place might be http://www.8052.com/forum/.

    back to your question:
    there are many address spaces in a '51
    CODE
    register banks
    BDATA
    DATA
    IDATA
    SFRs
    XDATA

    you need to fsmiliarize yourself with the processor, an the best place is "the bible" chapters 1, 2 and 3, you can find a link here www.8052.com/.../120112

    Erik

  • Heh, thanks for the reply. I wasn't sure of the word I needed (as stated in previous posts) but I had a feeling "register" was the incorrect word.

    Regarding the chip/code I'm using, just to specify based on what you share, I am using a M8051W chip, which has 256 bytes of on chip RAM so I have:

    8K code space (I am currently utilizing just under 7K of it)
    128 bytes of Data space (which is all used up)
    128 bytes of Idata space (of which I'm using approximately 62 bytes of it)
    No Xdata on my chip
    The ESFR and SFR registers are all assigned to various functions of the chip

    Right now, I seem to be juggling between data/idata space and code space so I'm trying to find the most efficient ways of doing so, hence why I come to this forum. I can mickey mouse my code and MAKE it work but I'd rather learn how to do things correctly from people who have coding experience, hence why I came here.

    Thanks for the links you gave me. I will check them out. Thanks for the help!

  • On a sidenote, is there any reason everything designed by Keil or anything related to the 8051 looks like it was designed in the 90's? Every tool or forum looks extremely dated. Is that because long time programmers don't like changes or are the developers unable/unwilling to update the look/feel of the program? For a $2k-3k piece of software, you'd think they'd want to make it look a bit more up to date.

  • Right now, I seem to be juggling between data/idata space and code space so I'm trying to find the most efficient ways of doing so, hence why I come to this forum. I can mickey mouse my code and MAKE it work but I'd rather learn how to do things correctly from people who have coding experience, hence why I came here.

    basically the right way is to base it on "access frequency" and size.
    the stack (which is indirectly addressed anyhow is automatically placed at the top of (I)DATA which is where it belongs

    frequently accessed "directly addressed" variables should be in DATA
    frequently accessed "indirectly addressed" variables (straucts, arrays) should be in DATA
    large stuff should be in XDATA

    take a peak on the generated assembler for this

    char xdata x;
    char idata i;
    char data  d;
    bit  bdata b;
    
    char justFun j;
    
    j = x;
    j = i;
    j = d;
    j = P0;
    

    Erik