Skip to content

Customizing the HAL file

Paciente8159 edited this page Apr 17, 2023 · 9 revisions

# SOME FUNCTIONALITIES ARE STILL IN CONSTRUCTION AND SHOULD NOT BE USED AS REFERENCE

# VERSION 1.4 CARRIES SEVERAL MODIFICATIONS THAT CHANGED THE WAY MODULES ARE CONFIGURED AND THIS PAGE HAS NOT BEEN FULLY UPDATED

Jump to section

HAL Configurations

Most µCNC HAL configurations can be customized via the Web Config Tool and it's the easiest way to go. Most (not all features) can be customized via this tool. If you can't find it in the web UI please refer to the source code files to perform the needed changes (mainly cnc_config.h and cnc_hal_config.h).

Dual drive axis (self-squaring)

µCNC supports up to 2 simultaneous dual drive axis. This allows to enable self squaring with machine homming if the kinematics allows it (like in cartesian machines). As stated up to 2 axis can be enabled with this feature. This is set by enabling the following settings in cnc_hal_config.h

//this allows dual axis mode on axis X for example
#define ENABLE_DUAL_DRIVE_AXIS
#ifdef ENABLE_DUAL_DRIVE_AXIS
// defines the first dual drive capable axis
#define DUAL_DRIVE0_AXIS X
// by default this will be rewired to STEPPER6 (if available on the board)
// this can be uncommented to re-wire to an available (unused stepper other then 6)
#define DUAL_DRIVE0_STEPPER 3

// defines the first second drive capable axis
// #define DUAL_DRIVE1_AXIS Y
// by default this will be rewired to STEPPER7 (if available on the board)
// this can be uncommented to re-wire to an available (unused stepper other then 7)
// #define DUAL_DRIVE1_STEPPER 7
#endif

For each dual drive axis the respective STEPPER pins must be configured. (STEPPER6 -> AXIS0 and STEPPER7 -> AXIS1 are the default). This must be set on each individual boardmap file.

For homing purposes the second axis limit switch (if not already defined in the boardmap) needs to be configured too. For example with dual drive X you may need to configure the X2 limit switch pinout.

M1 conditional program stop

By default M1 will behave like M0. But it is possible to define condition for the program stopping like defined in the RS274NGC standard. This condition can be any thing that evaluates to a true or false condition. It can be the state of an input or output, a threshold of an analog input, or any internal condition. This will make M1 pause if the condition is meet. Here are a couple of examples by adding a line to cnc_hal_config.h:

//pauses the program if an M1 command is given and input DIN11 is high
#define M1_CONDITION_ASSERT (io_get_pinvalue(DIN11)!=0)

or

//pauses the program if an M1 command is given and output DOUT5 is low
#define M1_CONDITION_ASSERT (io_get_pinvalue(DOUT5)==0)

or

//pauses the program if an M1 command is given and analog input ANALOG0 is above 65
#define M1_CONDITION_ASSERT (io_get_pinvalue(ANALOG0)>65)

µCNC Encoder module

The encoder module is the simplest of the available modules. It can work as an directional encoder or a simple counter. It supports up two 8 encoders/counters. Each encoder is defined by PULSE pin and a DIR pin.

Preparing your board

First you must make sure you have available pins on your board and they are configured properly. For each encoder you will need at least an ISR capable DIN pin (PIN0-7) and a directional PIN (preferably a non ISR pin line DIN8-15) if the encoder needs to work has a directional encoder. Go to your board file and map the pins you need. To configure your boardmap file read the customization page page. Depending on your board/MCU specific definitions may be needed.

Modify cnc_hal_config.h

To define 1 encoder open cnc_hal_config.h first set the number of encoders to 1.

#define ENCODERS 1

This will enable ENC0. If you set ENCODERS to 2 you will enable ENC0 and ENC1, and so on. Next you need to set the PULSE and DIR pins by connecting them to a pair of DIN pins in the HAL.

Note: PULSE pin should be connected to a ISR capable DIN(0-7) pin and the ISR must be active for that pin

Note2: DIR pin should be connected to a non ISR capable DIN(8-16) pin

Note3: Both pins must be defined in the respective boardmap for your board file

Let's say you defined and ISR input pin with the name DIN7 and a non ISR input pin DIN 10. To assign them to them to encoder 0 insert the following lines

#define ENC0_PULSE DIN7
#define ENC0_DIR DIN10

That's it. Every time PULSE pin rises from low-high it will trigger the ISR and count up or down depending on the input value of the DIR pin. If this encoder keeping track of the STEPx motors that move the machine there is only one configuration to add. That is to link the encoder to the respective STEPx. Let's say ENC0 (encoder 0) keeps track of STEP1 position. Then add this line:

#define STEP1_ENCODER ENC0

This is needed so that the correspondent encoder is also reset along with the interpolator variable (for example during homing motions).

If you only need a direction independent counter you just need the ISR capable pin. You can assign both PULSE and DIR pins to the same board pin like this.

#define ENC0_PULSE DIN7
#define ENC0_DIR DIN7

This will make use of the encoder to count always in the same direction.

µCNC PID module

UNDER DEVELOPMENT

The PID module works by setting a definition for the DELTA (difference error between the expected value and the current value of the given PID system), the OUTPUT code to execute that receives a value (9bit- -255 to 255) to adjust the respective the system output and the STOP code that is executed if any failsafe detection triggers the machine to stop.

