Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 8 of 8

Thread: is it okay to use analgoWrite() in an ISR?

  1. #1

    is it okay to use analgoWrite() in an ISR?

    Hey folks,

    I'm been using code similar to what's below to run a brushless motor, but it involves sending to analogWrites to each of the three leads of a motor. I'd like to do be able to control velocity in a very precise way for a balancing robot, and to be able to change velocity outside of the main loop. Is it okay to use analogWrite() in an ISR? I'lll be making various tests using and oscilloscope but I thought I'd ask for everyone's opinion as well.

    thanks.

    owen

    Code:
    #define ENABLE_PIN    11
    #define LED_PIN       13 
    
    // LED 
    boolean blinkOn = false;
    uint32_t blinkDelta = 0;
    uint32_t blinkInterval = 50;
    uint32_t blinkNow;
    
    unsigned long loopTimer;
    
    // motor numbers
    #define L_Motor 0
    #define R_Motor 1
    
    // motor pole angle, 0->255 overflow to loop after >>8 shift
    uint16_t R_MotorStep = 0;
    uint16_t L_MotorStep = 0;
    
    uint16_t MotorPower = 120;
    uint16_t idl_motor_power = 80;
    
    // speed of motors, -127 to 127
    int16_t R_Speed = 0;
    int16_t L_Speed = 0;
    
    volatile uint16_t _freqCounter = 0;
    volatile uint16_t _R_MotorStep = 0;
    volatile uint16_t _L_MotorStep = 0;
    volatile uint16_t _R_Speed = 0;
    volatile uint16_t _L_Speed = 0;
    volatile uint16_t _power;
    
    byte motorPins[2][3]={
      {0, 2, 1}, // M0
      {5, 9, 6}  // M1
    };
    
    int8_t pwmSinMotor[] = {0,  5,  10, 16, 21, 27, 32, 37, 43, 48, 53, 59, 64, 69, 74, 79, 84, 89, 94, 99, 104,  109, 
    			111,  112,  114,  115,  116,  118,  119,  120,  121,  122,  123,  123,  124,  125,  125,  126,  126,  126,  127,  
    			127,  127,  127,  127,  127,  126,  126,  126,  125,  125,  124,  123,  123,  122,  121,  120,  119,  118,  116,  
    			115,  114,  112,  111,  110,  112,  113,  114,  116,  117,  118,  119,  120,  121,  122,  123,  124,  124,  125,  
    			125,  126,  126,  126,  127,  127,  127,  127,  127,  126,  126,  126,  125,  125,  124,  124,  123,  122,  121,  
    			120,  119,  118,  117,  116,  114,  113,  112,  110,  106,  101,  97, 92, 87, 82, 77, 72, 66, 61, 56, 51, 45, 40, 
    			35, 29, 24, 18, 13, 8,  2,  -2, -8, -13,  -18,  -24,  -29,  -35,  -40,  -45,  -51,  -56,  -61,  -66,  -72,  -77,  
    			-82,  -87,  -92,  -97,  -101, -106, -110, -112, -113, -114, -116, -117, -118, -119, -120, -121, -122, -123, -124, 
    			-124, -125, -125, -126, -126, -126, -127, -127, -127, -127, -127, -126, -126, -126, -125, -125, -124, -124, -123, 
    			-122, -121, -120, -119, -118, -117, -116, -114, -113, -112, -110, -111, -112, -114, -115, -116, -118, -119, -120, 
    			-121, -122, -123, -123, -124, -125, -125, -126, -126, -126, -127, -127, -127, -127, -127, -127, -126, -126, -126, 
    			-125, -125, -124, -123, -123, -122, -121, -120, -119, -118, -116, -115, -114, -112, -111, -109, -104, -99,  -94,  
    			-89,  -84,  -79,  -74,  -69,  -64,  -59,  -53,  -48,  -43,  -37,  -32,  -27,  -21,  -16,  -10,  -5, 0};
    
    IntervalTimer ISR_function;
    
    void setup() {
      // motor inits
      initMotors();
      setMotorState(true);
    
      ISR_function.begin(tickLoop, 2); 
      loopTimer = micros() + 4000;
    }
    
    
    void loop() {
      noInterrupts();
      R_MotorStep = _R_MotorStep;
      L_MotorStep = _L_MotorStep;
      _R_Speed = R_Speed;
      _L_Speed = L_Speed;
      _power = MotorPower;
      interrupts();
    
      R_MotorStep++;
    }
    
    void initMotors() {
      for (int8_t x = 0; x < 2; x++) {
        pinMode(motorPins[x][0], OUTPUT);
        pinMode(motorPins[x][1], OUTPUT);
        pinMode(motorPins[x][2], OUTPUT);
        analogWriteFrequency(motorPins[x][0], 32000); 
        analogWriteFrequency(motorPins[x][1], 32000); 
        analogWriteFrequency(motorPins[x][2], 32000); 
      }
      pinMode(ENABLE_PIN, OUTPUT);
      digitalWrite(ENABLE_PIN, LOW);
    }
    
    void setMotorState(boolean flag) {
      if (flag) { digitalWrite(ENABLE_PIN, HIGH); } // enable 
      else { digitalWrite(ENABLE_PIN, LOW); } // disable
    }
    
    void tickLoop() {
      _freqCounter++;
    
      if (_freqCounter > _R_Speed) {
        _freqCounter = 0;
    
        _R_MotorStep++;
    
        volatile uint16_t pwm_a, pwm_b, pwm_c;
        volatile uint8_t x, y, z;
        volatile uint8_t posStep = (uint8_t)(_R_MotorStep >> 8);
    
        pwm_a = pwmSinMotor[(uint8_t)posStep];
        pwm_b = pwmSinMotor[(uint8_t)(posStep + 85)];
        pwm_c = pwmSinMotor[(uint8_t)(posStep + 170)];
    
        pwm_a = _power * pwm_a; // scales motor power
        pwm_a = pwm_a >> 8;
        pwm_a += 128;
        x = pwm_a;
    
        pwm_b = _power * pwm_b;
        pwm_b = pwm_b >> 8;
        pwm_b += 128;
        y = pwm_b;
    
        pwm_c = _power * pwm_c;
        pwm_c = pwm_c >> 8;
        pwm_c += 128;
        z = pwm_c;
    
        analogWrite(motorPins[0][0], x);
        analogWrite(motorPins[0][1], y);
        analogWrite(motorPins[0][2], z);
      }
    }

  2. #2
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,244
    Setting a few registers isn't time consuming, so analogWrite() is perfectly fine to call in an ISR. The things to
    avoid are delaying significantly or calling some subsystem that itself relies on interrupts to progress, such as
    Serial.

  3. #3
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    9,567
    For what it is worth, I think it should be fine, as it mostly figures out what hardware register to write to, convert your value to the appropriate value for that register and write it out... Nothing that should be time consuming nor anything that has delays in it... But than again I have been wrong before

    Also in this case I don't think it maters, but code is different for T4 versus T3.x... So might help to know which Teensy.

  4. #4
    Thank you people. I thought I read somewhere that analogWrites that set PWM are based on interrupts, so I thought maybe I was creating code that might be working at cross-purposes.

  5. #5
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,244
    Sometimes if there isn't hardware, an interrupt might be used - so use a hardware PWM pin. An example is the Arduino Servo library which does this,
    so you'd probably have issues trying to use that from inside another ISR.

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,067
    I would answer with a qualified "yes". The usage you have shown should be safe, and most normal uses of analogWrite inside an interrupt should work.

    But there are not-so-normal cases that may not work. Using analogWriteFrequency() on the same pin while the interrupt might occur is likely to cause trouble. Likewise, you could expect problems if you use analogWrite() to the same pin from both the main program and your interrupt, or from multiple interrupts running at different interrupt priority levels.

    Your program appears to use analogWriteFrequency() only during setup() and before the IntervalTimer interrupt is turned on, so I believe this should be fine. Looks like you're also making use of volatile and temporarily disabling interrupts while accessing a group of shared variables, which is good. The use of volatile on local scope variables inside the interrupt isn't necessary, but isn't harmful either, other than running slightly slower.

  7. #7
    Thanks. So just to confirm - it sounds like I can create local variables that are not volatile in the ISR function, correct?

    And, I will be sure not to make any calls to the pins used in ISR/analogWrites outside of the ISR.

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,067
    Yes, local variables with simple types (eg, not pointers) within the interrupt function do not need to be volatile.

    But using volatile isn't really harmful. It just makes your code run slower, because the compiler can't do most optimizations.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •