Understanding the HAL - Paciente8159/uCNC Wiki

Jump to section

µCNC HAL (Hardware Abstraction Layer)

µCNC has two HAL. The first is the microcontroller HAL. It provides the abstraction layer needed to use all the core functionalities in any microcontroller/PC board. The second one is the kinematics HAL that translates how the machine converts linear actuators/steps in to cartesian space coordinates and the mechanical motions of the machines. In this page we will be looking at the different possibilities and configurations for both HAL's.

The microcontroller HAL

This HAL is actually composed of two parts. The MCU and the board/kit.

The way to implement/code this completely free. The only thing µCNC needs to know is that when it want's to set the step pin of motor 0 high it has to call: mcu_set_output(STEP0);

Pin naming conventions

µCNC sets a list of names that are used by the core functions to tell the microcontroller what to do. These are the fixed names used internally:

Output pins - special

Input pins - special

COM pins - special

Output pins - generic

Input pins - generic

Creating the HAL for a custom MCU

Before creating a custom HAL for a custom board/microcontroller the microcontroller must have the following hardware features available:

After this 4 steps are needed:

1. Implement all functions defined in the mcu.h

All functions defined by the muc.h must be implemented. These are:

//gets the value of the input pin. Low (GND) returns 0 and high (VDD) returns any value other than 0. This function can be declared has a macro
uint8_t mcu_get_input(uint8_t pin);
//gets the value of the output pin. Low (GND) returns 0 and high (VDD) returns any value other than 0. This function can be declared has a macro
uint8_t mcu_get_output(uint8_t pin);
//sets the output pin (VDD). This function can be declared has a macro
void mcu_set_output(uint8_t pin);
//sets the output pin low (GND). This function can be declared has a macro
void mcu_clear_output(uint8_t pin);
//toggles the output pin value (low or high). This function can be declared has a macro
void mcu_toggle_output(uint8_t pin);
//runs all needed initializations. Configures inputs/outputs, pullups, interrupts, com port, etc...
void mcu_init(void);
//enables probe interrupt on change if available. This function can be declared has a macro
void mcu_enable_probe_isr(void);
//disables probe interrupt on change if available. This function can be declared has a macro
void mcu_disable_probe_isr(void);
//gets the analog value of an analog input pin. Returns a value from 0 to 255 (usually from GND to VDD, but depends on board config and initialization). This function can be declared has a macro
uint8_t mcu_get_analog(uint8_t channel);
//sets the pwm duty cycle of a pwm output pin (VDD). This function can be declared has a macro
void mcu_set_pwm(uint8_t pwm /*PWMx*/, uint8_t value);
//gets the pwm duty cycle of a pwm output pin (VDD). This function can be declared has a macro
uint8_t mcu_get_pwm(uint8_t pwm/*PWMx*/);
//indicates if the MCU is ready to send the next char over the COM port. 
void mcu_tx_ready(void);
//indicates if the MCU has a char in the COM port ready to be read. 
void mcu_rx_ready(void);
//sends a char to the communication port. This function can be declared has a macro
void mcu_putc(char c);
//reads a char from the communication port. This function can be declared has a macro
char mcu_getc(void);
//enables global interrupts. This function can be declared has a macro
void mcu_enable_interrupts(void);
//disables global interrupts. This function can be declared has a macro
void mcu_disable_interrupts(void);
//converts steps/s to a clock and prescaller value to be used to modify the timer
void mcu_freq_to_clocks(float frequency, uint16_t* ticks, uint8_t* prescaller);
//starts the timer interrupt at a given frequency
void mcu_start_itp_isr(uint16_t ticks, uint8_t prescaller);
//modifies the timer interrupt at a given frequency
void mcu_change_itp_isr(uint16_t ticks, uint8_t prescaller);
//stops the timer interrupt
void mcu_stop_itp_isr(void);
//gets the MCU running time in milliseconds.
uint32_t mcu_millis();
//runs all internal tasks of the MCU.
//for the moment these are:
// - if USB is enabled and MCU uses tinyUSB framework run tinyUSB tud_task
// - if ENABLE_SYNC_RX is enabled check if there are any chars in the rx transmitter (or the tinyUSB buffer) and read them to the serial_rx_isr
// - if ENABLE_SYNC_TX is enabled check if serial_tx_empty is false and run serial_tx_isr
void mcu_dotasks(void);
//reads a byte from the non volatile memory at a given address
uint8_t mcu_eeprom_getc(uint16_t address);
//writes a byte to the non volatile memory at a given address
void mcu_eeprom_putc(uint16_t address, uint8_t value);

Internally the implementation of the MCU must: - use a interrupt timer to call itp_step_isr() and itp_step_reset_isr() alternately (evenly spaced) - use a 1ms interrupt timer or RTC to generate the running time and call pid_update_isr() - if a hardware USART/UART is used for communications, a RX interrupt that calls serial_rx_isr(unsigned char c) with the received char - if a hardware USART/UART and async TX is used, an interrupt on TX empty that calls serial_tx_isr() - if interruptible inputs are used they appropriately call io_limits_isr(), io_controls_isr(), io_probe_isr() and encoders_isr()

2. Map all µCNC internal pin names to I/O pins

The HAL must know the I/O pin to modify when the core want's to modify STEP0 pin for example. Again...µCNC doesn't care how it's done as long has it does what it is asked...If the switch is flicked on the bulb should turn on... simple.

3. Add the new board and mcu libraries to µCNC

4. Create the project and build From this point on you just need to create a project to run the program. This can be either a main file and a makefile and build, or used an IDE to create the project. Then on main just call the two functions needed to run µCNC. A bare minimum main file should look like this

#include "cnc.h"

void main(void)
{
    //initializes all systems
    cnc_init();

    for(;;)
    {
        cnc_run();
    }

}

The kinematics HAL

This HAL is manages the way the linear actuators and the 3D Cartesian space axis relate to each other.

Creating the HAL for a custom kinematics

2 steps are needed:

1. Implement all functions defined in the kinematics.h

All functions defined by the kinematics.h must be implemented. These are:

/*
	Converts from machine absolute coordinates to step position.
	This is done after computing position relative to the active coordinate system
*/
void kinematics_apply_inverse(float *axis, uint32_t *steps);
/*
	Converts from step position to machine absolute coordinates
	This is done after computing position relative to the active coordinate system
*/
void kinematics_apply_forward(uint32_t *steps, float *axis);
/*
	Executes the homing motion for the machine
	The homing motion for each axis is defined in the motion control
	In the kinematics home function the axis order of the homing motion and other custom motions can be defined
*/
uint8_t kinematics_home(void);
// this is currently deprecated and may be removed in next versions
/*
	In dual drive machines this translates which drive is locked when a particular limit switch is triggered during homing motion
*/
void kinematics_lock_step(uint8_t limits_mask);
/*
	Applies a transformation to the position sent to planner.
	This is applied only on normal and jog moves. Homing motions go directly to planner.
*/
void kinematics_apply_transform(float *axis);
/*
	Applies a reverse transformation to the position returned from the planner.
	This is applied only on normal and jog moves. Homing motions go directly to planner.
*/
void kinematics_apply_reverse_transform(float *axis);

2. Add the new kinematic library to µCNC

Now just edit the config file to specify the kinemtics file you want to use and recompile µCNC for your board.

The new HAL config file

This new HAL config file that is introduced in version 1.2.0 is manages the way the generic (and in some particular cases the special pins too) connect to the desired functions or modules. For example:

This is still the first version of this new HAL configuration and new modules may come in the feature to expand the flexibility of µCNC.