Run a simple C/C++ code on Jetson TK1

Hi,

I have a Jetson TK1 board and I want to independently run a simple C/C++ code on a single core of Cortex A15 processor. I have Ubuntu on the Jetson TK1 board. Seems to me, there are two options.

First, compile the code on the Ubuntu (on the board), and try to reserve one core for one process (the code) and the remaining cores for Ubuntu. Question: How can I do this? Any tutorial or example?

Second, try to run a bare metal code as usually done on a embedded microcontroller. At the moment, I have compiled my code on Eclipse (Windows Platform) using GNU ARM Compiler. Question: How can I flash the code on the Jetson board (single core of A15 processor)? Is it possible to do it through the micro-usb on the jetson board? Any Suggestion of tools for that?

Note: I heard the term of Bootloader for this purpose but I have no idea how it works. Any suggestions (tutorial or example) for that?

Thank you.

You might want to look at the “taskset” command for affinity.

Jetson is not a “standard” microcontroller, it is actually a very advanced full computer that happens to be physically small and low power use. Understand that bare metal coding applies to a boot loader, and cross compile tool chains generally indirectly name this as what they are designed for; cross compile tool chains which have a kernel to run them are usually specifically named with something like “linux-arm-gnueabihf…”. Linux for running under linux, arm for the cpu type, gnueabi for linux calling conventions version “e”, “hf” for hard float calling convention. The boot loader will run from a bare metal version, the kernel can run from either bare metal or not (but almost always runs the gnueabihf), and everything which runs under the operating system must run gnueabihf, not bare metal.

Making code run on a single core (core affinity) is unrelated to the flash process. Whatever is in your sample rootfs at the time of flash gets put onto the root file system of Jetson. If you have a program built as a kernel driver to use a single core, and put that driver into the kernel that is flashed, you get what you want; or if your sample rootfs contains the right taskset command during init, you also get what you want.

Boot loader is just the software which Jetson hardware hands off to after hardware is capable of giving control to something else. Nothing runs in the boot loader unless it is manually set up, e.g., you can’t even use the eMMC memory or RAM without something setting it up in some minimal way; the boot loader does this. When the environment is capable of being accessed then the boot loader begins kernel load, which is where all the nice “automated” abilities begin (e.g., in “C” language a local variable is automatically allocated, but even when “C” is used in a boot loader, allocation of the same local variable would need manual allocation).

Perhaps a more functional description for the boot loader is made by comparing desktop motherboards to embedded systems. Desktop systems generally have a BIOS (or something more modern) which has an ability to detect various hardware and provide a uniform interface to report that information to the kernel and boot loader. Since there are a large number of removable slots in a desktop, this is rather important. This also takes up a lot of physical space on the motherboard, along with memory. When you compare to an embedded system there is no BIOS (or equivalent) for embedded. In order for the embedded system to hand off to the kernel the boot loader itself must be hard coded to know about the hardware onboard and report it to the kernel (but since there are very few removable slots on embedded this doesn’t matter). Boot loader plus BIOS or hard coded information hands off to kernel and then boot loader goes away. The kernel understands both bare metal and gnueabihf and is the adapter between bare metal and an operating system.

Thank you for the detailed explanation. A lot of things have been clarified for me. Let me provide some more specific details regarding my issue. I am realizing a certain algorithm and would like to use the Neon Accelerator inside the A15 to benchmark it. Using “taskset” assigns my code (or process) to one core, however, other processes can also be scheduled on that core. Would this affect the benchmark process of the algorithm? Would the clock cycles required to execute the algorithm remain unaffected if I use “taskset” to define the CPU affinity?

Also, is it possible to run my algorithm without the Ubuntu 14.04 being pre-empting it?

Moreover, seems to me, U-boot is one of the bootloaders for the Jetson board. Could you provide some hints to how I can use U-boot to modify the parameters?

Regards.

Your single threaded benchmark will not be affected in any measurable way while the three remaining cores in principle runs idle.

Assigning to a single core does not eliminate other processes from going there. It does give you a much higher likelihood of achieving what you want.

Adjustment of pre-empting would require the fast IRQ (FIRQ) mode, which would basically be an RT (real time) linux o/s issue and not achievable under standard L4T without a nearly complete kernel rewrite. This does not mean that there are not “good but less than perfect” alternatives (as long as this is not something critical like a flight control or medical system other methods may be sufficient). Explained further down.

U-boot is a useful way to pass kernel parameters at boot. Just like your basic command line programs which allow you to add an argument to a program, the same is possible under u-boot. The real question is whether the kernel has an option to do what you want. Examples of a typical parameter are naming the root mount partition or the default console device. So it becomes a question of researching kernel parameters (I am unaware of kernel command line parameters for adjusting real-time behavior).

With regards to your goals, what you are interested in is the general topic of scheduling and schedule priorities. Without FIRQ, you cannot truly stop your core of interest from being pre-empted. What you can do is tweak scheduling. The priority of your process could be maxed out, and “mostly” other processes using that core would not get in the way. The “nice” level determines this, where default is 0, lowest priority is 20, and highest priority is -20. See “man nice”, and run this only after your process is tied to a particular core. Nice is not without its issues though, as there is a lot going on where your own process may invoke other requirements, and if that other requirement is too low of a priority, it is possible to actually force the original process to wait for another process which won’t occur because priorities are now inverted. When testing nice levels, you may want to start with something limited like renice to -5, and not going extreme.

@JensM mentioned something which would also help, making sure your system is forced into performance mode so other cores won’t sleep or slow down. See:
http://elinux.org/Jetson/Performance#Maximizing_CPU_performance
http://elinux.org/Jetson/Performance#Controlling_GPU_performance