This tutorial was extracted from Erich Styger blog http://mcuoneclipse.wordpress.com with his agreement.
I’m a big fan of physical UART/RS-232 ports on boards. So I was somewhat disappointed not to see a serial 9pin connector on the Freedom KL25Z board. But it is perfectly understood that for this price costs are critical, and a serial header or connector is pushing the budget for that board very likely out of the water. Still, I want serial connectivity for my applications.
Freedom Board with RGB LED
When I ported FreeRTOS to the Freedom board, I noticed that the OpenSDA debug interface enumerated as well a USB CDC port. After I had explored the P&E OSBMD/OSJTAG virtual serial port, I wondered if this works as well for my Freedom board. And yes, it does!
OpenSDA CDC Serial Port in Task Manager
So I used that opportunity as well to improve the FSShell component I’m using in other projects. The result is an application with FreeRTOS, a realtime clock, changing RGB LED and a Shell using the OpenSDA USB CDC for communication with the host.
The Application
The application is implemented with Processor Expert in Eclipse based CodeWarrior for MCU using the ARM gcc compiler:
Freedom Shell Application with Processor Expert Components
Compared to the application in this post, it ads:
- GenericTimeDate: A generic real-time clock implementation, see There is a Time and Date for both Worlds.
- FSShell: A file system shell with command line interface. See FatFs with Kinetis.
- Serial_LDD: Logical Device Driver for a serial/UART connection.
FSShell with RingBuffer
Developing the Application for the Freedom board, I used that opportunity to refactor the FSShell component a bit: the component was using its own buffer management. Having a more universal ring buffer implementation in RingBufferUInt8, I decided to use for the FSShell as too:
FSShell with Ringbuffer
Additionally I have added a new routine ReadAndParseLine() an ‘append’ buffer management. This is useful if the terminal is sending character by character (and not as a full string). It turned out that this was a good idea if using Tera Term.
01 | /* |
02 | ** =================================================================== |
03 | ** Method : FSSH1_ReadAndParseLine (component FSShell) |
04 | ** |
05 | ** Description : |
06 | ** Reads characters from the default input channel and appends |
07 | ** it to the buffer. Once a new line has been detected, the |
08 | ** line will be parsed. |
09 | ** Parameters : |
10 | ** NAME - DESCRIPTION |
11 | ** * cmdBuf - Pointer to buffer provided by the |
12 | ** caller where to store the command to read |
13 | ** in. Characters will be appended, so make |
14 | ** sure string buffer is initialized with a |
15 | ** zero byte at the beginning. |
16 | ** cmdBufSize - Size of buffer |
17 | ** * io - Pointer to I/O channels to be used |
18 | ** parseCallback - callback provided by |
19 | ** the user application to parse user commands. |
20 | ** If not used, NULL can be passed. |
21 | ** Returns : |
22 | ** --- - Error code |
23 | ** =================================================================== |
24 | */ |
25 | byte FSSH1_ReadAndParseLine(byte *cmdBuf, size_t cmdBufSize, FSSH1_ConstStdIOType *io, FSSH1_ParseCommandCallback parseCallback) |
26 | { |
27 | byte res = ERR_OK; |
28 | size_t len; |
29 |
30 | len = UTIL1_strlen(( const char *)cmdBuf); |
31 | if (FSSH1_ReadLine(cmdBuf+len, cmdBufSize-len, io)) { |
32 | len = UTIL1_strlen(( const char *)cmdBuf); /* length of buffer string */ |
33 | if (len==0) { /* error case */ |
34 | return ERR_FAILED; |
35 | } else if (len==1 && (cmdBuf[0]== '\r' || cmdBuf[0]== '\r' )) { /* eat preceding newline characters */ |
36 | cmdBuf[0] = '\0' ; |
37 | } |
38 | if (len>=cmdBufSize-1) { /* buffer overflow? Parse what we have, will be likely return an error */ |
39 |
40 | res = FSSH1_ParseCommand(cmdBuf, io, parseCallback); |
41 | cmdBuf[0] = '\0' ; /* start again */ |
42 | res = ERR_OVERFLOW; |
43 | } else if (cmdBuf[len-1]== '\n' || cmdBuf[len-1]== '\r' ) { /* line end: parse command */ |
44 | cmdBuf[len-1] = '\0' ; /* remove line end character for parser */ |
45 | res = FSSH1_ParseCommand(cmdBuf, io, parseCallback); |
46 | cmdBuf[0] = '\0' ; /* start again */ |
47 | } else { |
48 | /* continue to append to buffer */ |
49 | } |
50 | } |
51 | return res; |
52 | } |
Shell Task
The implementation of a task providing the shell interface was really straight forward:
01 | static portTASK_FUNCTION(ShellTask, pvParameters) { |
02 | unsigned char cmd_buf[32]; |
03 |
04 | ( void )pvParameters; |
05 | cmd_buf[0] = '\0' ; |
06 | FSSH1_Init(); |
07 | ( void )FSSH1_ParseCommand(( const unsigned char *)FSSH1_CMD_HELP, FSSH1_GetStdio(), ParseCommand); |
08 | for (;;) { |
09 | ( void )FSSH1_ReadAndParseLine(cmd_buf, sizeof (cmd_buf), FSSH1_GetStdio(), ParseCommand /* local cmd parser */ ); |
10 | FRTOS1_vTaskDelay(50/portTICK_RATE_MS); |
11 | LED2_Neg(); |
12 | }; |
13 | } |
14 |
15 | void SHELL_Init( void ) { |
16 | if (FRTOS1_xTaskCreate(ShellTask, ( signed portCHAR *) "Shell" , configMINIMAL_STACK_SIZE+350, NULL, tskIDLE_PRIORITY+1, NULL) != pdPASS) { |
17 | for (;;){} /* error */ |
18 | } |
19 | } |
Tera Term: USB CDC with OpenSDA
Trying my application did work right away: both the Eclipse Terminal view and Termite had problems: the were blocking after few seconds . Not sure if this a generic problem of the terminal implementation or the OpenSDA USB CDC implementation. Luckily it worked perfectly with Tera Term
. So that’s why I’m showing Tera Term screenshots below.
After reset, the board shows the following menu. The same menu is shown if I type in ‘help‘ as command:
Freedom Board Shell
Date and Time commands are provided automatically through the FSShell:
FSShell with TimeDate
Date/Time and other information is shown with typing the ‘status‘ command:
System Status
This shows me as well all RTOS tasks with their status, along with performance information about each task.
The Project
The project and sources can be downloaded from this link.
Summary
The Freedom has no physical UART/RS-232 on-board, but this is not a problem for me any more as I have a working shell connection through the P&E OpenSDA USB CDC connection. Although the OpenSDA firmware on the board is preliminary, it works very well. And I was able to successfully extend my Freedom board application with a real-time clock and a shell.