One of the most powerful elements of the Renesas Synergy Platform are the many high-level application frameworks provided in the Synergy Software Package (SSP). The APIs provided in these frameworks abstract development from a specific hardware implementation and make it so easy to move from one hardware implementation to another that it can be done without writing any code. Want to see how this is done? Read on.
A Common Development Challenge
Let’s say you have implemented a console interface for your application project that allows you to read and write to memory, test out serial interfaces and various other debugging tasks. You have used a UART port to host the connection to a laptop for convenience.
Figure 1: Debug Interface using UART Interface on a Renesas Synergy SK-S7G2 kit
Now, it turns out that marketing likes the functions you have implemented and wants to offer them as an option for remote diagnostics. The UART interface won’t work for this however, but there is a remote link available via an unused USB port. They now want you to move the console interface to USB. Lucky you.
A Synergy Shortcut- the Console Framework
This could be a monumental task if you had to implement all the USB functions on your own. Fortunately, you used the console framework available in SSP. The console framework implements a simple console interface with configurable multi-level commands, and built-in console functions that prompts the user for console commands, parses the commands and calls the associated user implemented callback function to implement the command.
The console framework uses a communications framework to implement the text input and output. The communications framework can be implemented using different hardware options, but all the console framework APIs are the same, independent of the specific hardware implementation! This is a big time saver when moving from one implementation to the other, as we will see.
When you add the console framework module to your project using the SSP thread stack tab, you are presented with all the options for the communications framework as illustrated in the following figure- Ethernet (sf_el_nx_comms), USB (sf_el_ux_comms) or UART (sf_uart_comms).
Figure 2: Console Framework Communications Options- Ethernet, USB or UART
Once you select the desired communications interface the stack is automatically populated with the needed low-level modules. For example, if the UART interface is selected the resulting stack is shown in the following figure. The lower-level modules- the UART hardware driver and the associated transfer drivers are automatically added to the stack. Modules that require some configuration settings are clearly indicated with highlighted red text. By hovering over the module, you can see what actions need to be taken to configure the module- in this case the interrupt priority levels for the UART driver need to be selected and enabled.
Figure 3: Console Framework using the UART Communications Framework
The configuration settings for the UART driver are shown in the following figure. The Interrupt priorities, shown at the end of the table, still need to be configured. The settings for the baud rate, number of data bits, and other communications channel characteristics can be changed or the defaults accepted. (These settings will be useful to know when setting up a terminal interface on the laptop.)
Figure 4: UART Communications Settings
The console framework has a few configurable settings as shown in the following figure. The most important ones are the name for the framework (which is used to call framework APIs) and the name for the initial menu, (which is needed to create the menu structure you will see in the code example shown in just a bit).
Figure 5: Console menu Configuration Settings
Implementing a Simple Console Interface
Once the console framework is defined and configured you can write the code to implement the desired console functions. Each console command has an entry in the console menu and an associated callback function to be executed when the command is recognized by the console interface.
A simple example is shown in the following figure. You can see in the third line of code it creates a single command, called TOGGLE, that is defined in the g_sf_console_commands array. The help text "Toggle an LED" and the command callback led_toggle_callback are also defined as part of the command structure. In the following code section the command structure is added to the command menu using the g_sf_console_root_menu structure in the command_list element. Next, the command is implemented in the led_toggle_callback function where it toggles an LED using io_port pinread and pinwrite APIs. Finally, the entire console interface function is implemented on console_thread_entry and it simply uses the prompt API to issue the command prompt to the user, to parse the command and to execute the associated command- in this example, “TOGGLE”.
Figure 6: Code Illustrating a Single Command Console Framework to Toggle an LED
Now the above illustration is very simple in order to show the entire design in a single page. Clearly more commands could now be added for other functions- memory read and write, serial interface tests, display tests and many others by just creating the menu items and implementing each debug function in a callback. The console framework makes it easy to get a starting point working right away- one that is very easy to expand on. This approach significantly speeds development over implementations that 'start from scratch'.
The operation of the UART version of this simple console interface is shown in the following figure. The console framework prompts the user for a command and when the TOGGLE command is entered, the LED on the board is toggled. Note that the console framework executes the built-in Help Menu command when a “?” is entered.
Figure 7: Terminal Interface Issuing the TOGGLE command to the console interface
Switching Communications Interfaces
To switch to a different communications interface, all you need to do is replace the UART comm framework with another one- for example, USB. You delete the UART communications interface from the thread stack and then select the USB option instead of the UART. The rest of the stack is auto-populated to complete the needed function as shown in the following figure.
Figure 8: Stack for the USB Implementation of the Console Framework
The USB Port module can use either the Full Speed (USBFS) or High Speed (USBHS) hardware implementations, so these are selected by clicking on the Add USBX Port DCD module. Once the selection is made, USBFS for example, and the interrupt priority selected, the stack is complete as shown in the following figure.
Figure 9: Console Framework Stack- USBFS Implementation
The USB port module has some useful configuration settings and these are shown in the following figure. (Typically, the defaults are sufficient and allow you to get the interface working quickly. You can come back and optimize or expand them later if desired.)
Figure 10: Configuration Settings for the USB Port
Once the USB port is configured to your requirements, you just need to click the generate code button. The UART communications framework will be replaced with the USB communications framework automatically. Simply switch the cable to the laptop from UART to USB, download the new code to the board and connect to the USB port on the board using a terminal emulator over the laptops USB port instead of the UART port. Once connected the command menu is displayed and the TOGGLE command can be used to toggle the LED, just the same as when we used the UART interface.
Figure 11: Console Interface using USB and Terminal Emulator
The Power of Synergy Frameworks
Did you notice how much code we had to write to implement the USB communications interface? None!
We were able to easily change to the USB connection from the UART connection without writing or changing any code because SSP frameworks abstract the lower-level hardware communications functions from high-level functions. The APIs used by the communications interface are all the same, so any higher level implementation sees a communications interface the same for many different hardware implementations. Significant functionality can be changed by simply swapping in a lower level module and configuring a few settings. This approach is used for a variety of frameworks- for things like audio playback, timing, serial communications, data transfer, and much much more.
Of course, this also means that the first time you need to implement a function you already have a wide variety of powerful frameworks that you can use- so you don’t need to write them yourself! The integration of the powerful ThreadX RTOS makes it possible to provide frameworks for very complex functions- including networking protocols, USB connectivity, graphical user interfaces, File systems and much more.