Jump to content
43oh

CNC-milling: create 3 different frequencies with MSP430G2553


Recommended Posts

For my new project (a self made cnc-milling-machine - mostly for pcb-prototyping and some kind of soft woods or plastics) i need to control 3 stepper motors - i already built up the translator and power-part of (L297 + L298)

 

first i tried interrupts - 30 kHz ... more than expected - but too less for my next project

 

Benchmarking... maximum possible frequency is about 1.5 MHz on P1.3

... so my 3 instructions (asm-equivalent: bitc, bits, jmp) take about 10 cycles? o.O this is really much ...

	for(; {
	// X-Axis
		P1OUT |= BIT3;
		P1OUT &= ~BIT3;
	}

 

Benchmarking in a real configuration... ~ 119 kHz output on P1.3 - P1.5

	for(; {
	// X-Axis
	BaseClockX--;
	if (BaseClockX == 0) {
		BaseClockX = mod_X;
		if (position_X != target_X) {
			P1OUT |= BIT3;
			P1OUT &= ~BIT3;
			if (dir_X == CW) {
				position_X++;
			}
			else {
				position_X--;
			}
		}
	}

	// 2 more axis

 

with this setup i can realise following output-frequencys and speeds:

Frequency IN	Counter	Frequency OUT	s-1		mm / min			
119000			1			119000			595		35700			
119000			2			59500			297		17850
119000			3			39666			198		11900
119000			4			29750			148		8925
119000			5			23800			119		7140
119000			6			19833			99		5950
119000			7			17000			85		5100
119000			8			14875			74		4462
119000			9			13222			66		3966
119000			10			11900			59		3570
119000			11			10818			54		3245
119000			12			9916			49		2975
... (i didnt want to copy the complete excel list in here)

 

As you can see the accuracy gets better the higher the mod-value gets.

 

My question: Is there any other possibility to create 3 independent output-frequencies? (I need a range from 0 - ~2500 Hz)

 

---

 

Another option maybe to fix the frequency for all 3 axis to the same value and then just do the movement by pulsing the clock-inputs as needed.

 

---

 

Has anyone of you tried to built up his own CNC-mill?

Link to post
Share on other sites

Here is some code that uses NCOs to generate three frequencies with 100 uHz (0.0001 Hz) resolution for a specified duration.

 

There will be some jitter when 100000 / Frequency is not an integer. This may or may not be a problem. There are ways to reduce the jitter, but more hardware is required.

 

Be very careful with the ISR code - it must be able to run in under 120 cycles.

 

#include "msp430g2553.h"

static long int timer = 0;      // Duration of motion
static long int pix = 0;        // Phase increment
static long int piy = 0;
static long int piz = 0;
static long int px = 0;         // Position
static long int py = 0;
static long int pz = 0;
static long int dx = 1;         // Direction
static long int dy = 1;
static long int dz = 1;

                           // Sample rate * (1 / resolution in Hz)
static const long int pl = 1000000000;

void set_fx(long int f) { pix = f - pl; }
void set_fy(long int f) { piy = f - pl; }
void set_fz(long int f) { piz = f - pl; }

void main(void)
{
   WDTCTL = WDTPW | WDTHOLD;   // Disable watchdog

   DCOCTL = 0;
   BCSCTL1 = CALBC1_16MHZ;     // Set DCO to 16 MHz
   DCOCTL = CALDCO_16MHZ;      //

   P1DIR = 0x13;               // I/O assignment
   P1REN = 0x00;               // 
   P1OUT = 0x02;               //
   P1SEL = 0x10;               // Enable SMCLK output
   P2DIR = 0x07;               //
   P2REN = 0x00;               //
   P2OUT = 0x00;               //
   P2SEL = 0xC0;               //

   TA0CTL = TASSEL_2 | MC_1;   // Timer A config: SMCLK, count up
   TA0CCR0  = 160 - 1;         // Setup Timer A CCR0 period for 100,000 Hz
   TA0CCTL0 |= CCIE;           // Enable PWM interrupt

   _EINT();                    // Enable interrupts

   set_fx(10000000);           // 1000.0000 Hz
   set_fy(20000000);           // 2000.0000 Hz
   set_fz(25000000);           // 2500.0000 Hz

   timer = -1;                 // Run for a long time
   for(;;
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void timer_a_isr(void)
{
   static long int pax = 0;   // Phase accumulator
   static long int pay = 0;
   static long int paz = 0;

   if(timer) {
       --timer;
       pax += pix; if(pax < 0) pax += pl; else { P2OUT |= 1; px += dx; P2OUT &= ~1; }
       pay += piy; if(pay < 0) pay += pl; else { P2OUT |= 2; py += dy; P2OUT &= ~2; }
       paz += piz; if(paz < 0) paz += pl; else { P2OUT |= 4; pz += dz; P2OUT &= ~4; }  
   }
}

Link to post
Share on other sites

thanks oPossum - i will have a look on your code - 120 cycles sounds more than it is :lol:

 

i will use the PC to translate and interpolate the g-code (especially 3-dimensional-arc-interpolations will take too long on MCU without lookup-tables) - the MCU will then get some data like speed (frequency) - target-position - sync (wait for all 3 axis reaching their target - should not be needed if everything works fine)

Link to post
Share on other sites

You think about use MSP with high resolution timer ( "Timer_D" )?

This timer work at frequency 16 x higher than processor clock frequency (256MHz at 16 MHz clock!!!) and give you more precision at frequency control. Look at [tipdf]slau208[/tipdf], chapter 16.1 (page 400) for more information.

Link to post
Share on other sites
I've read in the Ti datasheets that the max input frequency on an IO pin is something like 20MHz.

 

What about cranking the MCU speed up to the max?

Or have you done that already?

 

i think 16 MHz should be enough ;) the steppers can only go up to about 3000 Hz (steps per second) - so there is no need for higher speed of the IO ;)

 

You think about use MSP with high resolution timer ( "Timer_D" )?

This timer work at frequency 16 x higher than processor clock frequency (256MHz at 16 MHz clock!!!) and give you more precision at frequency control. Look at slau208, chapter 16.1 (page 400) for more information.

 

i'm using the MSP430G2553 - i dont think that it has sich a timer ;)

 

---

 

with the help of oPossums piece of code i created the following function - works nice for now ... more to come in a separate thread with the complete code and more details on the configuration

 

void set_Position_AbsoluteSpeed(unsigned long int x, unsigned long int y, unsigned long int z, unsigned long int absolute_speed) {
// set new target position
target_x = x;
target_y = y;
target_z = z;

// calculate difference between actual position and target position
static signed long int diff_x;
static signed long int diff_y;
static signed long int diff_z;

static double diff_abs;

diff_x = target_x - position_x;
diff_y = target_y - position_y;
diff_z = target_z - position_z;

// determine directions and set them
if (diff_x < 0) {
	ccw_x();
}
else {
	cw_x();
}

if (diff_y < 0) {
	ccw_y();
}
else {
	cw_y();
}

if (diff_z < 0) {
	ccw_z();
}
else {
	cw_z();
}

// calculate absolute difference between the 2 points
diff_abs = sqrt(diff_x * diff_x + diff_y * diff_y + diff_z * diff_z);

// calculate the speeds for each axis
set_frequency_x(absolute_speed / diff_abs * diff_x);
set_frequency_y(absolute_speed / diff_abs * diff_y);
set_frequency_z(absolute_speed / diff_abs * diff_z);

// calculate movement time
double time = diff_abs * pl / absolute_speed;

// and set the time
set_duration(time);
}

 

i have little problems with the sqrt ... it returns wrong values when the inner value gets too big ...

 

i will modify the code a bit more - the time-driven motion makes trouble when hitting the endpoints - sometimes steps get lost ... so i will change it to an event-driven "endpoint-detection"

Link to post
Share on other sites

You should do this calculation on the PC using double floating point. That will fix the overflow and precision problems.

 

The time based motion should move all the axis very close to the desired target stop position if the frequency and time calculations are all correct. The endpoint determined by the MCU should be used as the next start point by the PC to keep cumulative error under control. The advantage of a time based limit is that it keeps the ISR fast and the code simple (one time limit check instead of 3 position limit check).

Link to post
Share on other sites

You need to use endpoint ramps into stepper controll algoritmus (smooth change stepping frequency up / down at the begin / end of line to controll acceleration).

 

And high resolution timers help you use higher levels of accuracy - using microstepping. You will be able using for example 30000 microsteps instead of 3000 full steps and get 10 x better accuracy.

Link to post
Share on other sites
You should do this calculation on the PC using double floating point. That will fix the overflow and precision problems.

 

The time based motion should move all the axis very close to the desired target stop position if the frequency and time calculations are all correct. The endpoint determined by the MCU should be used as the next start point by the PC to keep cumulative error under control. The advantage of a time based limit is that it keeps the ISR fast and the code simple (one time limit check instead of 3 position limit check).

 

thats right ... it moves nearly perfect ... +/- 1 step positioning - error ;) but the small error accumulates to a bigger one with the time

 

i already modified it a bit more - not using the overall speed - instead it moves one axis at its maximum speed - and the others synchronized to it

 

void set_Position_MaximumSpeed(unsigned long int x, unsigned long int y, unsigned long int z, unsigned long int maximum_speed) {
// set new target positions
target_x = x;
target_y = y;
target_z = z;

// calculate difference between actual position and target position
static signed long int diff_x;
static signed long int diff_y;
static signed long int diff_z;

static double diff_max;

diff_x = target_x - position_x;
diff_y = target_y - position_y;
diff_z = target_z - position_z;

// determine directions and set them
if (diff_x < 0) {
	ccw_x();
}
else {
	cw_x();
}

if (diff_y < 0) {
	ccw_y();
}
else {
	cw_y();
}

if (diff_z < 0) {
	ccw_z();
}
else {
	cw_z();
}

/////

if (diff_x > diff_y) {
	if (diff_x > diff_z) {
		diff_max = diff_x;
	}
	else {
		diff_max = diff_z;
	}
}
else {
	if (diff_y > diff_z) {
		diff_max = diff_y;
	}
	else {
		diff_max = diff_z;
	}
}

// calculate the speeds for each axis
set_frequency_x(maximum_speed / diff_max * diff_x);
set_frequency_y(maximum_speed / diff_max * diff_y);
set_frequency_z(maximum_speed / diff_max * diff_z);

// calculate movement time
double time = diff_max * pl / maximum_speed;

// and set the time
set_duration(time);

// set flag
WORKING = 1;
}

 

you are right - i also can correct this error after the movement is complete (automatically correct an displacement)

 

the control i built up does not support microstepping ;) only full- and halfstep ... but really ... do i need this theoretical precision? not really ... the mechanical part will have "big" tolerances - so it makes no sense to use microstepping ;)

 

