PSoC 5 Port Of the Grbl 1.1 CNC Controller
Grbl
Grbl is a high performance CNC controller. It is used on a lot of small scale CNC machines and is the motion control code behind a lot of 3D printers. It was originally targeted at the Arduino 328p hardware (UNO). It is developed by Sungeun “Sonny” Jeon. He is a good friend. He is always very helpful and this port would not have been possible without the quality of his code and his advice.
PSoC Mixed Signal Controller
I love working with the PSoC (Programmable System on Chip) family of micro controllers. You can configure them on the fly with many analog and digital components. The analog components are not basic ADCs and DACs, you have OpAmps, PGAs, filters, MUXs and more. The digital blocks includes basic logic gates, all the way up to FPGA like components you program yourself in Verilog.. There are over 200 ready to use components you can wire together on the chip.
I have always used them for small prototype projects, but wanted to test my skills by porting a major project like Grbl. At the same time I wanted to take advantage of the features of the PSoC. The dev board I used was the CY8CKIT-059. This has ARM Cortex M3 processor a lot of I/O and costs less than $10! It has a built in programmer and debugger.
PSoC Advantages
Here is a comparison between the the ATMega 328p (Arduino UNO) and the PSOC5
PSoc 5 |
ATMega328p (UNO) |
|
CPU |
32 bit (ARM Cortex M3) |
8 bit |
Speed |
Up to 80MHz |
16MHz Typ. |
Flash (program size) |
256k |
32k |
RAM |
64k |
2k |
EEPROM |
2k |
1k |
I/O |
up to 62 |
14 |
Flexibility
Grbl’s flexibility allows you to tailor it to your hardware. With a few limitations, you can move the pins around and change things like whether switches are active low or high. This is all done using #define values in configuration files. That is great, but the code gets a little messy every time you access hardware. It has to do a little logic gymnastics each time.
With PSoC you can do all of that in a visual schematic and pin wiring feature. Here is a PDF of my schematic. Have you ever swapped transmit and receive on a UART? In PSoC you can just swap the pins on the schematic.
Here is an example of the difference in firmware code.
Grbl on 328p
uint8_t limits_get_state() { uint8_t limit_state = 0; uint8_t pin = (LIMIT_PIN & LIMIT_MASK); if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { pin ^= LIMIT_MASK; } if (pin) { uint8_t idx; for (idx=0; idx<N_AXIS; idx++) { if (pin & get_limit_pin_mask(idx)) { limit_state |= (1 << idx); } } } return(limit_state); }
Grbl on PSoC
uint8_t limits_get_state(){ return Status_Limit_Read(); }
Special Hardware Usage
I used some special features to move functions out of code and onto the hardware. One of them was the step pulse. Stepper drivers typically require a pulse of a minimum length to take a step. In normal hardware you have to raise the pin, then figure out a way to turn it off after a given period of time. This is typically done via an interrupt. It works fine, but the code is messy and interrupts can cause timing issues. PSoC control registers have a pulse feature that automates this. You attach a clock and the clock determines the length of the pulse. The code sets it and the hardware clears it. It looks like this on the schematic.
Another feature I used was hardware switch debouncing. This can be done completely in hardware. See the image below. The clock sets the debounce time. The debouncers are all fed into a status register where they are read as a single value. There are digital “nots” after the debouncers because my switches close to ground. The firmware could invert the logic, but it is so much easier to read on the schematic. It then feeds an interrupt.
If you would rather do this with an analog filter, you can design custom filters in the hardware. You could fine tune the filter right from your keyboard.
LCD
PSoC has a built in character LCD Component that makes using and LCD very easy. The code for the LCD is in the main loop and not an interrupt. This allows the time critical stuff to have higher priority. I used an interrupt to just set a flag so the LCD does not update every time through the main loop. I found the LCD to be an awesome debugging tool. I could display stuff while the code is running.
I also used a hardware Quadrature Decoder for the LCD rotary knob. This works great to monitor the encoder in hardware. I just need to read the value in the LCD update routine. The clock feature on the QuadDec is a debouncer, which helped debounce my mechanical encoder.
Next Steps
I have been testing for a while and so far it is working great. I also have some plans to use the extra power on some cool projects.
Here is the code on GitHub
Here is a picture of my test setup.
nice post.
I haven’t played with the PSoC devices before but has been on my TODO list. This article has just prompted me to order the dev board. Done!
Thanks for sharing the great article and will be following keenly
Stephen, good luck with your project. I plan on posting a few tips and enhancements soon.
[…] recently port Grbl to PSoC. I used (3) 16bit PWM components to control the hobby servos. See this blog post on how I did […]
Hi,
GREAT WORK!!!!!
Have you worked out the maximum step rate you can get out of the PSoC board? I know GRBL was limited to approx. 35,000sps, I’d be very interested to see what you can get.
Keep up the great work – I would love to see your project once you have finished your testing.
Thanks Andrew,
I have not fully tested the speed limits yet. I have spent more time adding features like the LCD and trying some encoders on the motors.
I have tried making the motion planner much deeper. The standard buffer size is about 16 and I have tried over 100 with no issues.
I can look into the stepper speed when I get a chance, but typically the current speed in not an issue for me. I think bigger bottlenecks occur in the communications and other areas. I might look into using DMA and other hardware features to speed up the slower areas of Grbl.
Sonny says the real speed tests are with Laser Engraving, so I might setup a machine for that.
HI bdring,
can i get the Psoc project files , i have the hardware but havent implemented Grbl on that . i want to implement G68 and G69 commands for angular movement. which is not available with Arduino. also to implement this in arduino we dont have enough memory left.
I put this code on GitHub.
Thank you for this!
I’ve been waiting for someone to port GRBL (or for that matter smoothie).
Is it just me, or does this barely even touch the speed/features of this chip?
Thanks,
The chip has a lot of untapped speed and features with this port of Grbl. I am already running 6 axis. I have at actively controlling the motor current and implemented an idle current reduction.
The PSoC 6 is coming soon and will significantly boost the performance with a 150MHz clock, FPU, dual core and Bluetooth.
Hi,
Just find out your project today, it’s very interesting use of PSoC unique capabilities.
As far as i know PSoC6 have less programmable logic (~12 UDBs) so maybe it will be not very easy to port the project to it :/.
Anyway really interesting videos and posts 🙂
Nice and very promissing!
But is there any tutorial for newbies on programming the PSoC? A step-by-step guide?
I can get the devboard locally for ~$15
I have step-dir drivers capable of 512 microstepping
How long would it take me to build the whole setup? Can I do that from a Mac? Do I upload my g-code the usual way via usb?
`There are many tutorials for PSoC. Go to cypress.com to find them. It is easy if you are comfortable with other microcontrollers.
You can use USB, just like Arduino with most senders including Universal GCode sender and Easel.
You must use the PSoc Creator software to program or load firmware. It is free but only runs on Windows operating system.
Hi
I would very much like to own a PSoc grbl controller. I have bought the dev board and was wondering if you had a pin out diagram for hooking it up to stepper motor drivers. I’ll be using TB6600 drivers. Also, I love the LCD feature and neat 3D printed case, is the LCD this one: https://www.itead.cc/display/nextion-nx3224t024.html
Can you supply some details for hooking it up to the PSoc dev board?
Many thanks,
Rob
Hi,
Do you have any kind of TODO list? i would like to contribute to the project, maybe you can add some issues on the github repo and let the people or yourself solve that issues to make this project better.
I read about you are thinking in use DMA in the “slower” parts of grbl, maybe you can extend a little on this?
Carlos
Hello bdring and hello together,
1.) for bdring: a super big thank you for this highly interesting idea to use this PSOC as controller. This project leads for me to grab nearly immediately such one and starting to work with it :-). You are right it simplyfied many things which belongs to the HW implemented. I am just wondering why this PSOC is so unfamiliar. There is also a very good documentation and very friendly developement suite.
2.) for Rob: download the PSOC development suite and load this project into. then you can see in the Pin overview page which pins are where to connect and to hook up. pay attention if you have an optoisolation for the limit switches you need to choose either pull up or pull down as input. It depends from you interface. For the display it self, it just a HD47xx based 4×20 or 4×16 lines. Just a simple one. The datapins are described in the schemata, and example for the resistor look in the datasheet of the lcd inside the PSOC developement suit.
At the moment I branched this very interesting idea and working on it to shift more configuration to the HW,
to avoid that the source needs to be modified
(its always an error source). For example, the limit switches are supplied now with XOR logic gates plus a inverter control register. Same game I do it for the stepper output. Inside the source I will remove the software parts where its done inside there. Additional the limit switches are now single one for each axis (one neg pos and one pos position). Also I want to simplify the GRBL Source and removing some define configs. Because there is a useable AMASS implemented and should be always on for example.
Regarding DMA, well somebody could try to work out a solution to switch between USB and USB UART(over the debug interface). This would allow to snap away the programmer for example.
If am a little more fullfilled the work, will supply the github for the branched one. And I would like to see that this amazing project get grown more. There is too less easy to use and programmable systems for controlling the CNC. (Try tinyG2 with arduino Due – Its for me a horror to work with it, I gave simply up to spend there more time into because this is just far to much complicated designed – just feature blown including a frontend in java)
For the record for sure the GRBL is a masterpiece and I say also a big thank you to Sungeon. I have always a high respect for software developers which can do some magic with limited ressources.
Cheers Folks
DAMIGO
Great comments DDAMIGO,
I am currently looking into directly using the USB without a UART and optionally loading code via bootloader over USB.
Hi bdring,
do you have an email address, so I could send you the first adapted and extended schemata for the PSOC.
Cheers
DAMIGO
bdring,
Absolutely no issues on compiling and downloading to my 059 kit using Creator 4.2, this is a killer application. Thanks.
Craig
BTW: I have the native USB port working now as a CDC Serial Port. That means super high speed (2Mbs) or any lower speed and is compatible with all existing com port grbl software
bdring,
Any chance you can post a link to your branch of the project that has USBUART CDC working? I have a different dev board and have been working for weeks attempting to get the native USB device to play well. Right now I can send all the commands I want via the terminal… but any attempt to use UGS and I get nothing. I assume you’re using a bulk transfer as opposed to isoc? Thanks.
Mike
I am on vacation for about a week. When I return, I will post it. If you check out the USBUART examples in PSoC Creator, I am using a similar transfer method.
Bdring,
I’ve been attempting to get USBUART up and running using the examples from PSoC Creator, and I’ve made some headway, but I’m still not there yet. I’m using a bulk transfer mode, and I’ve configured an interrupt to fire when I receive data over USB As far as I can tell all of that is working well, my issue is with parsing the data into GBRL. I’m not sure if I need to transfer it with GetChar(), or if I need to use GetAll() and read the data into the ring buffer. I’m officially stuck on this one… Any luck on committing the USBUART code, you may be my only hope? Either way this has been a huge learning experience, and serious respect is due to everyone working on this!
In other news I’m working on a project that has stepper motors that require a CW and CCW pulse line, as opposed to pulse and direction. I’m assuming that this is fairly uncommon from what I’ve read, but if any one is suffering from the same issues I have a custom component that I’ve built to solve this. If anyone needs it let me know or I can post a link to the component files on my GitHub page.
Mike
I have not had time to test the USBUART code under heavy load, like a laser job, I will do that next week. If all goes well I will upload the code. Here is my code in the area you are talking about.
/* Read received data and re-enable OUT endpoint. */
count = USBUART_GetAll(buffer);
if (0u != count)
{
/* Send the data to Grbl */
for (int i = 0; i < count; i++) { rx_handler(buffer[i]); } }
Post a link to the data sheet for the stepper motor. I would think PSoCs logic magic could handle it.
I have something a little different, as I attempted to maintain the ring buffer…maybe this is my mistake? I’m assuming that you setup a RX interrupt in software, since it would have been handled by the UART interrupt. You can take a look at my code from the same section you posted.
//was ISR(SERIAL_RX)
void USBUART_RX_ISR()
{
uint16 count;
uint8_t data;
uint8 buffer[64u];
uint8_t next_head;
int i;
count = USBUART_GetAll(buffer);
data = buffer[0];
//get first char of data packet to check for command char
switch (data) {
.
.
.
default: // Write character to buffer if data is present
if (0u != count){
LED_RXTX_Write(1); //debug
for (i = 0; i < count; i++) {
// load char to buffer
serial_rx_buffer[serial_rx_buffer_head] = buffer[i];
serial_rx_buffer_head++; //index ring buffer
}
LED_RXTX_Write(0); //debug
}
}
}
When I say "custom component" it wasn't written in HDL as there was no need. It's just a clever combination of muxes,demuxes, and gates…so 'PSoC magic' 🙂 It's just one easy to use block that keeps the schematic nice and orderly.
I'll look for some links to the data sheets. They were a pain in the *** to find the first time so I have a triple back up of the PDF's and that's what i've been working off of.
I did not see an interrupt associated with the USBUART. Where did you find it? Is it in one of the USBUARTxxx.h files?
For what it is worth. I am not sure optimizing the code there is going to yield any big performance gains. I have tired a few things, but even the most gcode heavy jobs, seem to take about the same time. The planner buffer and software handshaking “ok” seem to control the flow.
In USBUARTxxx.c you cand find the macro that sets the up the interrupt(s) for Tx and Rx. The component initializes the interrupts and interrupt vectors by default. Rx is located on endpoint 2(USBUART_EP2_ISR). The details are loosely written out in the USBUART documentation. But here is the macro for reference:
/* Set Data Endpoint 2 Interrupt. */
#if (USBUART_EP2_ISR_ACTIVE)
CyIntSetPriority (USBUART_EP_2_VECT_NUM,USBUART_EP_2_PRIOR);
(void) CyIntSetVector(USBUART_EP_2_VECT_NUM, &USBUART_EP_2_ISR);
#endif /* (USBUART_EP2_ISR_ACTIVE) */
IMHO if you can get data transfer working without having to work around the interrupts then all the better. I assume the PSoC is doing the magic behind the scenes for you anyway.
Where precisely is your code snippet from? did you put that in the Serial.c ? I’d like to give it a try and see what I can do.
Gave your serial code a try and it works well! Have you given it a try with UGS yet, still seems to be unable to connect to the device. As this seems to be an ongoing issue though I’m starting to think its a UGS issue not so much a grbl/programing issue. Have you had any problems with this, or are you using an alternate software to UGS?
It could be that UGS expects to see the startup string when connecting. Arduinos reboot when you connect via USB. That is done so that the IDE can start the bootloader in a simple way. The PSoC does not behave that way and I prefer it that way in case other interfaces like Bluetooth or Wifi are used.
Try this. As soon as you connect with UGS find a way to reboot the PSoC. There is a reset switch of the dev board that will do this. I suspect that might verify the problem.
I don’t know what UGS does, but other programs that can use bluetooth, like LaserGrbl send a reset command (ascii 0x18) when they connect. That does a soft reset of Grbl. It is a much better way than relying on the Arduino style reboot, because a basic Bluetooth module will not reboot Grbl.
Yup, you are 100% right, turns out UGS expects the startup string. I was able to verify this by adding a 5 second delay between the initialization of the USB, and the settings init. I decided to do it this way as it would produce a consistent result across all three of my different PSoC development boards. If I reset the board, then then connect UGS to it within 5 seconds everything works. But be warned; on all three boards it seems to break the connectivity with LaserGrbl.
I’m going to try to develop a programmatic approach to this that will work with multiple boards, and software packages. I’ve been playing with the idea of putting it in a while loop until a data packet appears in the USB buffer. Perhaps I can make use of the USB interrupts?? I don’t know but I’m open to suggestions.
I think you should post a suggestion for UGS to send a Grbl reset upon connection. UGS will have problems with other setups, like bluetooth.
Great Post btw. Whiole I liked it on the P59, you might want to look into sparkfun’s FreeSoC2. It uses 96, so more pins, and has a “almost” Arduino header. The 3.3v/5v power switch is a neet adon as well.
Few twiques and it works fine on this board:) Even have the TMC2130’s running off a line for spi
Greetings to all, someone who already has modified the program to use it to 16 bits and to be able to modify in universal g-code the option $ 0 = 8000
The $0 setting is uint8_t in Grbl
I’ve tried this port – and it works, except that I can’t get the limit switches to trigger an alarm. I notice that something does happen, but unlike my other GRBL machine, it doesn’t create an alarm. Looking through the code, I can’t see why but I also notice no one else has come across this problem?
I don’t have much time to maintain that port of grbl. It has not been as popular as the ESP32 port