Skip to main content
By the end of this section, you will gain knowledge and experience in the following topics.
  • Compiling Texas AM67 MCU software and running it on the Gemstone O1
  • Learning the stages the system goes through when the development board is first powered on
  • Gaining awareness that software can run concurrently on the different architectures present on the development board, namely Cortex-A (Linux) and Cortex-R (MCU)
While the primary focus of the T3-GEM-O1 development board is Linux, it also leverages the power of the R5 and C7x cores housed within the Texas AM67 microprocessor. For example, it is possible to perform various image processing tasks on Linux (Cortex-A) and transfer these to MCU (Cortex-R5) software, enabling scenarios such as driving various servos, reading sensors, etc. This section will cover topics such as how to compile software for the R5 cores, debugging, etc.

1. Boot Diagram

The flow chart specified below is for the Gemstone O1 development board, but a similar structure is found in many ARM-based embedded Linux development boards.

1.1. ROM Bootloader (RBL)

The primary purpose of the RBL (ROM Bootloader), which is often distributed only as a compiled program without source code by manufacturers, is to perform hardware health checks and initialization etc., when the board is first powered on, and then transition to the second bootloader called SBL (Secondary Bootloader), whose source code can be modified. Where the SBL is read from and started is determined by the RBL from the Bootmode switches.

1.2. Secondary Bootloader (SBL)

The purpose of the Secondary Boot Loader on T3-GEM-O1 development boards is to start the more advanced bootloader called U-Boot and to enable writing images to eMMC via the Gemstone Imager application. U-Boot is often preferred in embedded boards containing the Linux Kernel. While pre-loaders like SBL can perform more basic level initialization operations, U-Boot has much more advanced features. For example, U-Boot has its own Terminal/Console interface and many drivers not available in SBL, allowing for more advanced customizations.

1.3. U-Boot

U-Boot, which takes control of the development board after SBL, activates the drivers of the relevant hardware according to the configurations defined in the Device Tree and executes a set of predefined commands to load components like the Linux Kernel and Initrd into RAM, handing over control to the Linux Kernel.

1.3.1. U-Boot Console Exercises

This section demonstrates the use of the U-Boot console by connecting to the Gemstone development board via TTL. You can quickly browse the documents below.

U-Boot Console

1.4. Linux Kernel

It loads the drivers for the hardware defined in the Device Tree. Then, if any, it starts the initrd/initramfs and runs the init program found in the rootfs.
The Device Tree files for U-Boot and the Linux kernel are different from each other. The devicetree in U-Boot typically only activates enough hardware to load the kernel and initramfs from various storage devices (MMC, SSD, SPI flash, …) into RAM. The main hardware activation is done by the kernel.

1.5. Initial RAM Disk (Initrd)

It is a temporary filesystem located in RAM that performs intermediate tasks such as loading various kernel modules, decrypting the disk, performing software updates, etc., before the rootfs is started.
If the rootfs is stored encrypted on the disk, the kernel cannot directly start the init program. First, the disk encryption must be decrypted by the initramfs.

1.6. Root Filesystem (Rootfs)

After the initrd finishes its operations, it mounts the filesystem called rootfs, which contains system and user programs, libraries, and various configuration files, to the / directory. Then the kernel runs the init program located in the rootfs at /init, /sbin/init, or a similar directory. This program loads drivers for some hardware (kernel modules), system services (services such as network connection, time synchronization, package update, and bluetooth) and starts the desktop environment (gnome, kde, xfce).

2. MCU Software Development

The tools required to compile MCU projects are listed below.
  1. Texas Instruments Processor SDK RTOS J722S
  2. Texas Instruments Sysconfig
  3. Texas Instruments Code Generation Tools C7000
  4. Texas Instruments Code Generation Tools ARM LLVM
Since downloading these tools one by one from the Texas Instruments website and performing their installations is cumbersome, an infrastructure has been set up in the t3gemstone/examples repo to download all the necessary tools and compile MCU projects. It is installed automatically when you clone the project.

