Trying to run a motor

Hello,

I have a small DC motor (20mA), which only needs to run in one direction.
It's speed shall be regulated via back-EMF. Thus the motor is directly connected between Pin11 and GND. Diode to GND is there.

Using analogWrite(11, dutycycle); works.

However, when I want to measure the back-EMF, then I have to do it at the falling edge of the dutycycle.

Obviously, I could feed pin 11 to pin 1 and have a falling edge IRQ do the job.

Stupid as I am, I thought, it should however also work with T2 as fast PWM generator. IRQ generated on the compare. In the ISR I can then do the motor regulation. That however is a later topic right now.

I don't even get the PWM to work and I'm at my wits end.
What is wrong?

This the important part of the sketch:

void start_motor(void)
{
//digitalWrite(motor_drv,HIGH);
//analogWrite(motor_drv,start_rev);
//TIMSK2 &= _BV(OCIE1B); // disable T1 compare A interrupt
OCR2A = start_rev;
OCR2B = start_rev;
delay(start_time);
OCR2B = mid_rev;
OCR2A = mid_rev;
//TIMSK2 |= _BV(OCIE1B); // enable T1 compare A interrupt
Serial.println("Motor started");
}
void setup() {
// put your setup code here, to run once:
pinMode(motor_drv, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(stall_ind, OUTPUT);
pinMode(shunt, INPUT);
pinMode(motor_pos, INPUT);

k=0;
//PRR &= _BV(PRTIM2); // enable T2
TCCR2B = _BV(CS22); // T2 clk = sysclk/64,
//TCCR2B = _BV(WGM22) | _BV(CS22); // T2 clk = sysclk/64,
//TCCR2B = _BV(WGM22) | _BV(CS20); // T2 clk = sysclk
//TCCR2A = B01100011; // T2 = fast PWM w/ end of duty cycle at OCRA match, output on D11
//TIMSK2 |= _BV(OCIE1A); // enable T1 compare A interrupt
//TIMSK1 |= _BV(OCIE1B); // enable T1 compare B interrupt

TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);

//TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);

Serial.begin(115200);
start_motor();

}

I have uncommented everything in loop() regarding the motor. So it should just run with one straight PWM. Impossible. It either does not run at all or it runs full speed.

Like I said, I don't understand how this should be made to work. The Atmega328p DS and code examples in the Internet do not run the motor with a PWM. Full speed or stop, that's all I get.

Thanks for your help in advance.

BR

First you did not follow the guidlines on how to post your code.
In the IDE click on Edit then Copy For Forum and paste your code here.

Second when the PWM signal goes to zero, it essentially shorts the motor to ground, so you can't read the back EMF

OK, here the complete code as it is not fully debugged yet.

To measure the back_EMF, the port has to get configured as INPUT.

#define HIGH 1
#define LOW 0

#define motor_drv 11      // PWM output via T2
#define shunt A0
#define motor_pos A1
#define stall_ind 10

#define min_EMF 2
#define good_rev 65
#define mid_rev 100
#define start_rev 255
#define start_time 1000

#define TCCR2A_on B10100011
#define TCCR2A_off B00000011

unsigned int v_EMF;
unsigned char k;

void start_motor(void)
  {
    //digitalWrite(motor_drv,HIGH);
    //analogWrite(motor_drv,start_rev);
    TIMSK2 &= _BV(OCIE1B);    // disable T1 compare B interrupt
    OCR2A = start_rev;
    OCR2B = start_rev;
    delay(start_time);
    OCR2B = good_rev;
    OCR2A = good_rev;
    //TIMSK2 |= _BV(OCIE1B);    // enable T1 compare B interrupt
    Serial.println("Motor started");
  }