It supports up two 7 (of 8) PID controllers. When enabling PID controllers PID0 is always hardwired to the current tool PID callback. Each PID runs every log2(Total number of PID controllers)/1000 milliseconds PID_SAMP_FREQ. Lower sampling frequencies can be defined also with a FREQ_DIV definition for each PID controller that can range from 1 (default value) to PID_SAMP_FREQ milliseconds (that is the same as a sample rate of 1Hz).

Both PID OUTPUT, STOP and DELTA can be defined has a variable or function depending on the needs.

Preparing your board

First you must make sure you have available pins on your board and they are configured properly for your setup (PWM, ANALOG, INPUTS, or even other modules like the encoder module).

Modify cnc_hal_config.h

To define 1 PID controller open cnc_hal_config.h first set the number of PID controllers to 1.

#define PID_CONTROLLERS 1

This will enable PID0. Remember PID0 is hardwired to the tool PID callback. If you set PID_CONTROLLERS to 2 you will enable PID0 and PID1, and so on. To effectively use additional PID controllers a PID_CONTROLLERS with a value of 2 or more must be set. This will also enable Kp, Kd and Ki settings. For PID0 they will be available via commands $200, $201 and $202. For ENC1 $210, $211 and $212, and so on. Next you need to set the DELTA, OUTPUT and STOP to each PID controller in the HAL.

Let's look at some examples:

Example 1: A spindle PWM output (PWM0) with a closed loop feedback read from and ANALOG input (ANALOG0)

//compares the read spindle value to the programmed value
#define PID1_DELTA (io_get_analog(0) - itp_get_rt_spindle_pwm())

//readjusts the output value of the PWM with the PID adjust value (limited between 0 a 255)
#define PID1_OUTPUT(X) (io_set_pwm(PWM0, CLAMP(io_get_pwm(PWM0) + X, 0, 255));

//stops the spindle
#define PID1_STOP() (io_set_pwm(PWM0, 0));

//if not defined PID0_FREQ_DIV will be defined as 1 by default
//this will make the PID run every 5/PID_SAMP_FREQ seconds
#define PID1_FREQ_DIV 5

Example 2: A spindle PWM output (PWM0) with a closed loop feedback read from and encoder counter (ENC0)

//compares the read spindle rpm detected with ENC0 to the programmed value
//this the way to define a multiline macro (like a block of code)
#define PID1_DELTA ({ \
    /* get's de encoder count absolute value and multiplies by 125Hz to convert to RPM*/ \
    float rpm = (float)ABS(encoder_get_pos(0) * PID_SAMP_FREQ); \
    /* resets the ENC0*/ \
    encoder_reset_pos(0); \
    /* returns the error between the actual RPM and the programmed RPM*/ \
    (rpm - itp_get_rt_spindle()); \
})

//readjusts the output value of the PWM with the PID adjust value (limited between 0 a 255)
#define PID1_OUTPUT(X) (io_set_pwm(PWM0, CLAMP(io_get_pwm(PWM0) + X, 0, 255));

//stops the spindle
#define PID1_STOP() (io_set_pwm(PWM0, 0));

Example 3: STEP0 is not a stepper but a servo motor with encoder. The motor is controlled by 2 PWM (PWM0-foward and PWM1-backward) and a closed loop feedback read from and encoder position (ENC0) sampling @ 125Hz.

//compares the actual servo position with STEP0 position from the interpolator
#define PID1_DELTA (encoder_get_pos(0) - itp_get_rt_position_index(0))

//readjusts the output value of the servo motor
//this is the way to define a multiline macro
#define PID1_OUTPUT(X) ({\
    if(X > 0) {io_set_pwm(PWM0, (uint8_t)X);io_set_pwm(PWM1, 0);/*moves forward*/} \
    else if(X < 0) {io_set_pwm(PWM0, 0);io_set_pwm(PWM1, ((uint8_t)-X));/*moves backward*/} \
    else {io_set_pwm(PWM0, 0);io_set_pwm(PWM1, 0);/*breaks*/} \
});

//stops the spindle
#define PID1_STOP() ({io_set_output(DOUT0, false);io_set_pwm(PWM0, 0);/*breaks*/});

Example 4: STEP0 is not a stepper but a servo motor with encoder. The motor is controlled by 1 PWM (PWM0) a DIR (DOUT0) and a closed loop feedback read from and encoder position (ENC0).

//compares the actual servo position with STEP0 position from the interpolator
#define PID2_DELTA (encoder_get_pos(0) - itp_get_rt_position_index(0))

//readjusts the output value of the servo motor
//this is the way to define a multiline macro
#define PID2_OUTPUT(X) ({\
    if(X > 0) {io_set_output(DOUT0, false); io_set_pwm(PWM0, (uint8_t)X);/*moves forward*/} \
    else if(X < 0) {io_set_output(DOUT0, true);io_set_pwm(PWM0, (uint8_t)(255-X));/*moves backward*/} \
    else {io_set_output(DOUT0, false);io_set_pwm(PWM0, 0);/*breaks*/} \
});

//stops the spindle
#define PID1_STOP() ({io_set_output(DOUT0, false);io_set_pwm(PWM0, 0);/*breaks*/});