BLDC Commutation Sanity Check

Go To Last Post
26 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I am creating a BLDC motor controller with an Arduino UNO, using the Arduino app for Mac. I have the motor spinning with good torque and speed range. What I would like is for someone with more experience to look over the commutation code to see if I can optimize it to work with fewer clock cycles. The speed filtering and PI controller runs in the main loop and I would like to free up some processor cycles for that, if possible.

Pins 8 to 13 are connected to MOSFET gate drivers. Pins 9, 10, and 11 control the high side with PWM, and pins 8, 12, and 13 control the low side with no PWM. The hall sensors are connected to pins 2, 3, and 4. The timer0 ISR calls the commutate function at 128microsecond intervals because I plan on doing full sine wave commutation in the future. I acquire the speed signal from the interval of only one hall sensor because the sensors' alignment seems to be inconsistent, which throws off the speed signal. Is there a better way to acquire speed?

Some questions that I have: Is my method of disconnecting the pins from the timers for full on and full off correct? My reason for doing so is because I think non-inverting PWM at the lowest setting will still produce 1/256 pulses, which would not work. I developed the code by digging through the Arduino analogWrite() function and copying the essential bits. Does it matter if I call PINB with some pins attached to the PWM clock? Are there any unnecessary steps in the code? Is there a speed penalty for putting the code into a separate function as opposed to the ISR routine itself?

Thanks

 

void CommutateSquare()
{
  static bool flipA;

  motorHTime ++;

  switch (PIND | B11100011)//mask all but the three hall sensor pins
  {
    case B11101111: //1: C Low, A HIGH
      if (!flipA) {
        motorHInterval = motorHTime;
        motorHTime = 0;
        flipA = 1;
      }
      if (Output == 255)  //no pwm for full on
      {

        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B100010;   //commutate for full on
      }
      else if (Output == 0) // no PWM for full off
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B100000;   //commutate for full off
      }
      else //PWM for in-between values
      {
        sbi(TCCR1A, COM1A1);  //turn ON pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B100000;   //commutate for PWM
        OCR1A = Output; // set pwm duty on phase A
      }

      break;
    case B11100111: //2: B Low, A High

      if (Output == 255)  //no pwm for full on
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B010010;   //commutate for full on
      }
      else if (Output == 0) // no PWM for full off
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B010000;   //commutate for full off
      }
      else //PWM for in-between values
      {
        sbi(TCCR1A, COM1A1);  //turn ON pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B010000;   //Commutate PWM
        OCR1A = Output; // set pwm duty on phase A
      }

      break;
    case B11110111: //3: B Low, C High

      if (Output == 255)  //no pwm for full on
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B011000;   //commutate for full on
      }
      else if (Output == 0) // no PWM for full off
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B010000;   //commutate for full off
      }
      else //PWM for in-between values
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        sbi(TCCR2A, COM2A1);  //turn ON pin 11 PWM timer
        PORTB = B010000;   //Commutate PWM
        OCR2A = Output; // set pwm duty on Phase C
      }

      break;
    case B11110011: //4: A Low, C High
      if (flipA) {
        motorHInterval = motorHTime;
        motorHTime = 0;

        flipA = 0;
      }

      if (Output == 255)  //no pwm for full on
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B001001;   //commutate for full on
      }
      else if (Output == 0) // no PWM for full off
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B000001;   //commutate for full off
      }
      else //PWM for in-between values
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        sbi(TCCR2A, COM2A1);  //turn ON pin 11 PWM timer
        PORTB = B000001;   //Commutate PWM
        OCR2A = Output; // set pwm duty on Phase C
      }

      break;
    case B11111011:  //5: A Low, B High

      if (Output == 255)  //no pwm for full on
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B000101;   //commutate for full on
      }
      else if (Output == 0) // no PWM for full off
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B000001;   //commutate for full off
      }
      else //PWM for in-between values
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        sbi(TCCR1A, COM1B1);  //turn ON pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B000001;   //Commutate PWM
        OCR1B = Output; // set pwm duty on phase B
      }
      break;
    case B11101011: //6: C Low, B High

      if (Output == 255)  //no pwm for full on
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B100100;   //commutate for full on
      }
      else if (Output == 0) // no PWM for full off
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        cbi(TCCR1A, COM1B1);  //turn off pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B100000;   //commutate for full off
      }
      else //PWM for in-between values
      {
        cbi(TCCR1A, COM1A1);  //turn off pin 9 PWM timer
        sbi(TCCR1A, COM1B1);  //turn ON pin 10 PWM timer
        cbi(TCCR2A, COM2A1);  //turn off pin 11 PWM timer
        PORTB = B100000;   //Commutate PWM
        OCR1B = Output; // set pwm duty on phase B
      }
  }

  // minimum speed is 400*128 microseconds per half electrical rotation
  if ((motorHTime > 400) || (motorHInterval > 400)) motorHInterval = 400;
}

 