2.1. Download the sample projects with Git clone

ubuntu@host:~$ git clone https://github.com/t3gemstone/examples.git
ubuntu@host:~$ cd examples

2.2. Install the necessary tools and libraries for compilation

ubuntu@host:examples$ ./setup.sh
ubuntu@host:examples$ devbox shell
ubuntu@host:examples$ task fetch-ti

2.3. Create a template project

The mcu project in the t3gemstone/examples repo contains sample projects running on two R5F real-time cores and two C7x DSP cores. Similar examples can be found in the build/ti/ti-processor-sdk-rtos-j722s-evm-10_01_00_04/mcu_plus_sdk_j722s_10_01_00_22/examples directory. It is recommended to find an example project suitable for your purpose, copy it to the mcu project directory, and develop on it. Under each sample project, there are subdirectories for different cores. For example, the hello_world project has the following directories.
  1. c75ss0-0_freertos
  2. c75ss1-0_freertos
  3. main-r5fss0-0_freertos
  4. mcu-r5fss0-0_freertos
The code to be written should be developed in the directory of the core on which it is intended to run, and the compiled outputs from that directory should be used. The MCU projects to be compiled are defined as the MCU_TARGETS variable in the .env file. Add the absolute or relative path of the makefile directory of the project you want to compile to the MCU_TARGETS variable. Below is an example for the mcu-r5fss0-0_freertos core of the hello_world project.
MCU_TARGETS="
ipc_rpmsg_echo_linux/j722s-evm/c75ss0-0_freertos/ti-c7000
ipc_rpmsg_echo_linux/j722s-evm/c75ss1-0_freertos/ti-c7000
ipc_rpmsg_echo_linux/j722s-evm/main-r5fss0-0_freertos/ti-arm-clang
ipc_rpmsg_echo_linux/j722s-evm/mcu-r5fss0-0_freertos/ti-arm-clang
hello_world/j722s-evm/mcu-r5fss0-0_freertos/ti-arm-clang
"

2.4. Configure peripherals with SysConfig

SysConfig is a configuration tool developed by Texas Instruments (TI). It is used in TI’s microcontroller (MCU) and processor-based development environments. Its main purpose is to allow the configuration of hardware and software settings visually. Instead of writing complex initialization code directly, it allows system configuration via a GUI by clicking options. Main features:
  • Pin Muxing: Determines which pin will serve which function (UART, SPI, GPIO, etc.).
  • Peripheral Settings: Configures peripherals like UART, I2C, Timer, ADC.
  • Driver and RTOS configuration: Enables TI-Drivers or FreeRTOS components.
  • Automatic Code Generation: Automatically generates C source files (.c, .h) based on the settings made.
  • Error prevention: Detects inappropriate pin or module combinations and warns.
Which peripherals (GPIO, I2C, UART, etc.) the project uses and their configuration are defined in the .syscfg file. The SysConfig GUI tool is used to add new peripherals or change the Pin Mux settings of existing ones.
Before using the SysConfig GUI tool, read the Sharing Resources Between Cores section to correctly allocate resources and avoid unexpected errors.
To launch SysConfig for an MCU project:
  • Change the SYSCONFIG_TARGET variable to the desired project.
    • You can edit this variable inside the .env file or
    • Pass it as an environment variable to the task program.
SYSCONFIG_TARGET=hello_world/j722s-evm/mcu-r5fss0-0_freertos/ti-arm-clang task sysconfig
After saving your changes with the Ctrl + S shortcut key, you can close the SysConfig interface.
The remoteproc infrastructure is used to allow remote software loading to the R5F and C7x cores from the Linux side. For a project’s compiled .out file to be loadable via remoteproc, certain settings must be made in the SysConfig interface. After copying a new project, the following steps should be followed.
  1. Open the IPC tab under TI DRIVERS.
  2. Click the ADD button.
  3. Ensure the Linux A53 IPC RP Message setting is active.
  4. Save the .syscfg file with the Ctrl + S shortcut key and exit.

