Surf5 board is an increadible low cost board for IoT and any project thart needs Internet connectivity while driving external peripherals in a very reliable and compact manner, only requiring the W7500x MCU. More over SUrf5 board is designe by wiznet to provide PoE out of the box which make it more compact.
In this project we will explore how to program the W7500x Cortex M0 MCU on the SURF5 board to create a Smart Clock capable of hadling real time events. The design is very flexible as code can be adapted easily. Along the road we will explore how to achive real time response for different tasks running concurrently on the board by using a hardware RTOS framework.
The SURF5 board is an inexpensive board from Wiznet with a Cortex M0 MCU that has a hardware TCP/IP stack. The Wiki page is very comprehensize to get you started with this board. In this guide we will not cover the basics about setting the software tools needed for working with W7500x MCU as it is very clearly explained here. Nonetheeless, in this section we will cover a couple of points that might be important to review. For this project I have used the Surf5 board repository as a starting point. The repository allow you to create projects in Keil or Visual Studio Code, we will use the later and the main reason for that is the flexibility of setting a debugger which is not possible in Keil project. Another reason is propietary licensing and code size restriction. You can go to Surf5 wiki and setup the envirement for Visual Studio as explained here. Once you have compiled the repository examples without any problem you should be ready to start adding the bits for the Smart Clock.
The Smart Clock specific hardware requires a few things we will discuss in next section, in order to work with Surf5 efficiently you will benefit for setting a debugger probe. Any SWD capable proble should work but I have use Segger J-link EDU (and PLUS) adapters. You need to connect 5 signals from the 20 pin adapter to the Surf5 board.
VTref connects to Pin 36, and the SWDIO and SWCLK to the signals in the 3 pin header as shown below.
With that you are ready to start building the Clock.
Here is a short list of some requirements that the smart clock project using SURF5 will try to fulfill.
The clock shall update the time automatically upon star of execution.
The clock shall provide a visible indicator to inform user of the date time.
The clock shall be able to display message information in a readible way to users.
The clock shall be able to configure the time zone.
The clock shall provide an way to read user input to manage it's configuration.
The clock shall provide a stopwatch.
In order to fulfill some of the requirements above, the Surf5 platform is very handy and appropiate for low cost/low BOM solution but as everything there are challenges and blockers so I will explore some of them that I faced during implementation.
The hardware needed is the Ethernet TCP/IP capable W7500x MCU, the connectivity and power is provided entirely by surf5 board using Power Over Ethernet (PoE) module WIZPoE-P1, the little board sits on top of surf5 board. Automatic update uses the TCP/IP Stack to connect to NTP servers in order to get the actual timestamp.
Surf5 board does not have a 32khz crystal on board needed for the RTC module to work properly. SO this project does not uses the RTC peripheral of W7500x MCU. Instead, in order to get BOM low , the idea of adding external RTC was ditched. A software solution was implemented, the solution relies on the SST feature to program a task to receive periodic Time Events as it will be shown in sthe software implementation description.
Clock visual indicator display.
The clock displays the current time using a led matrix (also 7-segment is possible) array. I am using the max7219 driver connected to a few 8x8 led matrix modules. The Maxim chip allows to cascade few 8x8 led arrays to create a bigger display in which we can show time or a message.
The clock has to ways to accept inoput from users. Using TCP/IP connectivity it is possible for user to modify the clock configuration. Another option is using an IR remote control.
The Ethernet connectivity requires more knowledge to setup and and also needs an external application of some sort to send the messages. This is the most configurable way to do it for some scenarios based on only TCP/IP communication.
The seconds option aimed for more regular users is the IR remote control. This opition is handy to quickly configure the clock even without internet connection.
The Surf5 SDK does not provide an RTOS, so basically out of the box you will be programming bare metal application using the wiznet repository. In a sense the SDK provides all the hardfare interface for the task but if the platform is meant to be expandable, putting everything in a while loop is not the best option. Some tasks can be programmed as events using the interrupts from MCU and that will help but interconnecting your tasks will soon become a project that is difficult to maintain as well as expand or modify for different purposes. Another aspect missing from SDK is the ability to program the MCU in C++ language. This might be overkill for a small MCU but the fact is that a large portion of existing libraries for third party drivers or applications is based on it, for instance take the Arduino as example, lots of projects and libraries but most of them has a dependancy on C++ which we cannot use as well without porting them. I have almost look for existing C libraries I can reuse or adapt.
The Approach used in this project.
Instead of avoiding the problem, I took the route to make my implementation entirely using the Wiznet SDK, so this project has only one MCU and no arduino piggy backing to fulfill requirements (sorry arduino lovers!), this project has just pure Wiznet juice on it.
Super Simple Tasker - A hardware RTOS.
The SST hardware RTOS was used in this project. There is a bit of work to create the BSP configurations for the W7500x MCU but once that is done, we have a hardware RTOS for our Smart Clock tasks. The project can be found in my github fork under the sst-wiz7500 branch. Smart Clock RTOS Tasks Overview.
There are four major important task running concurrently on this project, listed below in no order of importace.
Web Server task. The task is mainly for a server listening for communication using TCP/IP.
SNTP Client Task. The task periodically poll an NTP server and update time information.
Led Matrix Task. The task handle the messages to display to led matrix display using max7219 chip driver.
IR remote control task. The task handle the reception of IR remore control codes.
Led Task. Inherit from basic demo, it toggles the LEDon Surf5 board. Used mostly for debugging activities.
The task are initialized on main.c file using the following code.
The implementation of the task uses a library for max7219 in C programming language. The original library can be found here. Porting the library to Surf5 board was done and tested first before creatinf the SST task. It is working with both 7-segment and led matrix modules. It uses Surf5 SSP peripheral to send the bit values for leds and consiste of two files max7219.c and max7219.h under the src folder directory. The task source files reside in led_matrix.c and led_matrix.h files as shown below.
The Task will accept messages to display a text on the led matrix display using a method to post message from SST RTOS. It can display the text when requested but it will also help to scroll the txt on the led matrix by specifying the number of times a text will scroll. For our demo the task upon initilizing will display a message. The instruction for this is in BSP file bsp_surf5_w7500.c and shown below.
So the task will scroll text one time in this case as show below.
The smallest font available at the moment is 6x8 dots, which is somehow big for displaying time in hours/minutes and seconds.
The SNTP task is a client that periodically connect to an NTP server to update time information, the refresh period is defined using a flag in code whih can become a parameter that user can change if desirable.
Upon star of execution it start querying the NTP server until response or timeout. After successful response is received the time is updated and displayed on screen. For this stage the task configures a time event to happen in short intervals, this will monitor the TCP requestr response and parsed. Onve done, the task configures a 1 second event that keep the display updated every second.
Since we don't have an RTC module available on surf5 board, I used the SNTP library to manually update the time as if the update is coming from NTP response, for instance the snippet code that handle the time update every second is
Basically inc_sec_ticks() funtion is called to see if it is time to update using NTP server or time to keep our update locally using our library and 1 second task event. If update is local, we increment the second epoch variable and call again the library function to convert it to time date object.
This works very well as show in the following video.
The update using NTP works flawless but one problem of the original library from Wiznet is that SNTP library does not account for summer daylight saving time, so time is wrong. For fixing this, I implemented an algorithm which is explained here. A new funtion in wiznet sntp.c file was implemented, the function details can be found in sntp.c file under the libraries Internet directory, i.e.
The function is used within the library only, when NTP response is parsed and epoch seconds are available in datetime structure, the function is called to aply DST saving if required inside get_seconds_from_ntp_server funtion.
The Web server task is a simple task that serves a web page, in this case we are using same web page as the original example and ported the implementation to run on it's own SST Task. The webserver Task runs every millisecond but this can be change in the webserver.c file, for example serving on HTTP 80 port is done in the following code.
A more interested Task here is a work in progress with also a basic example working for a MessagePack web server. The idea is to communicate with the smart clock using a TCP socket that serves a C implementation of the MessagePack coding protocol. The example code is located inside the examples directory of the SDK.
The server works by calling the following function periodically in exact way we do with the webserver.
The IR remote control task handles the reception of IR signals. The implementation was a port from an existing arduino library found here. The library implements only NEC protocol decoding and encoding, althought encoding is still a WIP. For an explanation of how it works refers to the english documentation. There are a few things I have done for this to work. First is to correctly configure the ISR for signal detection. Currently I have some issues to get the falling edge interrupt to work on my surf5 board, and investigation is under way. The workaround for now is that the GPIO interrupt is set for rising edge detection and a inverter gate is configured to negate the signal from IR led receiver.
The othwer thing needed is to calculate elapsed time in micro seconds since star of execution. Tje library relies on the micros() function from Arduino IDE which is not available in Surf5 SDK.
Arduino micros() implementation for Surf5 board.
The implementation uses the DualTimer available module, in short it is configured as a down counter with 1us tick, a software function converts the down counter value to a up counter and also adjust for rollover which happens aproximately every 71 minutes.
The arduino micros() function dependancy on specific MCU to provide exactly 1us tick increment is explained here, some platforms can only achieve 4 or 8 us resolution. The Surf5 implementation provides 1us resolution. This is crucial as library timing for NEC decoding requires to calcultation the bit time. The NEC protocol is explained somehow here. The task in defined to process incoming received codes and produce some output in response. In the case of our Smart clock (which is still a Work In Progress), the task process all command codes from a cheap IR control.
The task receive a new code and generates an action, in this simple case it stop the colon character from been toggle in tjhe led matrix as shown in the following video.
In the same way we can handle the configuration of the clock parameters or any other user action can be assigned into our code.
The nec_decoder.c and nec_decoder.h provides the implementation, for instance your remote control might have different codes assigned to buttons, in this case you need to adjust the codes in the header file, for instance, my control looks like this and there is a loink to buy it as well.
There are number of 3D designs out there for led matrix displays, so I took one of my favorites I could find and did the modifications for hosting our Surf5 board alone the rest of components. The original design can be found here anfd the remixed design here.
The 3D design is still a work in progress as some details are been finilized.
A few items need some rework such as the position of the Surf5 board, as the PoE module is too high we need to account for that.
This project shows the powerful MCU TCP/IP Offload Engine (TOE) W7500x device handling comms, external display and IR remote without any other MCU. The device is more than suitable for a Smart Clock or a Smart display device.
The framework implemented for programming the MCU is novel as it allow to have a Hardware RTOS to work, allowing several process concurrently. A software RTOS will be overkill for this MCU but thanks to SST RTOS project now the limit is the sky.