Blink
This guide will walkthrough the native compilation of a Blink executable for the phyCORE-AM64x Development Kit running Linux. This demo will blink an LED connected to GPMC0_AD3 processor pad, which is accessible at pin 8 of the X27 Expansion Connector (with net name X_GPMC0_AD3/BM_3/FSI_RX2_CLK/UART3_RX/GPIO0_18). In order for this demo to work properly we will also need to dive into configuring processor pins and the best reference for that is the Technical Reference Manual (TRM) and Datasheet for the AM64x processor, which can be downloaded from the Texas Instruments AM62Ax product page.
Note
This guide leverages build tools on the target (native compilation). These are not installed by default and must be first added to the target software. Checkout the Hello World guide for steps on adding this support.
Create the Blink Program
Let’s make a project directory to contain the Blink source code:
Target (Linux)
mkdir ~/blink-project
cd ~/blink-project
Create the main Blink application source code file using your favorite text editor:
Target (Linux)
vi blink.c
Note
The vi text editor begins in “Command Mode” and you must first hit the ‘i’ key in order to enter “Insert Mode”. Using the arrow keys to navigate, make the necessary changes and then hit ESC to go back to “Command mode”. Now enter “:wq” to write the file and quit.
Pro Tip: Use the right click on your mouse to paste! This will only work if you are in “Insert Mode” first.
Edit the contents of the file to reflect the following and remember to save your changes when you are done!
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
// Setup GPIO0_18
#define GPIO0_ADDR_START 0x000600000
#define GPIO0_ADDR_END 0x0006000FF
#define GPIO0_SIZE (GPIO0_ADDR_END - GPIO0_ADDR_START)
#define GPIO0_PORT (1 << 18)
#define GPIO_DATA_OFFSET 0x000000018
#define GPIO_DIR_OFFSET 0x000000010
#define GPIO_CLEAR_OFFSET 0x00000001C
void *gpioAddress;
unsigned int *gpio_setdataout_addr;
unsigned int *gpio_direction_addr;
unsigned int *gpio_cleardata_addr;
void delay(unsigned long ms)
{
clock_t start_ticks = clock();
unsigned long millis_ticks = CLOCKS_PER_SEC / 1000;
while (clock() - start_ticks < ms * millis_ticks){}
}
int main()
{
int fd = open("/dev/mem", O_RDWR);
gpioAddress = mmap(0, GPIO0_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO0_ADDR_START);
close(fd);
gpio_setdataout_addr = gpioAddress + GPIO_DATA_OFFSET;
gpio_direction_addr = gpioAddress + GPIO_DIR_OFFSET;
gpio_cleardata_addr = gpioAddress + GPIO_CLEAR_OFFSET;
*gpio_direction_addr &= ~(GPIO0_PORT);
while (1)
{
*gpio_setdataout_addr |= GPIO0_PORT;
delay(1000);
*gpio_cleardata_addr |= GPIO0_PORT;
delay(1000);
}
}
Compile the project using the GCC toolchain, which you had to manually add to the phytec-headless-image. See the Hello World guide for more nformation.
Target (Linux)
gcc -O blink.c -o blink
You should now see an executable of the name “blink” in the current working directory.
Mux the Processor Pin
In order for this blink executable to work as intended, we will also need to multiplex (AKA mux) the processor pad such that the GPIO0_18 signal is enabled and configured as an output on the GPMC0_AD3 processor pad. We can do this easily using the ‘devmem2’ utility to directly access nd modify the AM64x hardware registers.
Warning
Use caution when working with the ‘devmem2’ utility as it gives you direct access to read and write to memory that could render the system unstable if you modify memory that is being actively used. This utility has no error checking and shouldn’t be relied upon in production software. PHYTEC recommends working with ‘devmem2’ only while prototyping and transitioning your pin settings to the linux device tree for production.
First, identify the processor pad that brings out the signal we are targeting. This can be done by following X_GPMC0_AD3/BM_3/FSI_RX2_CLK/UART3_RX/GPIO0_18 in the carrier board schematic back to the SOM and to the AM64x processor itself. You should find that this signal is accessible at the processor ball number U20, named GPMC0_AD3.
Looking up the GPMC0_AD3 processor pad within the AM64x Datasheet, we can see that this pad is configured within the PADCONFIG18 register which has the memory address 0x000F4048.
We can read this register like so:
Target (Linux)
devmem2 0x000F4048
We should see the following output by default:
Example Output
root@phyboard-electra-am64xx-2:~# devmem2 0x000F4048 /dev/mem opened. Memory mapped at address 0xffff9fc5f000. Read at address 0x000F4048 (0xffff9fc5f084): 0x00254007
The value held in the PADCONFIG18 memory address is 0x00254007, which can be broken down according to the PADCONFIG18 Register Field Descriptions within the TRM (see Table 5-77). Here we can see that the register is in its reset state and is configured as an input, without any internal pull up/down resistors, schmitt trigger enabled, and mux mode 7 which is GPIO0_18, per the Datasheet. This is the mux mode we want but we will need to configure the pad as an output in order to drive an LED.
Modify the PADCONFIG18 register in order to configure the GPMC0_AD3 as the desired GPIO mux mode we need (GPIO0_18):
Target (Linux)
devmem2 0x000F4048 w 0x00010007
Writing the value 0x00010007 to PADCONFIG18 effectively changes the pad config settings, giving us the signal we want in the mode we need.
Run the Blink Program
Once you have the blink executable built and the processor pin is correctly multiplexed to bring out the signal GPIO0_18 as an output, we can connect up an LED to X_GPMC0_AD3/BM_3/FSI_RX2_CLK/UART3_RX/GPIO0_18 and blink it!
Reference the following circuit diagram to help you connect up an LED to pin 8 of the X27 Expansion Connector on the phyCORE-AM64x Development Kit carrier board:
Now run the blink executable and watch the LED blink on and off!
Target (Linux)
./blink
To end the program, use Ctrl + C.