2.5. Build the project

ubuntu@host:examples$ PROJECT=mcu task clean build

2.6. Upload the compiled project to the development board

ubuntu@host:examples$ scp mcu/hello_world/j722s-evm/mcu-r5fss0-0_freertos/ti-arm-clang/hello_world.release.out gemstone@10.0.0.1:

2.7. Run the compiled project

The .out files to be loaded to the cores via Remoteproc must be copied under the /lib/firmware directory with predefined names. The firmware name for each core is given in the table below.
CoreFirmware
mcu-r5fss0-0j722s-mcu-r5f0_0-fw
main-r5fss0-0j722s-main-r5f0_0-fw
c7xss0-0j722s-c71_0-fw
c7xss1-0j722s-c71_1-fw
The firmware names and which core corresponds to which remoteproc device can be accessed with the head /sys/class/remoteproc/remoteproc*/firmware command. This needs to be checked because after each boot, the cores can correspond to different remoteproc devices.
The above procedure ensures a clean shutdown and restart of the remote cores. In some cases, the clean shutdown process may fail. In this case, we recommend the following steps:
  1. Place the new firmware files in the /lib/firmware directory.
  2. Reboot the board.
Upon system startup, the remoteproc mechanism will automatically load the firmwares to the relevant cores.Note: This approach is particularly useful in the following situations:
  • When core crashes occur
  • When IPC communication is interrupted
  • When unexpected behavior is observed during dynamic loading

2.8. Running the Compiled Project at the U-Boot Stage

As seen in the diagram in the Boot Diagram section, when using the execution method described in the previous section, for the MCU application to run, Linux must complete its startup process and load and start the core software. This process can cause unwanted delays in some applications. This delay can be prevented by starting the remote cores at the bootloader (U-Boot) stage.
  1. First, the compiled application is copied to the /boot/mcu-fw/ directory.
  2. In the /boot/uEnv.txt file, the necessary parameter is defined using the table below, depending on which core the compiled application belongs to.
CoreVariable Name
main-r5fss0-0main_r5f_firmware_name
mcu-r5fss0-0mcu_r5f_firmware_name
wkup-r5fss0-0wkup_r5f_firmware_name
c7xss0-0c7x0_dsp_firmware_name
c7xss1-0c7x1_dsp_firmware_name
For example, when an application named blink_main_r5 is desired to run on the main-r5fss0-0 core at the U-Boot stage, first the application is copied to the /boot/mcu-fw directory as shown below.
gemstone@t3-gem-o1:~$ ls /boot/mcu-fw/
total 102K
drwxr-xr-x 2 root root  512 Jan  1  2000 ./
drwxr-xr-x 4 root root 1.0K Jan  1  1970 ../
-rwxr-xr-x 1 root root 101K Jan  1  2000 blink_main_r5*
Then, the following line is added to the /boot/uEnv.txt file.
main_r5f_firmware_name=blink_main_r5
Now the blink_main_r5 application will be started directly at the bootloader stage, without waiting for Linux to start.

3. Sharing Resources Between Cores

Due to the AM67 being a multi-core processor, the resources it possesses must be shared among these cores. For example, the main_uart1 uart peripheral cannot be used simultaneously by both Linux (A53 cores) and the main-r5fss0-0 core. If this UART peripheral is to be used by the MCU, it must be indicated that it is not used by Linux.

3.1. Default Resource Allocation Table

