Quantcast
Channel: Arduino Forum - Latest topics
Viewing all articles
Browse latest Browse all 15574

TB6612 microstepping with unoR4

$
0
0

For your information I have developped a sketch to perform microstepping using a uno R4, a TB6612 shield and a 17HS4401 microstep motor. The goal was to achieve slow and very quiet rotation using 256x50 steps per rotation and reducing the cosumption to a minimum. I use four PWM outputs with a frequency of 10KHZ. It gives me 4800 different levels of PWM.

Achievment : the motor is perfectly quiet up to 0.5 r/s. The maximum speed is 4 turn/second. It consumes 100mA with a 9V (8V in fact) battery (Vin) with raisonnable (low) torque. I can reduce the torque and consume down to 50mA. This does not include the UNOR4.

I use the EventLinkInterrupt library from David Caldwell. Thanks.
So It works on UNOR4 only, a 10 Khz interrupt is only possible with this fast processor.
The rotation period is perfectly precise in terms of timing, in multiple of 1,041 µs ( see code).
(but do'nt forget that the 48Mhz of the card is not precise at all :frowning_face: )

My final need is to make it turn once every 70.558 seconds to build a DOY equatorial stand for my camera.
If someone wants to turn it into a library, no problem, I dont own it.

The wiring :

and the demo program :

//______________________________________________________________________________________________________
#include "EventLinkInterrupt.h"
// Writen by Eric AZELART march 2024
// 256 steps of sinusoid with 4800 max amplitude
int sina[256] = {
  0, 118, 236, 353, 470, 588, 704, 821, 936, 1052, 1166, 1280, 1393, 1506, 1617, 1727, 1837, 1945, 2052, 2158, 2263, 2366, 2468, 2568, 2667, 2764,
  2859, 2953, 3045, 3135, 3223, 3310, 3394, 3476, 3557, 3635, 3710, 3784, 3855, 3924, 3991, 4055, 4117, 4176, 4233, 4287, 4339, 4388, 4435, 4478,
  4519, 4558, 4593, 4626, 4656, 4683, 4708, 4729, 4748, 4764, 4777, 4787, 4794, 4799, 4800, 4799, 4794, 4787, 4777, 4764, 4748, 4729, 4708, 4683,
  4656, 4626, 4593, 4558, 4519, 4478, 4435, 4388, 4339, 4287, 4233, 4176, 4117, 4055, 3991, 3924, 3855, 3784, 3710, 3635, 3557, 3476, 3394, 3310,
  3223, 3135, 3045, 2953, 2859, 2764, 2667, 2568, 2468, 2366, 2263, 2158, 2052, 1945, 1837, 1727, 1617, 1506, 1393, 1280, 1166, 1052, 936, 821, 704,
  588, 470, 353, 236, 118, 0, -118, -236, -353, -470, -588, -704, -821, -936, -1052, -1166, -1280, -1393, -1506, -1617, -1728, -1837, -1945, -2052,
  -2158, -2263, -2366, -2468, -2568, -2667, -2764, -2859, -2953, -3045, -3135, -3223, -3310, -3394, -3476, -3557, -3635, -3710, -3784, -3855, -3924,
  -3991, -4055, -4117, -4176, -4233, -4287, -4339, -4388, -4435, -4478, -4519, -4558, -4593, -4626, -4656, -4683, -4708, -4729, -4748, -4764, -4777,
  -4787, -4794, -4799, -4800, -4799, -4794, -4787, -4777, -4764, -4748, -4729, -4708, -4683, -4656, -4626, -4593, -4558, -4519, -4478, -4435, -4388,
  -4339, -4287, -4233, -4176, -4117, -4055, -3991, -3924, -3855, -3784, -3710, -3635, -3557, -3476, -3394, -3310, -3223, -3135, -3045, -2953, -2859,
  -2764, -2667, -2568, -2468, -2366, -2263, -2158, -2052, -1945, -1837, -1728, -1617, -1506, -1393, -1280, -1166, -1052, -936, -821, -704, -588,
  -470, -353, -236, -118
};

#define FREQ 4800          // for 10 000 Hz IRQ
#define MAX_SPEED 240000L  // 4 rotation per second (48000000/(50*4 ))
#define SEC_ 1000000L      // in µs
#define uc unsigned char

// variables to be set              (those variables can be read by interrupt any time)
boolean sens;            // gives the rotation
unsigned long tick = 0;  // number of clocks (*256) between two micro steps, 0 meaning "stop". tick = ( 48000000 / (speed * 50))
unsigned long gain = 0;  // tension to be proportionate to speed min : 0 , max 1024 ;

// variables to be read             (those variables can be changed by interrupt any time)

volatile unsigned long count = 0;  // compared to tick
volatile long step = 0;            // number of micro steps since reset, négative and positive.
unsigned long count_irq;           // number of irq served since reset, not very useful

// variables to be untouched
unsigned char kk = 0;    // pointer in sinusoid
int pwm1 = 0, pwm2 = 0;  // actual pmw values
unsigned int IrqIndex;   // interrupt vector

void micro_step_setup() {

  // pinMode(2, OUTPUT); // if pin2 used for spying irqs

  analogWrite(6, 255);
  analogWrite(7, 255);
  analogWrite(8, 255);
  analogWrite(9, 255);  // this forces pwms to be programmed

  Serial.begin(9600);

  R_GPT7->GTWP = 0xA500;          // allow to write in timer registers
  R_GPT7->GTCR = 0x00000001;      // start counter, saw wave, clk = 48 Mhz
  R_GPT7->GTPBR = FREQ - 1;       // set to 10 000 Hz
  R_GPT7->GTBER = 0x1F0000;       // double buffer operation to give time to irq

  R_GPT3->GTWP = 0xA500;
  R_GPT3->GTCR = 0x00000001;
  R_GPT3->GTPBR = FREQ - 1;
  R_GPT3->GTBER = 0x1F0000;

  R_GPT3->GTCLR = 0x0000088;      // clear counter 3 and 7


  IrqIndex = attachEventLinkInterrupt(0x95, IrqHandler);  // 0x95 means GPT7 overflow
}

void IrqHandler(void) {
  // digitalWrite(2, 1);  // to evaluate time in ITQ
  if (tick != 0) {
    count += FREQ * 256;
    if (tick < MAX_SPEED) {        // max speed 5 rot/s
      while (count > MAX_SPEED) {  // if speed > 0.7 rot/s, steps are skipped
        if (sens) kk++;
        else kk--;
        count -= MAX_SPEED;
        step++;  // number steps are ok even if steps are skipper
      }
    } else {
      while (count > tick) {  // if speed > 0.7 rot/s, steps are skipped
        if (sens) kk++;
        else kk--;
        count -= tick;
        step++;  // number steps are ok even if steps are skipper
      }
    }
  }

  pwm1 = FREQ / 2400 * ((long)(gain * sina[(uc)(kk + 00) & 0xFF]) / 2048);  // gain should be 0 to 1024 for no saturation
  pwm2 = FREQ / 2400 * ((long)(gain * sina[(uc)(kk + 64) & 0xFF]) / 2048);  // 64 for 90° phasing
  // 0xff stands for micro stepping : 0xFF:256, 0xFE:128, 0xFC:64, 0xF8:32, 0xF0:16, 0xE0:8, 0xC0:4. less will not work
  if (pwm1 > FREQ) pwm1 = FREQ;
  if (pwm2 > FREQ) pwm2 = FREQ;

  count_irq++;

  if (pwm1 >= 0) {
    R_GPT7->GTCCR[2] = FREQ - pwm1;  // pin 8
    R_GPT7->GTCCR[5] = FREQ;         // pin 9
  } else {
    R_GPT7->GTCCR[2] = FREQ;         // pin 8
    R_GPT7->GTCCR[5] = FREQ + pwm1;  // pin 9
  }
  if (pwm2 >= 0) {
    R_GPT3->GTCCR[2] = FREQ - pwm2;  // pin 6
    R_GPT3->GTCCR[5] = FREQ;         // pin 7
  } else {
    R_GPT3->GTCCR[2] = FREQ;         // pin 6
    R_GPT3->GTCCR[5] = FREQ + pwm2;  // pin 7
  }

  resetEventLink(IrqIndex);
  // digitalWrite(2, 0);  // to evaluate time in ITQ
}
void setup() {
  micro_step_setup();
}
void loop() {

  // minimum to make it work : set tick, sens and gain ;

  unsigned int jj = 0;
  unsigned long ii, iii, ll, lll, hh, hhh, tick1;
  int speed = 0, gain1 = 0;
  bool sens1;
  iii = ii = micros();

  lll = ll = step;
  hhh = hh = count_irq;

  while (1) {

    while ((micros() - ii) > (SEC_ / 100)) {  // we are here every second/100, even during long overflow
      ii += SEC_ / 100;

      speed = (analogRead(A0)) - 512;  // speed from -5.12 to 5.11

      if (speed >= 0) {
        sens1 = true;
      } else {
        sens1 = false;
      }

      if (speed != 0) {
        tick1 = (96000000L / abs(speed));
        if (tick1 < MAX_SPEED) tick1 = MAX_SPEED;

      } else {
        tick1 = 0;
      }

      gain1 = 200 + (35000 * FREQ) / tick1; //  this gives a balance between torque and comsumption 
      //                                        200 and 35000 are OK for 8V Vin. motor draws about 100mA
      //                                        higher numbers for more torque and noise and current
      //                                        lower numbers for more silence
     
      if (gain1 > 1024) gain1 = 1024;

      sens = sens1;
      tick = tick1;
      gain = gain1;  // change values of sens, gain, tick only when computed
    }


    while (micros() - iii > SEC_) {  // we are here every second, even during long overflow
      iii += SEC_;

      lll = step - ll;  // how many steps in one second
      ll += lll;

      hhh = count_irq - hh;
      hh += hhh;  // how may irq_s in one second



      Serial.print(speed);  // Speed set
      Serial.print(",");
      Serial.print((lll * 10000) / (256 * 50));  // measured absolute speed (*1000) if no rotation inversion
      Serial.print(",");
      Serial.print(lll);  // number of steps
      Serial.print(",");
      Serial.print(hhh);  // number of irqs
      Serial.print(",");
      Serial.print(tick * 1000 / (256 * 48));  // actual period between steps in ns
      Serial.print(",");
      Serial.println(gain);
    }
  }
}
//_____________________________________________________________________________________________________

1 post - 1 participant

Read full topic


Viewing all articles
Browse latest Browse all 15574

Latest Images

Trending Articles



Latest Images