By far, the most time-consuming portion of this project was the firmware. I tried to create a system that could be easily ported from the STM32F4 to another microcontroller and I tried to make it very readable. I’m not much of a coder and knew that if I were to visit it later (as I’m doing now), I wouldn’t remember how anything worked. Reviewing the files now, two years later, I’m rather pleased with how it was all laid out.
To make the code easier to understand, easier to segment, and more portable, I split the files up into manageable chunks. Any file that ends in “_f4” is specific to the STM32F4, while all other files were created to be portable among microcontrollers. This is what each file does:
adc.c acts as the intermediary between msgq.c (message queue) and the low-level STM32F4 ADC code.
adc_f4.c is the machine-level code for initializing and using the ADC.
consume_adc.c is the function that takes the ADC data and controls the PWM, LCD, and UART according to that data.
msgq.c is the queue that organizes and moves ADC requests and data, working between main.c and adc.c.
pwm_f4.c is the machine-level code that controls the PWM and is used by consume_adc.c.
systick.c is the timing control for the entire project, using the systick timer of the STM32F4.
uart_f4.c is the machine-level code that initializes and utilizes the UART on the board. It is used by consume_adc.c.
7seg_f4.c is the machine-level code that converts data to the appropriate voltages to display data on the seven-segment LCD.
This was also the first time I delved deeply into the makefile of a project, for a couple of different reasons but mainly because of the FPU. There are three settings for the STM32F4 in the makefile: You can either completely disable the FPU, enable a soft FPU, or enable a hard FPU. The soft FPU uses the FPU, but it passes the parameters through the core registers, whereas the hard FPU forces all calculations to go through the FPU and its registers. After several compilation failures due to setting the makefile to hard FPU, I found a page online (the page has since shut down) showing the differences in efficiency for no FPU, soft FPU, and hard FPU while doing floating-point calculations. From the results, the performance difference between soft FPU and hard FPU is small enough to be nearly non-existent, which led me to forgo the hard FPU and use the soft FPU. In reality, due to the infrequent floating-point calculations, I could have avoided the FPU entirely and still not had any timing issues.
The display presented a minor, yet interesting, challenge. Twisted nematic LCD displays are extremely useful due to their practically non-existent current consumption; however, they are driven by an ac signal to make certain that the crystals don’t “lock” into one position. It was surprisingly difficult to find clear information on how they should be driven and recommended frequencies. My original issue was that I attempted to toggle the individual driving pins while tying COMMON to either ground or VCC. The display would flicker and was washed out. In retrospect, the fact that the datasheet referred to it as COMMON versus GND or VCC should have been my first clue. I hooked COMMON up to another GPIO and switched it opposite to the pins that I wanted driven. I made the refresh frequency changeable in main.c but currently have it set to update every 10 milliseconds, or at 100 Hz, which means there is no visible flicker.
I’m attaching a zip file of the source files and header files for the project as well as the final hex file for your perusal. Even if you don’t need the whole project, these files may be helpful. Or, as is likely, for a better coder than me, these files may be a source of great amusement. Either way, enjoy!