Porting grbl to HiFive1

Hi,

I started porting grbl (link) to HiFive1.
For those of you unfamiliar with grbl, it’s an Arduino-based real-time G-code interpreter capable of driving CNC machines like engravers and laser cutters.

My porting is still work in progress, but so far I managed to get the UART working with interrupts and I managed to get the PWM output working properly.

You may find some info about this on my github:
Grbl for HiFive1

I’m trying to use PWM interrupts for periodic interrupts. The decision was to use PWM interrupts to get a periodic interrupt at fixed intervals, independent on the IRQ service time.

I encountered this weird behaviour where interrupts get disabled for no apparent reason. Trying to debug this with openocd, I see that mstatus has the MIE bit turned off without the software explicitly turning it off. This means everything gets stuck: no UART, no motor control.

As I said, it’s still work in progress, but if anyone wants to help or get more information, feel free to contact me or reply to this thread.

Cool project!

With regard to the interrupts getting disabled, does this happen even when you aren’t using the debugger?

OpenOCD mucks around with MSTATUS and it’s possible it’s not restoring it properly in all cases.

If you share your code that isn’t doing what you expect we can help take a look!

Thanks for the quick response.

My code is here:
https://github.com/jonronen/grbl_porting

To build it, I’m using the freedom-e-sdk:

  1. Clone grbl_porting to freedom-e-sdk/software/grbl_porting
  2. cd software/grbl_porting
  3. make -f Makefile.hifive
  4. cd …/…
  5. sudo make upload PROGRAM=grbl_porting
  6. Open a terminal: miniterm.py /dev/ttyUSB1 115200
  7. Reset the device
  8. GRBL should come up and print a welcome message
  9. Commands can be sent over serial

The following commands work OK:

  • M3 - turns on the spindle
  • M5 - turns off the spindle
  • S500 - set spindle speed (half way through)
  • S1000 - set spindle speed to maximum

So far these commands have used PWM0 and UART and things seem to work fine. However, commands that make use of PWM1 and PWM2 interrupts seem to get stuck:

  • G01 X100 F10 - move on the X axis with a slow feed rate
  • G00 X50 - move fast on the X axis

When these commands get stuck, all interrupts seem to be disabled. This can be reproduced both with openocd and without openocd. When the interrupts are disabled, the user cannot send any UART commands and the whole system seems to be frozen.

Let me know if this helps or if more information is needed. Thanks again!

Well, it looks like the problem is solved now.

Applying some trial-and-error I was able to find the right way to make things work:

  1. Configure some interrupts, set the interrupt handlers, set their priority, but don’t enable the HW yet.
  2. Enable interrupts using the CSR MIE bit: set_csr(mstatus, MSTATUS_MIE);
  3. Enable interrupts in the peripheral-specific register (e.g. UART0_REG(UART_REG_IE)|=UART_IP_TXWM enables the UART transmit interrupt)

The problematic code seems to be in the location of the code that enables interrupts: set_csr(mstatus, MSTATUS_MIE); It turns out that if this line is inserted before interrupts are configured or after interrupts are pending then some interrupts misbehave and some interrupts get lost and don’t fire at all.

Does this make sense? Has anyone seen this before? Or am I missing something?

It makes sense. I would probably swap 2 and 3, but it should work either way.

As you’ve discovered, many of the registers which feed into the interrupt enabled by MIE are not zero-ed out at reset (notably most of the PLIC registers are not reset, and many of the PWM registers aren’t reset either).

MIE is the final gatekeeper, and if you enable it too soon you’ll probably just drop into the trap handler which may or may not be set up yet.