The STM32 Development board
The development board used for this project is readily available. By no means is it new technology, but it does the job for a very good price. You can pick these boards up for under $50 on Ebay or through many other online electronics stores. The actual MCU on this board is the STM32F103VE.
Development Environment
I was thinking of how to start this post for a while as I really didn't want to conjure up all of the info I used to build the tool-chain for the stm32 board. After gathering some inner strength I decided to just search the old faithful Google and see if I could find a solution that was straightforward and step-by-step.
In saying this, Zizzle does have an Ubuntu virtual image with the tools already built which you can access from
here.
I just stumbled across this
document which provides a very comprehensive walk-through on setting up an SMT32 development environment.
Either of these two should get you talking to an ST board pretty quick.
Here's a SS of Eclipse with the STM32 code etc etc.
FreeRTOS
Ok so I had previously programmed ATMEGA micro-controllers, which was my first step into C Programming in general. My role as industrial electrician taught me about programming via PLC's using ladder logic, function block diagrams, and statement list programming.
In addition to the steep learning curve of micro-controllers and C programming, I enrolled in a Bachelor of Engineering course in which I studied part time (I will finish in November 2014).
THEN... I get told about this operating system called FreeRTOS which would make multitasking a breeze and the world would become so much easier.... ha! Read on...
I HAD to learn this... had to.
So, I used Zizzle's Virtual-box image, and dabbled in a bit of the FreeRTOS API functions. In short, I got very confused and created more bugs than you could imagine. This was the best thing for me... I was back in the deep end. I bought the Cortex M3 FreeRTOS programming manual and reference manual from the FreeRTOS site. And that's when things made more sense.
One step was forward, then I would take two steps back... this went on for a long time before I started to get it. I was introduced to the world of binary semaphores, task priorities, and many more strange things that I had "heard" of before. As a side note, I will say that much of the theory that I was learning at university was starting to become clearer.
LCD and TFT
Zizzle and myself worked on hacking a driver we found on the net so it would work on the dev boards we had. This took a fair bit of reading, time, and patience. Most of the credit should go to Zizzle as he did incorporate the text interface that we use now as well as the menu system which I am sure he hacked from a version he wrote for an Atmega128 controller previously. Here's a pic of the display working with text and some basic graphics.
So this was the starting point for the Brew Machine code!
Applet coding.
Zizzle had created a sample applet in his source code which I used as a starting point for my coding of Manual Operation. The idea was to get each and every component to a working state manually and make a few beers this way to test components. I created tasks that would handle calls to the LCD so that it didn't clog up the actual code that handled the functionality (start/stop/change values etc).
I used semaphores to handle the display applet so that the touch handler wouldnt hand back control to the menu until the display had finished updating.
I found that working with FreeRTOS helped me learn quickly about the importance of understanding 'context switching' and how can play a large role in introducing bugs into the system.
The following image shows some of the crane code:
DS1820 Temperature Sensors
As an exercise, I rewrote the driver to handle the one wire bus that talks to the DS1820 temp sensors. I had a little bit of exposure to this driver whilst using the Atmega128, so I found it interesting writing it for a different micro-controller. A permanent task was created to send a convert command to the temp sensors every second and wait for each result.
I2C I/O Expansion
I started to run out of I/O as we added a few extra valves and sensors. I bought an I2C relay board online for around $40 which handles 10A 240V over the contacts. I coded a driver for the I2C using the stm libraries to handle calls to the bus. I also introduced a basic error checking mechanism where it would read what was written to the device, and if the values werent the same, it would resend. If the bus returned a failure, it would reset the bus and try again. This functionality hasnt yet failed for me whilst running the machine. I am aware of other error checking methods, but time is my smallest resource whilst Im studying and have a full time job!
Auto Brew
The auto code was part-hack and part-new design. This is mainly for the fact that code-reuse is a helpful and friendly tool which I have learnt during coding. I incorporated a multi-tasking approach to the original auto code.
The concept is as follows:
- User presses "brew" in the menu system.
- Application opens brew applet and passes key handler there. The key handler handles calls to each of the buttons shown in the image above (LCD Display). The three buttons on the right hand side are "view changing" buttons which change whats shown on the display. The three buttons on the bottom are functional. They start/stop the brew or change the brew step.
- Upon pressing "brew", a task is created which handles the brew steps. These brew steps are ADT's holding information such as: start time, elapsed time, and pointers to their functions in which provides the functionality of that step.
- Some steps are able to be run in conjunction with each other such as "grind grains" and "close valve x", therefore a messaging system was created where the brew task receives messages when tasks have been completed. These messages hold information such as "task source" and a integer which equates to a message code such as COMPLETE or FAIL etc. The brew task can then send start multiple steps and simply wait until they send a message back upon completion. It then updates is "complete" flag in its ADT.
- Other steps do require all previous steps to be complete, for example the Mash - where all ingredients have been added to the mash tun. This is where the brew task has to check to see if the next step requires this. If so, then the brew task sits and waits until all "completed" flags have been set in the previous steps and then invokes the next step. As soon as this task has been called, the brew task can then check the following task before invoking it. This allows the brew "designer" to tailor the brew to their liking.
This code is still under testing and there are many "better" ways to do things. Thorough code testing is definitely required. Functionality testing has proven to be reliable, although a single brew can take around 4 hours, so repeated tests are very rare.
The image below shows the brew steps in the brew data structure.
The following videos show a few of the sequences during the brewing process.
Video #1 shows a test sequence with no multitasking. It was created before the stirring motor was mounted.
Auto Testing Video #1
Video #2 shows a sequence where the stirrer gets lowered into the grain incrementally. This is so that the stirring arms can break into the grain and turn at the same time whilst lowering.
Auto Testing Video #2