FezCNC

Which board/chip?

If you include the correct header then you dont have to worry about addresses, you just use the correct name, which you can also look up in the header file…

The Fez Rhino. This would be the LCP2388 chip

Edit: I also saw the sample code on RLP Interrupts (http://www.tinyclr.com/codeshare/entry/366/) so I know it’s possible but how do you take an interrupt from a timer?

You can check my codeshare submission here: http://www.tinyclr.com/codeshare/entry/366

It’s developed for EMX but things should almost be the same. I even see it includes the “LPC23xx.h”, so you’re all set :slight_smile:

What do you want to do exaclty? TimerIsr will be called at the rhythm of TIMER3 in the example.

Oh I didn’t notice that you were using a timer in that code:

RLPext->Interrupt.Install(TIMER3_INT, TimerIsr, NULL)

I am creating a RLP that will run the step clocks for the 3 axis of the CNC. I need sub millisecond timing.

That’ll be no problem, just modify the prescaler T3PR and/or value in matchregister T3MR0, see calculation in comment and LPC datasheet for a better insight on how the timers work.

Hurray! Well I solved my issue with the Z axis not moving properly: I upgraded from 12V @ 2A, to 16V @ 4A. I replaced the power brick I had with an adapter used for recharging rechargeable batteries.

Now all I need is to figure out the spindle’s issue.

Whohoo… and now I solved my power problem with the end mill. All that is left mechanically is to attach the mill to the z axis! After that write the code that turns G-Code into motion.

1 Like

And there we have it. The mill is mounted to the Machine and everything moves and has power to move. Next is a test cutting program.

1 Like

Congratulations!!! That was a long road. Can’t wait to see it cutting first something! :clap:

Ack… I’ve encountered a show stopper bug.

I have a Relay module (Fez Relay) that I’m using. Whenever I connect it and activate it ( myRelay.Write(true)) then I try to set one of the PWM pins (doesn’t matter which one); the device (Fez Rhino) restarts.

Has anyone had a problem where the device restarts if you use the PWM and a Fez Relay at the same time? I’m using the relay to play sound. Could it be that I hooked up the speaker bad and the voltage drop is too much for the device?

Answered my own question. It’s the current draw from the speaker.

How do I connect a speaker to a Fez properly anyways?

Using a transistor.

Right, will do that.

So it seems that I don’t know anything about transistors (no no really), so instead I hooked up my M-Mini speakers to it. Now the sound is amplified a another problem is solved.

New Problem: the Z axis is stalling…

Didn’t you have that problem before? Sounds like a power issue again.

I did, but I would not suddenly have another power issue as I’m using more power and it was working. My friend suggested that it must be a timing issue this time, since the control program changed. Here is the current control program

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.USBHost;

namespace FEZRhino {
    public class Program {
        static OutputPort led;
        static OutputPort millRelay;
        static bool allowMill = false;
        static bool xDirection = true;
        static bool yDirection = true;
        static bool zDirection = true;
        static USBH_Keyboard keyboardController;
        static string currentCommand = string.Empty;
        static string tempCommand = string.Empty;
        static bool isLastCommandProcessed = true;
        static PWM soundPort;
        static int stepMultiplier = 200;

        public static void Main() {
            #region Initilization
            bool _xCurrentDirection = xDirection;
            bool _yCurrentDirection = yDirection;
            bool _zCurrentDirection = zDirection;

            USBHostController.DeviceConnectedEvent += new USBH_DeviceConnectionEventHandler(USBHostController_DeviceConnectedEvent);

            //full step mode
            OutputPort _ms1 = new OutputPort((Cpu.Pin)Rhino.Pin17, false);
            OutputPort _ms2 = new OutputPort((Cpu.Pin)Rhino.Pin15, false);
            OutputPort _ms3 = new OutputPort((Cpu.Pin)Rhino.Pin13, false);

            //reset to high
            OutputPort _reset = new OutputPort((Cpu.Pin)Rhino.Pin29, true);

            //sleep to high
            OutputPort _sleep = new OutputPort((Cpu.Pin)Rhino.Pin31, true);

            //enabe pin
            OutputPort _enable = new OutputPort((Cpu.Pin)Rhino.Pin5, false);

            OutputPort _channelOneStep = new OutputPort((Cpu.Pin)Rhino.Pin7, false);
            OutputPort _channelTwoStep = new OutputPort((Cpu.Pin)Rhino.Pin10, false);
            OutputPort _channelThreeStep = new OutputPort((Cpu.Pin)Rhino.Pin11, false);

            //low = clockwise, high = counterclockwise
            OutputPort _channelOneDirection = new OutputPort((Cpu.Pin)Rhino.Pin3, true);
            OutputPort _channelTwoDirection = new OutputPort((Cpu.Pin)Rhino.Pin20, true);
            OutputPort _channelThreeDirection = new OutputPort((Cpu.Pin)Rhino.Pin22, true);

            AnalogIn _xLimit = new AnalogIn(AnalogIn.Pin.Ain0);
            AnalogIn _yLimit = new AnalogIn(AnalogIn.Pin.Ain1);
            AnalogIn _zLimit = new AnalogIn(AnalogIn.Pin.Ain7);
            _xLimit.SetLinearScale(0, 100);
            _yLimit.SetLinearScale(0, 100);
            _zLimit.SetLinearScale(0, 100);

            bool ledState = false;

            led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, ledState);
            led.Write(true);

            millRelay = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO22, false);

            soundPort = new PWM(PWM.Pin.PWM5); 
            
            int _xLimitLastValue = _xLimit.Read();
            int _yLimitLastValue = _yLimit.Read();
            int _zLimitLastValue = _zLimit.Read();

            double _modulasSync = 0;
            double _xAxisMod = 2;
            double _yAxisMod = 2;
            double _zAxisMod = 2;

            int _xStep = 0;
            int _yStep = 0;
            int _zStep = 0;

            int _xStepsRemaining = 0;
            int _yStepsRemaining = 0;
            int _zStepsRemaining = 0;

            Sound(SoundType.Confirmed);
            #endregion


            while (true) {
                if ((_modulasSync % _xAxisMod) == 0 && _xStepsRemaining > 0) {
                    _xStep = 1;
                }
                if ((_modulasSync % _yAxisMod) == 0 && _yStepsRemaining > 0) {
                    _yStep = 1;
                }
                if ((_modulasSync % _zAxisMod) == 0 && _zStepsRemaining > 0) {
                    _zStep = 1;
                }

                if (_xStep == 1) {
                    _xStep = -1;
                    _xStepsRemaining--;
                    _channelOneStep.Write(true);
                }
                else if (_xStep == -1) {
                    _xStep = 0;
                    _channelOneStep.Write(false);
                }

                if (_yStep == 1) {
                    _yStep = -1;
                    _yStepsRemaining--;
                    _channelTwoStep.Write(true);
                }
                else if (_yStep == -1) {
                    _yStep = 0;
                    _channelTwoStep.Write(false);
                }
                
                if (_zStep == 1) {
                    _zStep = -1;
                    _zStepsRemaining--;
                    _channelThreeStep.Write(true);
                }
                else if (_zStep == -1) {
                    _zStep = 0;
                    _channelThreeStep.Write(false);
                }

                Thread.Sleep(1);

                _xLimitLastValue = _xLimit.Read();
                _yLimitLastValue = _yLimit.Read();
                _zLimitLastValue = _zLimit.Read();

                if (_xLimitLastValue > 50 || _yLimitLastValue > 50 || _zLimitLastValue > 50) {
                    _xStepsRemaining = 0;
                    _yStepsRemaining = 0;
                    _zStepsRemaining = 0;
                    millRelay.Write(false);
                    if (_xLimitLastValue > 50) {
                        Sound(SoundType.LimitX);
                    }
                    else if (_yLimitLastValue > 50) {
                        Sound(SoundType.LimitY);
                    }
                    else if (_zLimitLastValue > 50) {
                        Sound(SoundType.LimitZ);
                    }
                }

                _modulasSync++; //overflowing is fine

                if (!isLastCommandProcessed) {
                    string _lastCommand = currentCommand;
                    try {
                        string[] _commands = _lastCommand.ToUpper().Split(' ');
                        int _xSteps = 0;
                        int _ySteps = 0;
                        int _zSteps = 0;
                        int _multiplier = 0;
                        foreach (string _command in _commands) {
                            string _commandSwitch = _command.Substring(0, 1);
                            if (_commandSwitch == "X") {
                                _xSteps = int.Parse(_command.Substring(1));
                            }
                            else if (_commandSwitch == "Y") {
                                _ySteps = int.Parse(_command.Substring(1));
                            }
                            else if (_commandSwitch == "Z") {
                                _zSteps = int.Parse(_command.Substring(1));
                            }
                            else if (_commandSwitch == "M") {
                                allowMill = int.Parse(_command.Substring(1)) == 1;
                            }
                            else if (_commandSwitch == "P") {
                                _multiplier = int.Parse(_command.Substring(1));
                                if (_multiplier > 0) {
                                    stepMultiplier = _multiplier;
                                }
                            }
                        }
                        _xStepsRemaining = System.Math.Abs(_xSteps * stepMultiplier);
                        _yStepsRemaining = System.Math.Abs(_ySteps * stepMultiplier);
                        _zStepsRemaining = System.Math.Abs(_zSteps * stepMultiplier);
                        _channelOneDirection.Write(_xSteps > 0);
                        _channelTwoDirection.Write(_ySteps > 0);
                        _channelThreeDirection.Write(_zSteps > 0);
                        Sound(SoundType.Confirmed);
                        millRelay.Write(allowMill);
                        isLastCommandProcessed = true;
                    }
                    catch (Exception ex) {
                        Debug.Print(ex.Message);
                        Sound(SoundType.Error);
                        isLastCommandProcessed = true;
                    }
                }
            }
        }

        static void USBHostController_DeviceConnectedEvent(USBH_Device device) {
            if (device.TYPE == USBH_DeviceType.Keyboard) {
                Debug.Print("Keyboard Detected");
                keyboardController = new USBH_Keyboard(device);
                keyboardController.CharUp += new USBH_KeyboardEventHandler(keyboardController_CharUp);
            }
        }


        static void keyboardController_CharUp(USBH_Keyboard sender, USBH_KeyboardEventArgs args) {
            if (args.Key == USBH_Key.Enter || args.Key == USBH_Key.Keypad_Enter) {
                if (tempCommand != string.Empty) {
                    currentCommand = tempCommand.Trim();
                    tempCommand = string.Empty;
                }
                isLastCommandProcessed = false;
                Sound(SoundType.Confirmed);
            }
            else if (args.Key == USBH_Key.Escape) {
                currentCommand = "X0 Y0 Z0 M0";
                isLastCommandProcessed = false;
                Sound(SoundType.Cleared);
            }
            else if (args.KeyAscii != 0) {
                Sound(SoundType.Clicked);
                tempCommand += args.KeyAscii;
            }
        }

        static void Sound(SoundType soundType) {
            float C = 16.35F;
            float D = 18.35F;
            float E = 20.6F;
            float F = 21.83F;
            float G = 24.5F;
            float A = 27.5F;
            float B = 30.87F;
            int _scale = 12;
            int _duration = 250;

            switch (soundType) {
                case SoundType.Clicked:
                    PlayNote(C, _scale, _duration);
                    break;
                case SoundType.Cleared:
                    PlayNote(F, _scale -1, _duration);
                    PlayNote(F, _scale, _duration * 2);
                    break;
                case SoundType.Confirmed:
                    PlayNote(G, _scale, _duration);
                    Thread.Sleep(100);
                    PlayNote(G, _scale, _duration * 2);
                    break;
                case SoundType.Error:
                    PlayNote(B, _scale, _duration);
                    Thread.Sleep(100);
                    PlayNote(B, _scale, _duration);
                    Thread.Sleep(100);
                    PlayNote(B, _scale, _duration * 4);
                    break;
                case SoundType.LimitX:
                    PlayNote(B, _scale, _duration * 4);
                    Thread.Sleep(500);
                    break;
                case SoundType.LimitY:
                    PlayNote(C, _scale, _duration * 4);
                    Thread.Sleep(500);
                    break;
                case SoundType.LimitZ:
                    PlayNote(A, _scale, _duration * 4);
                    Thread.Sleep(500);
                    break;
                default:
                    break;
            }
        }

        private static void PlayNote(float frequency, int scale, int duration) {
            uint _nanoSecond = 1000000000;
            float _hertz = 0;
            _hertz = (float)1 / ((float)frequency * scale);
            try {
                soundPort.SetPulse((uint)(_hertz * _nanoSecond), (uint)((_hertz / 2) * _nanoSecond));
            }
            catch (Exception ex) {
            }
            Thread.Sleep(duration);
            soundPort.Set(false);
        }

    }
    public enum SoundType {
        Clicked,
        Confirmed,
        Cleared,
        Error,
        LimitX,
        LimitY,
        LimitZ
    }
}

And with that, I have solved the last power problem. The hub I’m using to power the fez doesn’t provide enough power. Also the 9V adapter that I’m using to power the fez doesn’t seem to provide enough power either. I think it has something to do with the WizNet module that is on the Rhino’s back. When using usb power the Wiznet does not turn on. When using the 9V power it turns on but the Rhino doesn’t boot up. Solution: use a usb wall adapter.

I’ll try to upload and link the video of the cut in a few hours for all to see. Further the code below is the working code so far. Next stop is reading basic commands from the SD card.

Yea, I would definitely be powering every piece of this project via external power supply.

Are you cutting wood or making music? :wink:

Haha, both. In this case I’m milling plaster of paris as a test on a very soft material