Global Struct Arrays and Interrupts

I have an array of structs, seen below, that will be accessed by interrupts at some points; namely, the “ticks” variable of the structure will be changed by encoder-caused interrupts. “goal_velocity” is NOT read or modified by the interrupt routine, ever. My question, then, is whether I need to disable interrupts when I want to write to goal_velocity? Can I just declare the array as volatile, as shown below, or does that only act on the pointer? Could I throw in an extra “volatile” or two in the array definition to make goal_velocity safe to fiddle with without disabling interrupts? Or is it imperative that I disable interrupts before reading/writing goal_velocity?

typedef struct {
        unsigned char * output;          // motor output signal
        int goal_velocity;       // goal (ticks per 26.2msec)

        int ticks;               // ticks since last read
    
        int error_current;       // current error
        int error_last;          // error from last measure
        int error_acc;           // accumulated error for integral portion
        } drivemotor;

volatile drivemotor motors[NUM_MOTORS] = {
  {&drive1, 0, 0, 0, 0, 0},
  {&drive2, 0, 0, 0, 0, 0},
  {&drive3, 0, 0, 0, 0, 0},
  {&drive4, 0, 0, 0, 0, 0}
};

As if that weren’t enough, assuming I can set goal_velocity without disabling interrupts first, I’d like to make them accessible by macro, as seen here:

#define speed1 motors[0].goal_velocity
#define speed2 motors[1].goal_velocity
etc...

I can’t figure out how to declare the array so that it can be initialized easily per the definition above AND be accessible across multiple files so the macros WORK. Where do I declare it, and how?

Until some of you geniuses weigh in, I’ll assume that interrupts do NOT need to be disabled, and I’ll define an accessor function for the array.

Thanks for your time, folks. I’d really like a reply ASAP, as we want to have a testing version of the code ready tonight.

That’s 5 questions.

In order: Yes. The former. Not necessary. No.

Volatile only means that the value cannot be “cached” by the processor. The compiler will assume that the value will change every time you use it.

Easy. You make a header that contains the macros. In the same header, add the following code:

extern volatile drivemotor motors[NUM_MOTORS];

Then include that header where ever you reference it.

It’s definitely safer to turn off interrupts when reading or writing from goal_velocity. The reason to turn off interrupts is that it’s possible that while accessing the data, an interrupt may trigger and also access the data. It’s then possible for incorrect data to be generated.

However, you really only need to disable interrupts if both regular code and an interrupt handler are writing to the memory location. In most cases, if your interrupt is writing the data and the regular code is reading it, you shouldn’t need to disable interrupts.

As for setting it volatile, volatile is used when a variable may change in another thread of execution (not aplicable here) or in an interrupt handler. The reason for this is that the compiler could optimize out code to check for a value if the compiler thinks the variable couldn’t be changed within that code path; but the variable could change the interrupt. I doubt this is particularly relevant here as you probably aren’t sitting in a loop waiting for something to happen in your code. I’m also doubting the optimizing ability of this compiler (although I could be wrong). Either way, you can always be safe by declaring it that way.

Matt

First of all, thanks for taking the time to sort out my twisted English syntax.

Um…you contradicted yourself.
Question 1: My question, then, is whether I need to disable interrupts when I want to write to goal_velocity?
Your Answer: “Yes”
Question 4 (or 5?): Or is it imperative that I disable interrupts before reading/writing goal_velocity?
Your Answer: “No.”

Volatile only means that the value cannot be “cached” by the processor. The compiler will assume that the value will change every time you use it.

So I assume that this applies to the components of the array pointed to by “motors” and not merely the value of the pointer variable “motors”?

Easy. You make a header that contains the macros. In the same header, add the following code:
-blah-

I moved the following to the header file (which is #included in the C file that the code is in…)

extern volatile drivemotor motors[NUM_MOTORS] = {
  {&drive1, 0, 0, 0, 0, 0},
  {&drive2, 0, 0, 0, 0, 0},
  {&drive3, 0, 0, 0, 0, 0},
  {&drive4, 0, 0, 0, 0, 0}
};

and got this:

C:\mcc18\pidexp\drivereg.c:140:Fatal [151] -internal- populateExternalReferences() - symbol 'motors' is not an external reference.

The line it refers to is:

void set_motor(int motor, int goal) {
**      motors[motor].goal_velocity = goal; // this line**
}

Theoretically this function shouldn’t exist, but when it is commented out, I get the same thing on

Motor_Ints_Enable();

(huh?)
and, when I comment that out, I get it here:

motor_gains[a].kd * (motors[a].error_current - motors[a].error_last));

and so I have stopped commenting things out like that.
Help?

To clarify the functionality of the original motors struct and array: Only the element “ticks” of the struct is touched at all by the interrupt routine (the interrupt uses “motors[0].ticks++;” or similar). No other variable in the struct is explicitly accessed. As stated, the question was whether I need to shut off interrupts if I want to assign goal_velocity a value.

Thanks again for the help. Maybe if I’m lucky this will work someday…

I hate to be rude about this, but bump

The tick variable is an integer, with multiple bytes. It’s conceivable that an interrupt could occur after one byte was read but before the other one, so you’d get a corrupted value. Any time you want to use a variable like that, it’s a good idea to disable interrupts while you access it.