During the work on my OpenPPS project last winter I came to realize that a general purpose pulse width measurement tool would be a very useful thing to have in the maker’s lab. There are many ways to build something like that and most of the current high performance microcontrollers would likely do the job all by themselves but I wanted to continue learning how to use FPGAs and this seemed like a good way to do that!
My objectives for this project were the following:
- Measure the pulse width with a Lattice iCEstick evaluation board with as high a resolution as possible.
- Support 1-wire and 2-wire (2-wire = pulse on, pulse off) inputs.
- Be able to measure the period of the pulses as well (and therefore the frequency).
- Be able to measure high and low pulses.
- Support the possible use of an external stabilized clock for the iCEstick as for OpenPPS.
- Calibrate the system using GPS.
- Send the results to a microcontroller for display and logging (I chose the ESP32 based M5Stack Core).
- Use I2C for communications between the microcontroller and the iCEstick.
- Create a simple user interface to select measurement modes.
- Continue to use IceStudio for Lattice ICE40 FPGA development.
- Integrate a low cost 8 bit logic analyzer into the system for hardware debugging.
- Continue to use PlatformIO with the Arduino framework for microcontroller software development.
- Reuse as much as possible what I did for OpenPPS.
FPGA Development
When I started on this project I discovered much to my delight that version 0.4.0 of IceStudio had just been released (I decided to use version 0.5.0-dev which at the moment is essentially the same). This version contains several new productivity enhancement features but the most important one for me is the ability to edit and save blocks. In the previous versions you could save part of your project into a custom block and reuse that but if you needed to change it later then the only way to integrate the changes was to delete the imported block and add in the new revised one. This was a painful process and very error prone. Now with the ability to edit and save blocks it makes the development of more complex projects a lot easier.
I2C Communications
For OpenPPS I used a verilog UART (serial port) transmit component to send data to the microcontroller but I never did get the receive part of it to work and I wasn’t really sure how I was going to use that anyway. For this project I wanted to create a reusable method to communicate bidirectionally with the microcontroller. Since the M5Stack has a Grove connector on it and therefore has the ability to communicate with external devices via I2C I decided to try that.
I found several sources of veriog implementations of I2C but I really liked the work that Chris Courson did here:
https://www.chrisbot.com/ice40-i2c/
This was easy to turn into a IceStudio block and I built up the rest of the project using that as the communications mechanism.
MIcrocontroller Software Development
I mostly wanted to display the measurement results but also I wanted to change the measurement mode among the following four options:
- Pulse Width (positive pulse)
- Pulse Width- (negative pulse)
- Period (positive pulse edge)
- Period- (negative pulse edge)
The code was easy to adapt from OpenPPS and as usual I used PlatformIO for development (I have switched from Atom to VS Code for the IDE).
Switching to I2C for communications with the iCEstick was straight forward.
Conclusions
I ended up writing a lot verilog code for the iCEstick for this project but thanks to IceStudio and my development setup I was able to do this in an modular and incremental way.
I was pleased with the overall result and will be able to reuse what I did here for other projects.
I will be giving a presentation on this at the Maker Faire Rome on October 19, 2019 at 1:45 PM so come and see me there!
After the Maker Faire I will be posting my presentation here and putting all the code in Github. Stay tuned!