This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LAUNCHXL-F28027: Circular list address breaks after an iteration

Part Number: LAUNCHXL-F28027

Hello,

I have a struct defined in a header file as follows:

typedef struct CommutationStep
{
  uint16_t index;
  uint16_t hall_val;
  struct CommutationStep *next_step;
  struct CommutationStep *prev_step;
} CommutationStep;


In the file containing the main(), I have an other struct:

typedef struct MotorInfo
{
  CommutationStep *comm_table;
  uint16_t hall_raw;
uint16_t prev_hall;
bool debounced; // other unused fields } MotorInfo;

In my main I initialize a MotorInfo struct called motor succesfully. *comm_table also points correctly to the 1st element of a 6 element circular array. (debugger verified, the circular list is fine up to this point)

Next, there is the infinite loop of my main:

  while(1)
  {
    if (!motor.debounced)
    {
      set_commutation_step(motor.hall_raw);
    }

    motor.hall_raw = get_hall_val(); 
    debounce_hall(&motor);
  }

and the debounce_hall function:

void debounce_hall(MotorInfo *motor)
{
  // Check if debounce is disabled
  if (DEBOUNCE_LEVEL < 1 || DEBOUNCE_LEVEL > 5) // (bug here)
  {
    motor->debounced = false;
    return;
  }

  if (DEBOUNCE_LEVEL == 1)
  {
    if (motor->hall_raw != motor->prev_hall)
    {
      // Point the comm_table to the step matching the raw hall val
      while(motor->comm_table->next_step->hall_val != motor->hall_raw)
      {
        motor->comm_table = motor->comm_table->next_step;
      }
      motor->comm_table = motor->comm_table->next_step;
      motor->prev_hall = motor->hall_raw;
      motor->debounced = false;
    }
    else
    {
      motor->debounced = true;
    }
    return;
  }
  else
 {
   // other code, not of interest
 }
}

Now to my problem: comm_table points to one of the six addresses 0x00000410-420-430-450-460. MotorInfo motor address is 0x00000404. I am debugging manually step by step, setting the hall_raw to the next step each time. By the time comm_table points to the sixth step, the address is correctly 0x00000460, the next_step is 410, and the previous 450. Checking the next_step at the debugger, it still correctly points to the next and prev addresses. Now, I am at the start of the 2nd revolution, and I set the hall_raw correctly to match the 1st step. debounce_hall(&motor) is called, and still every single address points to the expected step. At the 1st line of the function (comment // bug here), suddenly the struct at address 0x00000410 (1st step) gets a field modified: next_step now instead of pointing to 0x00000420 is pointing to 0x00000404. (motor struct address). 

What may be the cause of it?
Thank you in advance!

  • Hi Chris,

    So are you saying that if you put a breakpoint at the call to debounce_hall(), everything looks fine, but as soon as you step into debounce_hall() (on the second revolution) you see the change happen?

    I think our default cmd files put the stack at 0x400. Did you move it?

    Whitney
  • I am using the default cmd files (ram + nonBIOS headers) unchanged.

    The address actually changes when evaluating this line:

    if (DEBOUNCE_LEVEL < 1 || DEBOUNCE_LEVEL > 5)

    update: I 've made an edit to assign the motor.hall_raw value myself to simulate working conditions, and now the motor.comm_table address breaks when debounce_hall is called

  • Did you use a #pragma to place your structures at a specific location or some other method? It appears to me that if your stack is at 0x400 and your structures are at 0x404-0x460 they're going to end up overwriting each other...?

    Whitney
  • No I don't write them at a specific location, do I have to?

  • No, you don't have to. I was just wondering how they ended up in a location that--as far as I can tell--should have been reserved for the stack.

    How are you declaring the various structures? How are you initializing the pointers in them? If you don't mind sharing a bit more of the related code, that might help me figure out what's going wrong.

    Thanks,
    Whitney
  • In the main file:

    int main(void)
    {
      MotorInfo motor = { NULL,  // comm_table
                          0,     // hall_raw
                          0,     // prev_hall
                          false, // debounced
                        };
      motor.comm_table = comm_clist_init();
     ...
    }

    In an other file:

    CommutationStep *comm_clist_init(void)
    {
      // TODO:  malloc(*cs) doesnt work, check why
      CommutationStep cs = { 0,                       // index
                             HALL_VALS[0],            // hall_val
                             NULL,                    // *next_step
                             NULL                     // *prev_step
                           };
      CommutationStep *csp = &cs;
      cs.next_step = create_comm_step(1, csp, csp);
      return csp;
    }
    
    CommutationStep *create_comm_step(uint16_t step, CommutationStep *head,
                                      CommutationStep *prev)
    {
      CommutationStep cs = { step,            // index
                             HALL_VALS[step], // hall_val
                             NULL,            // *next_step
                             prev             // *prev_step
                           };
      CommutationStep *csp = &cs;
    
      if (step == (CLIST_LEN - 1)) // if last hall step, the next step is the head
      {
        cs.next_step = head;
        head->prev_step = csp;
      }
      else
      {
        cs.next_step = create_comm_step(++step, head, csp);
      }
    
      return csp;
    }

    I tried to initialize like this:

    CommutationStep *csp;
    if ((csp = malloc(sizeof(*csp)) != NULL)
    {
      // init logic here
    }
    

    but it failed with an error about not enough memory.

    Let me know if you need anything else!

  • Okay, I think that explains the weird behavior. In comm_clist_init() you're creating a local variable cs (which is stored on the stack), initializing it, and returning a pointer to it. However, when the function returns, the memory where that local variable is stored is free to be overwritten when it gets used for some other function's stack.

    You need to make sure that you've created the CommutationStep object in a location that will still be available when you've returned to main(). malloc() would work because that would put it on the heap. If the number of objects needed is known (will you only ever need six?), you could declare them in main() or globally depending on what scope you need.

    If you want to use malloc(), let me know what errors you were getting and we'll see if we can resolve them.

    Whitney
  • Thank you, this is eye-opening! I will probably declare them in main() since their number is known, and I don't expect to use much of the stack memory, but I'd like to have the malloc() problem sorted too.

    This is the error I get:

    http://processors.wiki.ti.com/index.php/Compiler/diagnostic_messages/10099 - program will not fit into available memory. run placement with alignment/blocking fails for section ".stack" size 0x300 page 1. Available memory ranges: 28027_RAM_lnk.cmd /orca-ecu line 149 C/C++ Problem

  • To fix that issue you'll either need to make some adjustments to the size of the stack and heap (Project > Properties > C2000 Linker > Basic Options) or change the .cmd file to allocate more space to these sections. Or possibly both. By default the linker uses a heap size of 0x400. That's the entirety of RAMM1 which is supposed to be shared with several other sections according to the default .cmd file--hence the errors.

    We have a wiki page on the subject of linking if you do want to try editing the .cmd: processors.wiki.ti.com/.../C28x_Compiler_-_Understanding_Linking

    Whitney

  • The wiki page was very helpful, thanks!