Skip to content
adichell edited this page Feb 20, 2018 · 6 revisions

This is a port of GRBL code to 32-bit microcontrollers supported by libopencm3.

Status

The first stable port has been achieved with a NucleoF401 board running at 48 MHz (at the moment), using GRBL version 0.9 latest available build.
While some successful tests have been executed, there is still need to test it in all the functionality.

Technical issues and resolution

In order to achieve the same functionality of GRBL on Arduino, some issues had to be solved. In the following paragraphs the main issues and the solution are presented, in order to clarify the status and a bit of the way the code works.

Non-volatile memory

A fundamental difference between the two boards is the type on Non-Volatile memory used. While Arduino uses EEPROM, the NUCLEOF401 uses a FLASH memory.
The Non-Volatile memory is used to store both the application code/data and various settings or parameters (let's call all of them "settings" for now).
This is done also in the FLASH of this board, but different sectors are used, since the settings may need to be changed, while the code is stored as it is for a fixed build.
The flash memory of this board can only be written by clearing the bits to zero, while to set a one the whole sector needs to be erased, i.e. all bits are set to one at the same time.
To achieve the re-writing of values that change the bits from zero to one, two flash sectors and a sort of finite state machine have been used.
Another side effect of using the flash is that if a read operation is performed on the flash while a write or an erase operation is performed, the processor gets stalled. This poses a problem, since the GRBL application needs to get real time commands (like a reset commanded by the user) without loosing any of them.
Since the code is stored into the flash, a write or an erase operation would definitively stall the processor when the code is fetched from the flash. So, in order to avoid this, critical part of the code is copied in RAM at the startup of the application, and then fecthed from there by the processor. This solves this issue, or so it seems.

Interrupt lines and muxing

The GRBL application uses some input IOs with interrupts associated to edge of the change of state of the logic value.
A well defined number of external interrupts lines (EXTI) are present in the microcontroller, 16 in the case of the STM32F401xE, while there are much more IOs, divided in ports (port A, port B, etc.) of 16 bits each.
So a muxing scheme is necessary to interface IOs and EXTI lines, and in the case of STM32F401xE the bits 0 of each IO port are muxed in the same EXTI0 line, the bits 1 of each IO port are muxed in EXTI1 line, and so on.
The effect is that just one bit n can be used for EXTIn, where n goes from 0 to 15. As an example, PC0 and PB0 pins cannot be used at the same time as external interrupt pins. For the porting this may not seem a big problem, but since the effort was to use the same pinout of the existing GRBL, using the arduino connectors, with the evident advantage of being able to reuse existing motor driving shields without any re-connection.
The muxing and the arrangement of the IOs made this impossible, but as few pins as possible are to be used outside of the arduino connectors.

Pinout

The effort when choosing the pinout to be used was to get as near as possible to the arduino pinout used in GRBL, in order to be able to re-use existing and cheap shields with as few reconnection as possible.
Still, it is possible to change the pinout by acting on the cpu map file, but taking special care to the input pins that use interrupts. For more information about these read the "Technical issues and resolution" paragraph.

The following image shows the chosen pin disposition on Nucleo F401 arduino connectors.

Inputs:

PC_7 <--> limit x
PB_6 <--> limit y
PB_0 <--> limit z

PB_2 <--> reset
PA_1 <--> feed hold
PA_4 <--> cycle start/resume
PC_0 <--> probe
PC_3 <--> safety door

Outputs:

PA_10 <--> step x
PB_3 <--> step y
PB_5 <--> step z

PB_4 <--> direction x
PB_10 <--> direction y
Pa_8 <--> direction z

PA_9 <--> stepper enable

PA_6 <--> spindle enable/pwm
PA_5 <--> spindle direction

PC_1 <--> coolant_flood
PC_2 <--> coolant_mist