This is a LinuxCNC component and firmware that uses the SPI bus on a Raspberry Pi to communicate with a STM32 microcontroller as a programmable realtime unit, for motor control, digital I/O, spindle PWM etc.
This project was inspired by and uses some code from the 'Remora' system https://github.com/scottalford75/Remora
The firmware for the realtime unit targets STM32F103C8 aka 'Blue Pill'. Source code includes a project file for STM32CubeIDE.
Unlike Remora, this firmware is not conveniently configurable by SD card, so all modifications will need to be changed in the source code.
Tested on Raspberry Pi 3B and ZeroW with 4.19.71 PREEMPT, LinuxCNC 2.8.4
- 4 axis stepper motor control at up to 50kHz step rate
- 4 μs step pulse by default
- 10kHz spindle PWM frequency
- 14 digital I/O (allocate these to input and output as desired)
- two analog inputs for joystick jogging
- one rotary encoder (slow for manual jogging etc, not for closed loop motor control!)
- WS2812 style RGB LED strip (up to 16) controllable from HAL
The default step pulse length (the time the pin is held high) is set to 4 microseconds. You can change this in the call to __HAL_TIM_SET_COMPARE in stepgen.c if your stepper drivers require a longer pulse. Keep in mind that at 50kHz there is only 20 microseconds available for a full pulse cycle.
The analog inputs are intended for use as a joystick for jogging two axes. To use this correctly, the joystick should not be moved for 10 seconds on startup, to calibrate the center position value. There is a sizeable deadband enforced so that small jitters around the center position do not cause joint movement, but it would still be wise to use a switch to only enable joystick jogging when actually intended.
Pin PC13 is used to indicate that SPI connection to Raspberry Pi is established. This LED should light up when you remove e-stop, and remain lit while SPI connection is active.
The WS2812 protocol is used to control up to 16 addressable RGB LEDs on PB5. Although these are not officially supposed to work with 3.3V signals, in my experience many variants do actually work just fine. You can control the individual red/green/blue components of each LED (simply on or off, no gradual dimming) via HAL pins. Note that when SPI connection is lost, all RGB LEDs will also turn off.
The STM32F103C8 seems to struggle with this workload when running a debug build, and you may find the SPI connection occasionally dropping. With a release build though, I've had it running fine for 3 weeks at a time without any loss of communication.
To install the LinuxCNC component, invoke halcompile from the components/weeny folder like this:
sudo halcompile --install weeny.c
Note that even though the default firmware only has a total of 14 pins for digital I/O, there are 16 digital pins each for input and output in the HAL settings. This is mainly because the messaging between Raspberry Pi and the PRU uses uint16 types to hold these values. In future the extra 2 bits might be useful if for example, two more digital I/O were needed instead of a rotary encoder.
Returns the value of digital inputs (as assigned in tasks.c)
Sets the value of digital outputs (as assigned in tasks.c)
Returns the raw (floating point 0-1) value on PB0/PB1
Returns a value that will be incremented or decremented by moving the analog input on PB0/PB1 away from center. The speed of change will be faster when further from center.
Returns a value that will be incremented or decremented by moving a rotary encoder on PC14/PC15
Sets the duty cycle of the PWM pulse on PA8. This takes a value from 0-65535, where 65535 will result in an always-high pulse.
Sets the red/green/blue component to on or off in the RGB LED of the given index.
The default layout shares the 14 digital I/O equally between input and output. You can assign the digital pins in some other arrangement by editing tasks.c (move pins between the digitalIns and digitalOuts arrays).
PB15 | MOSI |
PB14 | MISO |
PB13 | CLK |
PB12 | NSS |
PC13 | Connection LED (lights when pulled low) |
PA0 | Dir 1 |
PA1 | Dir 2 |
PA2 | Dir 3 |
PA3 | Dir 4 |
PA4 | Step 1 |
PA5 | Step 2 |
PA6 | Step 3 |
PA7 | Step 4 |
PB2 | D1 |
PB10 | D2 |
PB11 | D3 |
PA11 | D4 |
PA9 | D5 |
PA10 | D6 |
PA12 | D7 |
PA8 | PWM |
PA15 | D8 |
PB3 | D9 |
PB4 | D10 |
PB6 | D11 |
PB7 | D12 |
PB8 | D13 |
PB9 | D14 |
PB0 | Analog 1 |
PB1 | Analog 2 |
PC14 | Data |
PC15 | Clock |
PB5 | WS2812 style LED strip |