In the last post, we looked at assertion fundamentals. As you might recall, an assertion is a boolean (true/false) expression at a specific point in a program that will be true unless there is a bug in the program. In today’s post, we are going to setup assertions and use the Renesas Debug Console to monitor for a failed assertion.
The first step to setting up assertions is to enable printf capabilities. Several posts ago, we discussed how this could be done using the Renesas Debug Console. To review, read Setting up and using printf. This involves including the stdio library and creating the prototype for:
extern void initialise_monitor_handles(void);
A developer can add these libraries and definitions to their project module but today’s blog, we will assume that these are being defined in the Synergy generated blinkyled with RTOS application in the blinky_thread_entry.c module.
Assertions are defined in the assert.h module. To get access, a developer needs to simply include assert.h in their module. Assertions are usually implemented in the header file as a function like macro with assert being all lower-case letters. This may seem strange to developers because we typically define macros in all capital letters. The assert module is part of the C standard and has to follow their definitions to meet the standard. This is why many developers will create their own custom assertions.
The blinky_thread_entry.c module contains the blinky_thread_entry function that defines a few basic variables and controls LED blinking. In the initialization section, after initializing the monitor handles, a developer can create a simple assertion. Just to see how an assertion looks when it fails, we can assume that the variable count, which is initialized to 0, should be initialized to 1. The assertion would look as follows:
assert(count == 1);
If count is not equal to 1, which it won’t be in this case, the assertion will fire off a message and halt program execution. The question that might come to mind though is how is this assert message set? It turns out, that by default, there is no function defined to handle assertions! The developer has to define it themselves!
Creating the assertion function is quite simple. First, a developer can right click on their first assert use and select Goto Definition. This will bring them to the following macro:
First, note that if the macro NDEBUG has been defined, assert becomes nothing! Some developers choose to use assertions during development to catch bugs but then disable assertions for testing and production. Rather than go through the code and remove all the assertions, which would probably be needed for further development, we simply define the assert macro to replace all instances of assert with nothing.
Second, since we have not defined NDEBUG, if the assertion fails, a function named __assert_func is called with four different parameters to specify the file, line number, function and the conditional error that occurred. In order to use the assert macro, a developer has to manually define __assert_func in their code somewhere. Since the implementation for the assert macro is standard, there is standard code that is used to implement __assert_func. An example can be found below:
void __assert_func (const char * file, int line, const char * function, const char * error)
printf("File %s, Line %i, Function %s, Error Code %s\r\n",file, line, function, error);
In this case, we use printf to display the file, line number, function and error into the Renesas Debug Console and use an infinite while loop to prevent the program from executing any additional code. If a developer were to forget the while loop, a warning would be generated by the compiling letting the developer know that a function that had the attribute no return was actually returning.
The output generated by this code is the same that we saw in the last post, but to remind the reader, you can see the output from the failed assertion in the Debug Virtual Console below:
A developer can now use assert throughout their code to test their application conditions and make sure that they are exactly what they believe they should be. When they aren’t, the assertion will fire and the developer can dig in to see what is going on and make the appropriate adjustments.
In the next post, we will start examining the different debug capabilities that are built into the Arm Cortex-M processors and how developers can use them to improve their debugging strategies.
Until next time,
Live long and profit!
Hot Tip of the Week
Do You Know About Technical Updates?
Periodically important technical updates are published on issues related to Synergy Platform elements. These can contain critical information and you should look them over to make sure you understand any issues that might impact your design. You can find them by going to the top tool bar on the Renesas home page, selecting Design & Support -> Document Search.
Then select these filters depending on the devices you are interested in.
Here is the direct link if you want to bookmark it: