FAQ: Answers to Questions and Feedback¶
On this page, we answer the questions and comments raised in the feedback regarding the C language section of the course, divided by lecture chapters.
About Completing the Course¶
Q: I couldn’t finish the course last year. Do I need to start from scratch?
A: No. The course completions for JTKJ and/or TKJ courses are valid for one year, so you only need to complete the missing parts of the course. However, you need to complete the entire block: C programming and the course project.
Q: What exactly does the exercise deadline mean?
A: Points towards the final grade are awarded for exercises from lecture chapters 1-12 that are completed by the deadline. These exercises can be found on the Exercise subpages of the course materials. Introductory or ungraded lecture tasks within the materials do not contribute to the grade.
Q: Will I be penalized in the exercises if I attempt the same task multiple times?
A: No, you won’t. You can attempt each task as many times as needed. You get points when the checker approves your answer. However, we do not recommend using Lovelace as a C language error checker... it’s better to ask the assistants. There is only one exception. There are some questions that limit the number of answer. If you exceed the limit, your exercise wont be evaluated.
Q: The schedule for the lab session week doesn’t work for me at all!
A: Discuss this with the course staff. Without attending the lab, you won’t be able to get the development board.
Q: Can I complete the project with Arduino or other platform?
A: Generally, no. However, if you have built an embedded system as a hobby or something similar using Arduino or a similar platform, you can propose it, and we will see if it meets the course project requirements.
Q: As a minor subject student (or equivalent), I am simultaneously taking the Elementary Programming course and the JTKJ course. I’m struggling with the JTKJ tasks because they require knowledge that hasn’t yet been covered in the Elementary Programming course.
A: The Elementary Programming course is a prerequisite for JTKJ. The courses are not designed to be taken at the same time, and the course materials are not synchronized. The course instructors have no control over this, so please give feedback to those responsible for your studies.
Q: I do not live in Oulu. Can I take the course remotely?
A: The course is part of an in-person degree program, and attendance may be required for mandatory events such as laboratory exercises or final meetings. Depending on the situation, the course staff may offer alternatives, but these are provided on a case-by-case basis and are not guaranteed (exceptions are generally denied). In any case, the student must arrange to acquire the development platform themselves. Under no circumstances will we post any of the equipment.
About Lovelace¶
Q: The checker program keeps crashing.
A: We are very interested in hearing about this. Could you please show us during the lab or send a message explaining exactly how the crash occurs? Please include the URL of your submission.
When you receive a JSONDecodeError in Lovelace, it usually means that you have memory problems in your code (basically, you are trying to use memory positions that you are not supposed to use, e.g., overflow). In that case, the checker will kill the process. Check your loops carefully and make sure you are not trying to read/modify array positions outside their limits.
There is absolutely nothing we can do if the checker crashes due to your submission violating memory limits. It is impossible to retrieve anything from the checker because the OS kills the entire process stack immediately when you try to access memory outside of your reserved area. If you get a "checker crashed" report, your program likely has this issue.
Q: I submitted feedback, but I haven’t heard anything since. What’s wrong?
A: Feedback is shown to us anonymously, so we don’t know who to contact. We don’t publish solutions to the exercises, at least not until after the deadline.
C Language Exercises¶
Codeblocks¶
Q: When I try to compile/run my code in Codeblocks, I get this message: ''undefined reference to 'WinMain'
A:
Check that the
A:
Check that the
main
function is implemented. Check that the
main
function is only in one file. Ensure that you have created a "Console application" project, not a "Windows GUI".
Restart Codeblocks.
3. Bits and Number Systems¶
Q: I get frustrated with number system conversions and bit operations... and hey!, calculators exist!
A: These are such fundamental skills for a computer/electrical engineer that you should really be able to do them in your head.
Q: How can I represent a binary number in C? I saw the prefix 0b used online.
A: The prefix 0b is not standard C but an extension in some compilers. In the gcc compiler used in this course, it is working.
Binary numbers can easily be represented as hexadecimal; see the lecture materials.
Q: In hexadecimal, negative numbers usually have a minus (-) sign instead of the higher bits like 8(0b1000) and above.
A: That's true, you can use the minus sign with hexadecimal numbers as well. However, the computer internally handles these negative hexadecimal numbers as 2’s complement values, meaning the compiler does the conversion automatically.
Note that the assignment
int8_t neg = -0x81
(which seems like "two minus signs") doesn’t fit within the value range and requires a 9th sign bit, which means the 8th bit is interpreted as part of the value.In the course, we use the 2’s complement representation. For instance, when reading the register of a peripheral device, the only way to pass both positive and negative numbers is through 2’s complement.
5. Bitwise Operations in C¶
Q: If we're being precise, doesn’t the operations order table at the end miss the left-to-right post-increment and post-decrement operators (++ and --)? The table seems to only show the right-to-left 'first assign, then reference' versions of the ++ and -- operators. Example:
uint8_t n = 4;
printf("%d\n", n++); // <- missing, returns 4
printf("%d\n", ++n); // returns 6
printf("%d\n", --n); // returns 5
// for some reason, ++i and --i work the same as i++ and i-- in loops?!?
for (uint8_t i; i < 10; i++) {}
for (uint8_t i; i < 10; ++i) {}
A: Good question, there are a few things to consider here.
1) The table is meant to describe the order of precedence by rows, with higher precedence at the top. The direction of evaluation (whether left-to-right or right-to-left) depends on the row.
Evaluation direction means that if you have multiple operators of the same precedence in one statement, in what order are they evaluated, from right to left or left to right? For operator Q:
(a Q b) Q c
or a Q (b Q c)
? On this course, you won’t need to worry about this if you use parentheses.2) Additionally, when using these unary operators as function parameters, be careful, as the evaluation order (binding order) is compiler-dependent. This is discussed in the textbook (Kernighan & Ritchie, section 2.12).
// Here, we don’t know which operation happens first, ++ or pow()
printf("%d %d", ++n, pow(2,n));
// A clearer way to do this would be (for example)
++n;
printf("%d %d", n, pow(2,n));
3) Finally, in a for-loop, the assignment operation always comes last. So it doesn’t matter whether you use ++ before or after, as it will always be executed at the end of the iteration.
7. Control Structures in C¶
Q: I can't print 64-bit numbers with printf. (I found a weird %PRI64d format specifier on Google that seems to work.)
A: Printing large numbers may require the use of the format specifier
%lld
(long long int), depending on the architecture and compiler, as %ld
might not be enough. In some compilers, you might need to use %i64d
as the format specifier.SensorTag Programming¶
Q: How do I print sensor data to the console window?
A: Strings are printed to the console’s debug window using the
System_printf
function, which is covered in lecture material 8. Input and Output in C (the "thousand-dollar tips"). However... due to the way RTOS is implemented, the function should not be used like the standard library's print function, meaning you don't pass numerical values in the arguments to be printed in the string. You should proceed as follows:
1. Use the
2. Pass this string as an argument to
3. Finally, don’t forget to call
1. Use the
sprintf
function to first create the desired string. Floats, integers, characters, etc., are printed into this string.2. Pass this string as an argument to
System_printf
.3. Finally, don’t forget to call
System_flush
, which actually prints the string to the console window.Q: Why doesn't
System_printf
print anything?A: The
System_printf
function only puts the message into the debugger’s buffer, and it is only sent to the waiting console on the other end of the USB cable when the entire buffer is flushed at once using the System_flush
function.In your program, decide whether you want to print a line at a time immediately to the console (by calling flush after each print), or if you prefer to collect the results in the buffer and flush multiple messages at once. The latter approach is faster for program execution since you aren't constantly sending messages between the device, debugger, and console.
SensorTag Device¶
Q: Something strange is happening, but I can't figure out where in the code it's coming from...
A: There are at least three ways to troubleshoot this:
1. Use debug print statements (like
2. The debugger can be used to control the program execution literally one line at a time and inspect, for example, the variable values, allowing you to try to find the line causing the runtime error. However, sometimes the line where execution stops isn’t faulty, and in larger programs, the debug prints from point 1 can be a better way to trace the issue. Conversely, the debugger works better in cases where slow debug prints from point 1 interfere with the program’s operation.
3. You can always ask the teaching assistant in the chat or during the exercises.
1. Use debug print statements (like
System_printf
) to trace how the program execution progresses.2. The debugger can be used to control the program execution literally one line at a time and inspect, for example, the variable values, allowing you to try to find the line causing the runtime error. However, sometimes the line where execution stops isn’t faulty, and in larger programs, the debug prints from point 1 can be a better way to trace the issue. Conversely, the debugger works better in cases where slow debug prints from point 1 interfere with the program’s operation.
3. You can always ask the teaching assistant in the chat or during the exercises.
A good solution for troubleshooting code issues independently is to use both debug prints and the debugger simultaneously!
Q: Why does SensorTag freeze immediately after startup or during execution?
A: There could be several reasons:
1. The device runs out of memory. There are a couple of things you should check here.
1. The device runs out of memory. There are a couple of things you should check here.
- The stack memory for tasks might be unnecessarily large. The 2048-byte stacks for
STACKSIZE
are only really needed for displayTask as “display memory”. Often, a smaller stack like 512 / 1024 bytes is enough (STACKSIZE
must be in the form of 256*n, n>1). - The array used for collecting sensor data might be too large, especially with the MPU9250 sensor. An array of around 100 elements is already borderline... MPU9250 has 6 measurement values * 8 bytes * 100 elements.
2. A handler that takes too long to execute can cause the device to hang, as the rest of the functionality (including RTOS) cannot proceed. Move the functionality out of the handler to the task code and control execution using a state machine. Often (always), the best practice for a handler is to simply set a state change and respond to it in the tasks.
3. A forgotten
4. Components/peripherals are being used outside the task where they were initialized. A common example is trying to print to or clear the display with
3. A forgotten
Task_sleep
causes the task to run indefinitely, or there is an unnecessary long-running process in commtask
(the task used for wireless communication).4. Components/peripherals are being used outside the task where they were initialized. A common example is trying to print to or clear the display with
Display_clear
from multiple tasks. Fix this by implementing a state machine in displayTask.Q: Why are only one of the tasks being executed?
A: Most likely, the task that is being executed doesn’t have a
Task_sleep
, which prevents other tasks from getting execution time. Remember that commtask
(the task used for wireless communication) should not have a Task_sleep
call!Q: Why doesn’t the power button start SensorTag when it’s connected to the computer?
A: When the debugger is connected to the SensorTag, the device emulates standby mode. For reasons related to the debugger, the device can’t be awakened when being debugged, but you can test its functionality simply by disconnecting the debugger while the device is running. So, the power button should work when the SensorTag is connected to the computer via USB without interacting with the development environment. Also, due to the emulation, it’s recommended to use the SensorTag with a battery without the Debugger Devpack board.
Sensors¶
Q: I don’t know where to start with using sensors!
A: The use of the TMP007 temperature sensor is described in the lecture material as an example... copy & paste will get you a long way. There is an example of using the MPU9250 sensor in the project, which you can find in the students’ file sharing.
Q: I’m trying to add sensors to my program, but the compiler can’t find their library functions..
A: For sensors and other peripherals, you need to include the header file
name.h
for each sensor you are using. So, check what is in the sensors
folder of the project template.Remember to implement the functionality required by the
name_get_data
function that interprets the registers at the end of the corresponding sensor library code file.Q: Sensor initialization (in
x_setup
function) fails!A: There could be many reasons, but most often it’s because you are trying to open both I2C sensor buses at the same time. The i2c connection must always be closed before opening a new one.
Q: How can I visualize sensor data?
A: Some IDEs used for SensorTag programming even have a
Graph
feature, which you can use to create plots while debugging. In the lecture material, the project chapter also gives tips for visualizing sensor data outside the development environment. You can use programs like M$ Excel, gnuplot, Python libraries, Matlab, etc.
It’s recommended to collect the sensor data in csv format, which most programs can read directly.
Graphics and Sound¶
Q: How do I get sound from the device?
A: SensorTag has a simple component that produces beeping sounds, called a buzzer. An example code file can be found in the students’ Github. The buzzer is connected to I/O pins, so you need the same pin configurations and setups as for a button, for example. The pin configuration can be found in the CC2650STK.c file between other familiar-looking lines. After calling
buzzerOpen
, you’ll naturally need to wait, for example, with Task_sleep
, before calling buzzerClose
to let the sound play.There are plenty of examples online for playing songs with an embedded systems "ghettoblaster".
There may be a little tweaking required depending on the development environment for using the buzzer library from the students’ repository. If the compiler complains that it can’t find the
driverLib/timer.h
header file, try changing the folder path to use a lowercase or uppercase "L".Q: How can I draw images on the screen using
GrImageDraw
?A: An image is represented in bitmap format with ones and zeros, where one means the corresponding pixel is on. The graphics library and the
GrImageDraw
function will draw the image “correctly” — that is, the first row of a height * width
image is determined by the first width
bits from left to right.The lecture material includes instructions for drawing 8x8 pixel images, and there is an example of drawing larger images on the screen in the students' file sharing.
You can draw images manually, pixel by pixel, using something like Paint, and then convert the image to hexadecimal by calculating it roughly yourself, or you could create your own image editor that converts the final image to hexadecimal. Ok, there are also bitmap image editors available online...
State Machine¶
Q: I copied the state machine example from the lecture material, but now I’m getting an
expected an identifier
or some similar error.A: The material notes that the example doesn’t work as-is because of the
IDLE
state, as this constant is already used by RTOS. Consider renaming the states.Q: How can I track the state machine’s behavior in multiple tasks?
A: By using debug print statements... so log the state changes of the state machine to the console window.
Development Environment and Console¶
Q: What is a debugger?
A: In embedded systems, a debugger is usually a separate physical device and associated software that allows you to control the behavior of the microcontroller and the execution of the program on it. A debugger is a very handy tool in embedded software development and is included with all modern devices and their development environments. The SensorTag debugger is the separate circuit board between the display and the device, where the green LED is always on.
Using the debugger involves setting up breakpoints in the code. You can have multiple breakpoints in the program at the same time. A breakpoint marks positions in the code (e.g., a circle or some symbol at the line of code in the editor) where you want the program execution to stop “live.” When the program stops, the debugger has access to the state of the device, memory, (sometimes even peripherals), and so on.
In the debugger software’s panel, there are various functions for program execution, such as running the program one line at a time (e.g., ‘‘step over’’) or running the program until the next breakpoint (‘‘run’’).
Conclusion¶
The person who asks questions does not get lost.
This course only gives a very faint glimpse of C and its usage. Just enough to learn how to use it as a tool for programming embedded systems.
Give feedback on this content
Comments about this material