thadwald

Last Edited: Sun. Apr 16, 2017 - 06:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Anyone?

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, you ask some specific questions which are pretty hard to answer without knowing your application, which you know far more about than we do, and you've only given a little bit of the code to look at it. Possibly there is some repeated code which could be optimised, but for that sort of optimisation one needs to look more widely. I would maybe separate monitoring the Hall sensor and setting the PWM outputs.

 

Otherwise, the code looks ok. If there is no specific problem, then I see no reason to change it.

Bob.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thadwald wrote:
Is there a speed penalty for putting the code into a separate function as opposed to the ISR routine itself?

 

YES, calling a function within an ISR will have a speed penalty as more registers need to be saved upon entry/exit to/from the ISR.

 

Keep ISR's, short by doing only what is necessary in the ISR, otherwise, set flags for non critical things that can be handled in LOOP() or main().

 

Jim

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks
I'll move it into the ISR routine.

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thadwald wrote:
Is my method of disconnecting the pins from the timers for full on and full off correct? My reason for doing so is because I think non-inverting PWM at the lowest setting will still produce 1/256 pulses, which would not work.

You haven't shown us everything -- I cannot tell offhand what PWM mode is being used.  And there is at least a hint of this being an Arduino app.

 

To make it easier to examine:

-- Tell AVR model and clock speed.

-- Tell toolchain and version and optimization settings.  [I guess "Arduino" would fit in here]

-- Ideally, show the smallest complete test program that exhibits your symptoms.  Tell what you expect to ahppe, and tell what is happening.

 

(If you get through the above, you'd be able to answer the "speed penalty" by looking at the ISR(s).)

 

Anyway, if Fast PWM then indeed you cannot have full-on and full-off on an AVR8 with a single setup.  However, in most cases, 255/256 is close enough to full-on.  So you can use inverted PWM and get full-off.  You can see how it will greatly simplify the posted code:  After the inversion and perhaps some limit checking there would be no conditional logic or fussing with the COM bits.

 

thadwald wrote:
because I plan on doing full sine wave commutation in the future.

Doesn't Atmel have app note(s) on this?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you.

I am familiar with some of those. I have been unable to find the code they refer to, though. Could you direct me to that?

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thadwald wrote:
I have been unable to find the code they refer to, though. Could you direct me to that?

There is a disk symbol for each on the "app notes" pages.  [but I haven't explored the Microchip version of the Atmel Web site]

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When you "tweak" Arduino base code, note that in many [most? all?] incarnations the timers have a default setup.  So you will want to completely set up the timer(s) you will be using.  And in general, avoid the system timer used for millis() and the like.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. I found them. I expect them to answer all my questions.

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

http://www.microchip.com/wwwprod...

 

No disk symbol next to the PDF symbol:

However, right-click on the "AN_8012..." and Open link in new tab and you get:

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Heh. I discovered that when I tried to set up CTC on timer0, and micros() stopped working.

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Guess what timer the Arduino core uses for millis()?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Will the AVR examples compile with the Arduino compiler? if not, is there a free compiler available that they will work with?

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The arduino compiler is avrgcc but it brings in its core libraries which use timer0 for housekeeping and maybe timer1 for pwm. You can easily override this, but don't expect millis() or pwm to work!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

OK, so I *think* I have the AVR447 AN ported from IAR to avr-gcc except for one line. I'm hoping you can help me with this.

 

\brief Motor control flags placed in I/O space for fast access.

    This variable contains all the flags used for motor control.
    It is placed in GPIOR0 register, which allows usage of several
    fast bit manipulation/branch instructions.
*/

//original IAR definition
//__io volatile PMSMflags_t fastFlags                               @0x1e;

//mine--copied from elsewhere in this forum where someone tried to do the exact same thing
#define fastFlags (*(volatile PMSMflags_t*)_SFR_MEM_ADDR(GPIOR0))

PMSMFlags is defined in another library as:

 

/*! \brief Collection of all motor control flags.
 *
 *  This struct contains all motor control flags used in this implementation.
 */
typedef struct PMSMflags
{
  uint8_t motorStopped : 1;     //! Is motor stopped?
  uint8_t motorSynchronized: 1; //! Is motor synchronized? Does not have any meaning when motorStopped is TRUE.
  uint8_t actualDirection : 2;  //! The actual direction of rotation.
  uint8_t desiredDirection : 1; //! The desired direction of rotation.
  uint8_t driveWaveform : 2;    //! The current waveform that should be produced.
} PMSMflags_t;

I get the following error when I try to compile:

 

 "warning: passing 'volatile PMSMflags_t {aka volatile PMSMflags}' as 'this' argument of 'PMSMflags& PMSMflags::operator=(const PMSMflags&)' discards qualifiers [-fpermissive] fastFlags = fastFlagsInitial;

 

I admit that I have some reading up to do before I will understand what that line does. What I think it does is, it creates an instance of the PMSMflags structure and stores it on the GPIOR0 register, presumably because the processor can access it faster.

 

thadwald

Last Edited: Thu. Apr 20, 2017 - 03:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thadwald wrote:
I get the following error when I try to compile:
That's not an error it is a warning?

 

Anyway what the warning is talking about is an overload of the '=' operator and the fact that a "volatile" is being dropped at some point. So in the code that is implementing the overload of = (which you haven't shown) there's probably a "volatile" missing somewhere.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I should not be using the Arduino app for this. It is not showing me the overload of = either.

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry are you saying this:

 

 "warning: passing 'volatile PMSMflags_t {aka volatile PMSMflags}' as 'this' argument of 'PMSMflags& PMSMflags::operator=(const PMSMflags&)' discards qualifiers [-fpermissive] fastFlags = fastFlagsInitial;

 

is occurring in Arduino library code rather than something you have written yourself? If so where is this code located? Is it visible on the internet somewhere?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define fastFlags (*(volatile PMSMflags_t*)_SFR_MEM_ADDR(GPIOR0))

 

clawson wrote:

 "warning: passing 'volatile PMSMflags_t {aka volatile PMSMflags}' as 'this' argument of 'PMSMflags& PMSMflags::operator=(const PMSMflags&)' discards qualifiers [-fpermissive] fastFlags = fastFlagsInitial;

//Initialize fastflags. Use temporary variable to avoid several accesses to
  //volatile variable.
  {
    PMSMflags_t fastFlagsInitial;

    // Set motorStopped to FALSE at startup. This will make sure that the motor
    // is not started if it is not really stopped. If it is stopped, this variable
    // will quickly be updated.
    fastFlagsInitial.motorStopped = FALSE;

    // Set motorSyncronized to FALSE at startup. This will prevent the motor from being
    // driven until the motor is in synch or stopped.
    fastFlagsInitial.motorSynchronized = FALSE;
    fastFlagsInitial.actualDirection = DIRECTION_UNKNOWN;
    fastFlagsInitial.desiredDirection = 0;
    fastFlagsInitial.driveWaveform = WAVEFORM_UNDEFINED;

    fastFlags = fastFlagsInitial;
  }

This is where the warning occurs.

 

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's the entire compiler output. I see now that the problem is not the warning. Can you tell me why it is giving me "no matching function for call to ..."? 

 

 

/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino: In function 'void setup()':
/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino:174:15: warning: passing 'volatile PMSMflags_t {aka volatile PMSMflags}' as 'this' argument of 'PMSMflags& PMSMflags::operator=(const PMSMflags&)' discards qualifiers [-fpermissive]
     fastFlags = fastFlagsInitial;
               ^
/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino: In function 'void ActualDirectionUpdate(uint8_t, uint8_t)':
AVR447:49: error: no matching function for call to 'PMSMflags::PMSMflags(volatile PMSMflags_t&)'
 #define fastFlags (*(volatile PMSMflags_t*)_SFR_MEM_ADDR(GPIOR0))
                                                                 ^
/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino:620:29: note: in expansion of macro 'fastFlags'
     PMSMflags_t tempFlags = fastFlags;
                             ^
/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino:49:65: note: candidates are:
 #define fastFlags (*(volatile PMSMflags_t*)_SFR_MEM_ADDR(GPIOR0))
                                                                 ^
/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino:620:29: note: in expansion of macro 'fastFlags'
     PMSMflags_t tempFlags = fastFlags;
                             ^
In file included from /Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino:31:0:
sketch/PMSM.h:253:16: note: PMSMflags::PMSMflags()
 typedef struct PMSMflags
                ^
sketch/PMSM.h:253:16: note:   candidate expects 0 arguments, 1 provided
sketch/PMSM.h:253:16: note: constexpr PMSMflags::PMSMflags(const PMSMflags&)
sketch/PMSM.h:253:16: note:   no known conversion for argument 1 from 'volatile PMSMflags_t {aka volatile PMSMflags}' to 'const PMSMflags&'
sketch/PMSM.h:253:16: note: constexpr PMSMflags::PMSMflags(PMSMflags&&)
sketch/PMSM.h:253:16: note:   no known conversion for argument 1 from 'volatile PMSMflags_t {aka volatile PMSMflags}' to 'PMSMflags&&'
/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino:623:15: warning: passing 'volatile PMSMflags_t {aka volatile PMSMflags}' as 'this' argument of 'PMSMflags& PMSMflags::operator=(const PMSMflags&)' discards qualifiers [-fpermissive]
     fastFlags = tempFlags;
               ^
/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino: In function 'void MotorSynchronizedUpdate()':
AVR447:861: error: no match for 'operator=' (operand types are 'PMSMflags_t {aka PMSMflags}' and 'volatile PMSMflags_t {aka volatile PMSMflags}')
   tempFlags = fastFlags;
             ^
/Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino:861:13: note: candidates are:
In file included from /Users/thaddeuswaldner/Documents/Arduino/AVR447/AVR447.ino:31:0:
sketch/PMSM.h:253:16: note: PMSMflags& PMSMflags::operator=(const PMSMflags&)
 typedef struct PMSMflags
                ^
sketch/PMSM.h:253:16: note:   no known conversion for argument 1 from 'volatile PMSMflags_t {aka volatile PMSMflags}' to 'const PMSMflags&'
sketch/PMSM.h:253:16: note: PMSMflags& PMSMflags::operator=(PMSMflags&&)
sketch/PMSM.h:253:16: note:   no known conversion for argument 1 from 'volatile PMSMflags_t {aka volatile PMSMflags}' to 'PMSMflags&&'
exit status 1
no matching function for call to 'PMSMflags::PMSMflags(volatile PMSMflags_t&)'

 

//__io volatile PMSMflags_t fastFlags                               @0x1e;
#define fastFlags (*(volatile PMSMflags_t*)_SFR_MEM_ADDR(GPIOR0))


...


#pragma inline=forced
static void ActualDirectionUpdate(uint8_t lastHall, const uint8_t newHall)
{
  //Make sure that lastHall is within bounds of table. If not, set to 0, which is
  //also an illegal hall value, but legal table index.
  if (lastHall > 6)
  {
    lastHall = 0;
  }
  if (expectedHallSequenceForward[lastHall] == newHall)
  {
    fastFlags.actualDirection = DIRECTION_FORWARD;
  }
  else if (expectedHallSequenceReverse[lastHall] == newHall)
  {
    fastFlags.actualDirection = DIRECTION_REVERSE;
  }
  else
  {
    PMSMflags_t tempFlags = fastFlags;
    tempFlags.actualDirection = DIRECTION_UNKNOWN;
    tempFlags.motorSynchronized = FALSE;
    fastFlags = tempFlags;
  }
}

 

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thadwald wrote:

//mine--copied from elsewhere in this forum where someone tried to do the exact same thing 
#define fastFlags (*(volatile PMSMflags_t*)_SFR_MEM_ADDR(GPIOR0)

 

Do you have a link to that thread?

Bob.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

donotdespisethesnake wrote:

 

Do you have a link to that thread?

 

http://www.avrfreaks.net/forum/s...

thadwald

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thadwald wrote:

donotdespisethesnake wrote:

 

Do you have a link to that thread?

 

http://www.avrfreaks.net/forum/s...

 

Thanks! That's good reading. But you are not doing exactly the same things with that struct - you are assigning to the whole struct, which is one of the things the thread starter said didn't work. In code:

 

// OK
  fastFlags.motorStopped = 1;
  test = fastFlags.motorSynchronized;

  // Not OK
  fastFlags = 0x02;
  fastFlags = test;
  test = fastFlags;

To assign to the whole byte, you need to change your struct :

 

For example, something like this :

 


typedef union PMSMflags
{
  struct {
  uint8_t motorStopped : 1;     //! Is motor stopped?
  uint8_t motorSynchronized: 1; //! Is motor synchronized?
  };
  uint8_t asByte;
} PMSMflags_t;

#define fastFlags (*(volatile PMSMflags_t*)_SFR_MEM_ADDR(GPIOR0))

uint8_t test;

void setup() {
// OK
  fastFlags.motorStopped = 1;
  test = fastFlags.motorSynchronized;

  // Now OK
  fastFlags.asByte = 0x02;
  fastFlags.asByte = test;
  test = fastFlags.asByte;
}

void loop() {
  // put your main code here, to run repeatedly:

}

Note, this compiles cleanly but I didn't check run. I'm 99.5% sure it works ... :)

Bob.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It compiles without errors now.

 

Thank you!

 

The AVR447 application notes specify that the IAR complier be set to lock GPIO registers 7 to 15 for global variables. Is there a parallel option in AVR Studio 7?

thadwald