void setup() {
  // put your setup code here, to run once:
  pinMode(motor_drv, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(stall_ind, OUTPUT);
  pinMode(shunt, INPUT);
  pinMode(motor_pos, INPUT);
 
  k=0;
  //PRR &= _BV(PRTIM2);       // enable T2
  //TCCR2B = _BV(CS22);                     // T2 clk = sysclk/64,
  //TCCR2B = _BV(WGM22) | _BV(CS22);        // T2 clk = sysclk/64,
  //TCCR2B = _BV(WGM22) | _BV(CS20);      // T2 clk = sysclk
  TCCR2B = _BV(WGM22) | _BV(CS22) | _BV(CS21); // T2 clk = sysclk/256
  //TCCR2A = B01100011;       // T2 = fast PWM w/ end of duty cycle at OCRA match, output on D11
  //TIMSK2 |= _BV(OCIE1A);    // enable T1 compare A interrupt
  //TIMSK1 |= _BV(OCIE1B);    // enable T1 compare B interrupt
  //TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  //TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2A = TCCR2A_on;

  Serial.begin(115200);
  start_motor();
       
}



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



Serial.print("V EMF = ");
Serial.println(v_EMF);
OCR2B = good_rev;

if(v_EMF <= min_EMF)
  {
    k++;
    if (k>10)
      {
        digitalWrite(LED_BUILTIN, HIGH);
        digitalWrite(stall_ind, HIGH);        // motor stalled
        Serial.println("Motor got stalled");
        //start_motor();
        Serial.print("duty_cycle = ");
        Serial.println(OCR2B);
        
        k=0;
        
      }
  }
    
else
  {
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(stall_ind, LOW);           // motor running
    Serial.print("duty_cycle = ");
    Serial.println(OCR2B);
    
  }
  
}


ISR(TIMER2_COMPB_vect)
{
  unsigned int adc_value2;

    TIMSK2 &= _BV(OCIE1B);    // disable T1 compare A interrupt
    v_EMF = 0;
    //if (digitalRead(motor_pos) == LOW)
        //{
            
            TCCR2A = TCCR2A_off;
            pinMode(motor_drv, INPUT);
            adc_value2 = analogRead(motor_pos);
            Serial.print("adc_value = ");
            Serial.println(adc_value2);
            pinMode(motor_drv, OUTPUT);
            TCCR2A = TCCR2A_off;
            //analogWrite(motor_drv, good_rev);
        //}
    v_EMF += adc_value2;
    //v_EMF = v_EMF/8;
    TIMSK2 |= _BV(OCIE1B);    // enable T1 compare A interrupt
    TIFR2 = 0;                // erase IRQ flags
}

It is not safe to power any motor from a port pin, as motors generate high voltage spikes that will eventually destroy the pin circuitry, and possibly, take the rest of the MCU with it.

I can add a TVR diode to the ports.

The question is, how can I get the PWM to work? What is wrong in my sketch?

A post was split to a new topic: "Copy for Forum (Markdown)" adds a "cpp" after the opening backticks

I hope you have more Arduinos on hand. It's a pleasant surprise that it hasn't fried yet, but it’s likely to fail soon.

Gil's Crispy Critter Rules for Processor Hardware:

  1. Rule #1: An Arduino is NOT a Power Supply!
  2. Rule #2: Never connect anything inductive (motors, speakers) directly to an Arduino!
  3. Rule #3: Avoid connecting or disconnecting wires while the power is on.
  4. Rule #4: Do not apply power to any pin unless you are certain of what you're doing.
  5. Rule #5: Do not exceed the maximum voltage ratings.
  6. Rule #6: Many Arduinos cannot power transmitters directly.
  7. Rule #7: Before powering your project, take a break and double-check the wiring.

LaryD’s Corollaries:

  1. Coro #1: When starting out, add a 220Ω resistor in series with both input and output pins to protect against shorts.
  2. Coro #2: Invest in a Digital Multi-Meter (DMM) to measure voltages, currents, and resistance.

Note: Violating these rules can turn your Arduinos into crispy critters. For optimal performance, keep your wires under 25 cm (10 inches).

Additional Tips:

  • The L293 motor driver, though common, is inefficient as it can lose around 3V as heat when driving both legs of a motor. Consider using a motor driver with MOSFET outputs to reduce heat loss and conserve battery power.
  • For more on powering Arduino boards, explore this guide: Powering Alternatives for Arduino Boards.

Arduinos are strong, don't underestimate them

I have worked through the night and the motor drive is working now.
I have used IRQ0 to detect the falling edge of the PWM as described earlier.

I thought, T1 and T2 could be freely used, but I have the feeling, the settings are getting overwritten every so often, apart from certain settings not working at all.
Well, it is a suspition only. I have given up on using the timers by direct access to the SFRs. Even examples copied from the Internet don't work consistently.

The Arduino Nano and the Motor are now working happily together, by sticking to the Arduino makros. That said, they both had to endure all my trials throughout the night. Last two hours, they had been running without interrpution and have not made their way into Nirvana.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.