The table below provides information such as which SOC pins the pins on the HAT correspond to, which peripherals they can be used as (Pinmux), whether they are used by default by Linux, if so for what purpose, and how this can be disabled.
HAT Pin NameSoC Pin NamePinmuxEnabled in Linux by Default?Purpose in LinuxHow to Disable
GPIO-0D110 → WKUP_I2C0_SDA
7 → MCU_GPIO0_20
YesI2C SDA for communication with EEPROM, RTC, and PMICMust be disabled via Device-tree (wkup_i2c0).
GPIO-1B90 → WKUP_I2C0_SCL
7 → MCU_GPIO0_19
YesI2C SCL for communication with EEPROM, RTC, and PMICMust be disabled via Device-tree (wkup_i2c0).
GPIO-2E110 → MCU_I2C0_SDA
7 → MCU_GPIO0_18
NoI2C SDA for Waveshare Touchscreen- k3-am67a-t3-gem-o1-dsi-waveshare-7inch-h-panel.dtbo
- k3-am67a-t3-gem-o1-dsi-waveshare-7inch-panel.dtbo
GPIO-3B130 → MCU_I2C0_SCL
7 → MCU_GPIO0_17
NoI2C SCL for Waveshare Touchscreen- k3-am67a-t3-gem-o1-dsi-waveshare-7inch-h-panel.dtbo
- k3-am67a-t3-gem-o1-dsi-waveshare-7inch-panel.dtbo
GPIO-4W260 → GPMC0_WAIT1
1 → VOUT0_EXTPCLKIN
2 → GPMC0_A21
3 → UART6_RXD
4 → AUDIO_EXT_REFCLK2
7 → GPIO0_38
8 → EQEP2_I
YesUART RX for Bluetooth- k3-am67a-t3-gem-o1-uart-ttys6.dtbo
- Must be disabled via Device-tree (main_uart6)
GPIO-5B200 → SPI0_CS0
2 → EHRPWM0_A
7 → GPIO1_15
NoGeneral Purpose PWM- k3-am67a-t3-gem-o1-pwm-epwm0-gpio5.dtbo
- k3-am67a-t3-gem-o1-pwm-epwm0-gpio14.dtbo
- k3-am67a-t3-gem-o1-pwm-epwm0-gpio5-gpio14.dtbo
GPIO-6D200 → SPI0_CLK
1 → CP_GEMAC_CPTS0_TS_SYNC
2 → EHRPWM1_A
7 → GPIO1_17
YesGeneral Purpose PWM- k3-am67a-t3-gem-o1-pwm-epwm1-gpio6.dtbo
- k3-am67a-t3-gem-o1-pwm-epwm1-gpio13.dtbo
- k3-am67a-t3-gem-o1-pwm-epwm1-gpio6-gpio13.dtbo
GPIO-7B30 → WKUP_UART0_RXD
2 → MCU_SPI0_CS2
7 → MCU_GPIO0_9
Yes- SPI Chip Select 2 for Linux spidev
- Wakeup Domain UART0 Rx
- k3-am67a-t3-gem-o1-spidev0-1cs.dtbo
- k3-am67a-t3-gem-o1-spidev0-2cs.dtbo
- k3-am67a-t3-gem-o1-uart-ttys0.dtbo
GPIO-8C120 → MCU_SPI0_CS0
4 → WKUP_TIMER_IO1
7 → MCU_GPIO0_0
YesSPI Chip Select 0 for Linux spidev- k3-am67a-t3-gem-o1-spidev0-1cs.dtbo
- k3-am67a-t3-gem-o1-spidev0-2cs.dtbo
GPIO-9C110 → MCU_SPI0_D1
7 → MCU_GPIO0_4
Yes- SPI DATA1 for BMP390 Pressure Sensor and ICM20948 IMU
- SPI DATA1 for Linux spidev (configurable as MOSI or MISO)
Must be disabled via Device-tree (mcu_spi0).
GPIO-10B120 → MCU_SPI0_D0
7 → MCU_GPIO0_3
Yes- SPI DATA0 for BMP390 Pressure Sensor and ICM20948 IMU
- SPI DATA0 for Linux spidev (configurable as MOSI or MISO)
Must be disabled via Device-tree (mcu_spi0).
GPIO-11A90 → MCU_SPI0_CLK
7 → MCU_GPIO0_2
NoSPI Clock for Linux spidevMust be disabled via Device-tree (mcu_spi0).
GPIO-12C200 → SPI0_CS1
1 → CP_GEMAC_CPTS0_TS_COMP
2 → EHRPWM0_B
3 → ECAP0_IN_APWM_OUT
5 → MAIN_ERRORn
7 → GPIO1_16
9 → EHRPWM_TZn_IN5
YesGeneral Purpose PWM- k3-am67a-t3-gem-o1-pwm-ecap0-gpio12.dtbo
GPIO-13E190 → SPI0_D0
1 → CP_GEMAC_CPTS0_HW1TSPUSH
2 → EHRPWM1_B
7 → GPIO1_18
YesGeneral Purpose PWM- k3-am67a-t3-gem-o1-pwm-epwm1-gpio13.dtbo
- k3-am67a-t3-gem-o1-pwm-epwm1-gpio6-gpio13.dtbo
GPIO-14F240 → MCASP0_ACLKR
1 → SPI2_CLK
2 → UART1_TXD
6 → EHRPWM0_B
7 → GPIO1_14
8 → EQEP1_I
Yes- Used as Linux serial device /dev/ttyS3.
- Can be configured as General Purpose PWM via overlay.
- k3-am67a-t3-gem-o1-pwm-epwm0-gpio5.dtbo
- k3-am67a-t3-gem-o1-pwm-epwm0-gpio14.dtbo
- k3-am67a-t3-gem-o1-pwm-epwm0-gpio5-gpio14.dtbo
- Must be disabled via Device-tree (main_uart1).
GPIO-15C270 → MCASP0_AFSR
1 → SPI2_CS0
2 → UART1_RXD
6 → EHRPWM0_A
7 → GPIO1_13
8 → EQEP1_S
Yes- Used as Linux serial device /dev/ttyS3.Must be disabled via Device-tree (main_uart1).
GPIO-16A250 → MCASP0_AXR3
1 → SPI2_D0
2 → UART1_CTSn
3 → UART6_RXD
5 → ECAP1_IN_APWM_OUT
7 → GPIO1_7
8 → EQEP0_A
NoGeneral Purpose PWM- k3-am67a-t3-gem-o1-pwm-ecap1-gpio16.dtbo
GPIO-17A260 → MCASP0_AXR2
1 → SPI2_D1
2 → UART1_RTSn
3 → UART6_TXD
5 → ECAP2_IN_APWM_OUT
7 → GPIO1_8
8 → EQEP0_B
YesUART TX for Bluetooth- k3-am67a-t3-gem-o1-uart-ttys6.dtbo
- Must be disabled via Device-tree (main_uart6).
GPIO-18D250 → MCASP0_ACLKX
1 → SPI2_CS1
2 → ECAP2_IN_APWM_OUT
7 → GPIO1_11
8 → EQEP1_A
NoGeneral Purpose PWM- k3-am67a-t3-gem-o1-pwm-ecap2-gpio18.dtbo
GPIO-19C260 → MCASP0_AFSX
1 → SPI2_CS3
2 → AUDIO_EXT_REFCLK1
7 → GPIO1_12
8 → EQEP1_B
No--
GPIO-20F230 → MCASP0_AXR0
2 → AUDIO_EXT_REFCLK0
6 → EHRPWM1_B
7 → GPIO1_10
8 → EQEP0_I
No--
GPIO-21B250 → MCASP0_AXR1
1 → SPI2_CS2
2 → ECAP1_IN_APWM_OUT
5 → MAIN_ERRORn
6 → EHRPWM1_A
7 → GPIO1_9
8 → EQEP0_S
YesCooling Fan Control- k3-am67a-t3-gem-o1-gpio-fan.dtbo
GPIO-22R270 → GPMC0_CSn0
1 → I2C4_SCL
3 → MCASP2_AXR14
6 → TRC_DATA15
7 → GPIO0_41
No--
GPIO-23B50 → MCU_UART0_CTSn
1 → MCU_TIMER_IO0
3 → MCU_SPI1_D0
7 → MCU_GPIO0_7
No--
GPIO-24C80 → WKUP_UART0_TXD
2 → MCU_SPI1_CS2
8 → MCU_GPIO0_10
NoWake Up Domain UART0 Tx- k3-am67a-t3-gem-o1-uart-ttys0.dtbo
GPIO-25P210 → GPMC0_CSn1
1 → I2C4_SDA
3 → MCASP2_AXR15
6 → TRC_DATA16
7 → GPIO0_42
No--
GPIO-26P260 → GPMC0_BE1n
3 → MCASP2_AXR12
6 → TRC_DATA11
7 → GPIO0_36
No--
GPIO-27N220 → GPMC0_OEn_REn
2 → MCASP1_AXR1
6 → TRC_DATA8
7 → GPIO0_33
No--
Look at the column named To Disable for the pin to be disabled. The files listed in this column as k3-am67a-t3-gem-o1-xxxxxx.dtbo are called device-tree overlay files, which inform Linux how to use the specified peripheral. To disable the relevant settings, open the /boot/uEnv.txt file and remove this file from the variable named overlays. For some pins, the To Disable column contains instructions other than overlays, such as Must be disabled via Device-tree. (mcu_spi0). To disable these;
  • Clone the https://github.com/t3gemstone/devicetrees repo.
  • Open the src/arm64/ti/k3-am67a-t3-gem-o1.dts file and add the following code snippet with the necessary modifications.
    &mcu_spi0 {
      status = "disabled";
    };
    
  • Run the make command in the repo directory to compile the device-tree.
  • Back up the old device-tree with the command $ sudo mv /boot/k3-am67a-t3-gem-o1.dtb /boot/k3-am67a-t3-gem-o1.dtb.bak.
  • Copy the resulting src/arm64/ti/k3-am67a-t3-gem-o1.dtb file from the compilation to /boot/.
  • Reboot the board and test if it works.