actually i dont need ramps - because it was only software evaluation - done with the debugger ... the ramps will be calculated on the PC later ;)

 

edit: its just a small demo without interfacing the PC at the moment ... i just do some trial & error - experiments now ;)

 

	/***
	DEMO
***/

set_Position_AbsoluteSpeed(2500, 5000, 10000, 25000000);
while(WORKING);

set_Position_MaximumSpeed(5000, 10000, 20000, 25000000);
while(WORKING);

set_Position_AbsoluteSpeed(10000, 15000, 30000, 25000000);
while(WORKING);

Link to post
Share on other sites

Microstepping is good solution for remove "jagged lines" - it add smoothness to steppers movement.

 

My suggestion of "almost ideal" stepper controller:

 

- Use something from MSP430F53XX or MSP430F55XX series (this serie give you advantage of USB communication)

- Use 3 timers A to independent and precise frequence generating for 3 axes

- Use timer B with 7 registers for synchronously generating PWM signals for microstepping controll 3 axes (two signals for axis...)

- Use 3 DMA channels directed by timers A to move modified sinus tables into timer B registers to precise timed, software - independent stepper movement

- Then You have full potential of processor power for interpolation computing (hardware multiplier help you a lot)

 

- Price of F53XX or 55XX series is

Link to post
Share on other sites

