BBAI-64 Cortex-R5 gpio toggle experiment

Hello All,

Expanding on @Tony_Kao’s Minimal Cortex-R5 example on BBAI-64, I would like to use the R5 core to toggle a gpio pin. I have studied @benedict.hewson’s pinmux spreadsheet and read the Beaglebone cookbook but, I must admit, I am totally perplexed as to how to connect a gpio pin to the R5 core. Does anyone have some pointers as to how to make this happen?

I don’t even know if this is possible but, I expect it should be possible.

I have the A72 cores (libgpiod) toggling pin P9_14 and can see jitter. With the R5, I’m hoping for real-time io performance.

Fred Eckert

1 Like

I haven’t gotten to the point in my current project where I’m working on GPIO, so I don’t yet have a self-contained sample or even definitive references. But I figure I can provide some general pointers if it’s helpful.

On hosted Linux, the BeagleBoard crew and/or TI has configured the appropriate driver to expose available ports via userspace APIs. What those drivers do internally is perform memory accesses which map in hardware to particular I/O configuration registers. E.g., logically, there’s a memory address somewhere which you can write a “1” to and it’ll set your chosen pin to a logic-level high, or a “0” and it’ll set it low. When you ask the kernel to set the pin high, it’s just writing to the appropriate memory address.

In practice, there’s some configuration the driver needs to do to tell the pin what mode to operate in – in this case, pure digital output. Other modes include a digital input, or a more specialized function like SPI or UART. Most pins have many alternate functions they can be configured for.

So, without the Linux kernel driver in place, you’ll have to do this “register-prodding” yourself. This means checking the chip’s documentation to understand which registers need to have their values changed and what those registers’ memory addresses are.

If you leave the relevant pins in the Linux device tree, the kernel might do you a favor and pre-configure the pins so that all you have to do is set their desired output value. I’d personally avoid the race condition that presents but it’s a possibility.

At a quick glance, section of the Technical Reference Manual for the TDA4VM outlines the process of configuring a pin’s mode and setting its output state. There’s a different section which gives the actual memory addresses of the relevant registers. The process doesn’t look too bad so long as you identify the right register for your pin.

If you are looking for a simple high/low control, that’s all you need to do. If you want other types of peripherals like SPI or UART, there are other modes you’ll have to configure the pin for and more setup that has to be done. The TRM has information on that as well.

Hopefully in a week or two I’ll have at least some basic code samples that could help out here. I haven’t written for bare metal on TI processors either (only STM32s and AVRs), so I’m right there with you on deciphering the datasheets.


Kaelin, Thanks for the pointers!

I have confirmation that SoC architecture wise, all peripherals (except the ones in the Security enclave) are accessible from anywhere…

So, it sounds like we just need to do the following:

  1. Pinmux pins to gpio or other peripherals as desired.
  2. Ensure that Linux on the A72 side doesn’t touch the gpio or other peripherals that we want to use.
  3. Start bit twiddling.
  • Prereq: Map out gpio/peripherals we want to use (6.4 Pin Multiplexing*) (12.1.2 General-Purpose Interface (GPIO)**).
  • Option: Call out any firewalls if desired ( Firewalls (FW)**).)

* Reference: TDA4VM Datasheet (TDA4VM.pdf)
** Reference: J721E DRA829/TDA4VM TRM (

I recall somewhere I saw RCN say that TI hasn’t back-ported the BBAI64 into their SDK yet. So, it sounds like maybe someday in the future, we can leverage the TI SDK to configure the hardware. It sure would be nice to have something like the STM32 HAL (or LL) stuff for this… I am going to take a look at the TI SDK to see what it is all about.

Best regards,

1 Like

If TI has an official evaluation SDK for bare metal (or RTOS), that would be great; it would give all the needed info and some sample code for less effort.

At a glance it looks like this is what they have: PROCESSOR-SDK-J721E Software development kit (SDK) |

The “PROCESSOR-SDK-RTOS-J721E” looks like the right one.

I haven’t taken a look yet but it probably has the important bits fairly separate from their RTOS stuff.

There is a lot of code in there, including low level drivers and a FreeRTOS port. There are also some examples both for FreeRTOS and baremetal. Building everything takes a while.

However using the code in your own project is not as easy as I would like. As far as I can see there is no way to include the SDK into Code Composer to make building your own projects with the drivers easier. I suppose as long as you can build libraries, they can just be included. I have been a bit busy with other things lately and not had as much time to investigate this as I would like.

Found the physical address for GPIO0_93 (pin 9_14):

#Toggle GPIO0_93 pin 9_14 using devmem2 on Linux side:
#set  - write GPIO0 GPIO_SET_DATA45 bit 29
sudo devmem2 0x00600068 w 0x20000000
#clear - write GPIO0 GPIO_CLR_DATA45 bit 29
sudo devmem2 0x0060006C w 0x20000000

At first look, It seems like the physical address is not mapped 1:1 into the R5. Will need to investigate a bit more.

TDA4VM TRM References for further investigation:

  • 6.3 Dual-R5F MCU Subsystem
  • 8.4 Region-based Address Translation (RAT) Module
1 Like

Got it working!! Tony’s example didn’t map the entire 4G address space. Once it was mapped, the code worked.

    #define DELAY 44
    uint64_t* pSet = 0x00600068;
    uint64_t* pClr = 0x0060006C;
        //set the output high
        *pSet = 0x20000000;
        for(volatile int i=0; i< DELAY; i++);
        //set the output low
        *pClr = 0x20000000;
        for(volatile int i=0; i< DELAY; i++);

Stable square wave:

Max jitter:


Just popping in again to mention another thing that occurred to me. One of the resources you can request in your remoteproc resource table is a VirtIO device, using the same mechanism as a virtual machine would use to access host resources. I haven’t done any investigation into which kinds of devices are supported or how they work, but there is a VirtIO device type for GPIO. It surely wouldn’t support all the kinds of I/O configurations, but it might be a cleaner way of doing I/O if all you need are the “simpler” ones.

Edit: also, there’s a latency effect involved which would need to be considered. Certainly, you lose a lot of the “real-time ness” of the R5 cores if they’re going through the host kernel every time they want to do I/O.

Also, @FredEckert, what mechanism did you use to map the additional 2G segment via RAT?

Complete 32-bit address space mapping concept came right from TI’s example:


I uploaded an r5_toggle branch into my fork:


1 Like