If an undesirable situation occurs as a result of the above operations, the backed-up device-tree can be restored with the command $ sudo cp /boot/k3-am67a-t3-gem-o1.dtb.bak /boot/k3-am67a-t3-gem-o1.dtb.
As a result of the above operations, mcu_spi0 will now be available for use by the mcu cores. However, the Usage Purpose in Linux section in the table indicates that it is - Used for BMP390 pressure and ICM20948 imu spi. Therefore, access to these peripherals from Linux will be closed and they will need to be driven by the MCU.

3.2. Example Scenario: Driving a Servo Motor from the MCU with PWM

In a scenario where we need to drive an SG90 model servo motor from an MCU core, we must first select a PWM pin on the HAT pins. For example, let’s select the GPIO-12 pin. Looking at the table, we can see that this pin is in use by Linux. To disable this pin in Linux, when we look at the To Disable column, we see that there is only one overlay file. To disable it, we open the /boot/uEnv.txt file and check the overlays variable.
overlays=k3-am67a-t3-gem-o1-i2c1-400000.dtbo k3-am67a-t3-gem-o1-pwm-ecap0-gpio12.dtbo k3-am67a-t3-gem-o1-pwm-epwm1-gpio13.dtbo k3-am67a-t3-gem-o1-spidev0-2cs.dtbo
Here we can see the name of the k3-am67a-t3-gem-o1-pwm-ecap0-gpio12.dtbo file specified in the table. We delete it, and the overlays variable becomes as follows.
overlays=k3-am67a-t3-gem-o1-i2c1-400000.dtbo k3-am67a-t3-gem-o1-pwm-epwm1-gpio13.dtbo k3-am67a-t3-gem-o1-spidev0-2cs.dtbo
When the board is rebooted, this pin can be controlled by the MCU.

4. Conclusion

A few example articles about the boot process are given below.