As i already said - this will be a very small DIY - cnc ... the frame and mechanics will be everything but stiff - and the needed accuracy will be lower than 0.01 mm ...

 

microstepping has good advantages ... smoother stepping, less noise ... but it has 2 main disadvantages ... 1. you need better (or lets say: more complex) control-unit .... and you need more power to compensate the losses on torque caused by the microstepping - this leading to bigger steppermotors - and as a conclusion - a higher price .... i just want to built a lowcost ;)

 

inbuilt usb sounds great - but i dont need it for this project - with simple uart i can control the device with every terminal ... when using usb you will need to write your own software and/or driver

 

oPossums code works fine up to frequencies of about 90 kHz with a resolution of 0.0001 Hz ... assuming a normal stepper motor with 200 steps this makes 450 revs / second !

 

fullstep: 450 revs

halfstep: 225 revs

1/4-steps: 112 revs

1/8-steps: 56 revs

1/16-steps: 28 revs

1/32-steps: 14 revs per second!

 

14 revs * 60 seconds = 840 rpm

800 rpm * 5 mm thread (circulating-ball spindle - do oyu call it like this? :shifty: ) = 4200 mm / minute ... this is more than most consumer-cnc-mills can do - and this on 1/32-steps - i only saw this configuration once in m lifetime - on a siemens-machine!

 

so my question again: do you really need it? in my opinion more than 100 kHz output is just overkill! it gives you a theoretical precision - but in practce the mechanical part cant handle this ;)

 

OK ... enough of this - you showed some other benefits of the F3XXX ... synchronizing the 3 axis is just fine - but i can do this with synchronizing the SYNC-input of the L297 - and i dont need extra shift-registers :) - i dont know about other stepper-controls ... but maybe you need it for them

 

i am using the PC to do all the calculations - so i dont really need hardware-multiplier .... when doing this on the MCU - you are right - then it will make a lot of things easier ;)

 

i think smd shouldn't be a too big problem ... but i prefer DIL for hobby-only applications

 

---

 

so far - i like the discussion and it shows what possibilities are left unused here - but for this project it would be overkill

 

for bigger projects i think i would not use stepper motors ... i would use servo-motors and incremental positioning-systems (like etched glass-scales) to move the axes to the desired positions

Link to post
Share on other sites
  • 1 year later...

Hi to everyone,

 

                  I am new to this blog. I recently started working on stepper motor, I have to design a 5 axial stepper motor ( control 5 stepper motors).

     

                  I am thinking to use Texas instruments microcontroller and motor driver and I have to drive a single phase bipolar stepper motor with current rating of 3 amps. can anyone suggest me with  microcontroller and motor driver that suits my requirement and if any one have reference design please send to e-mail - satya1312@gmail.com or post in this blog 

 

Thank you

 

Regards

 

Satya

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...