Blink
This guide will walkthrough the native compilation of a Blink executable for the phyCORE-AM57x Development Kit running Linux. This demo will blink an LED connected to mmc3_dat0 processor pad, which is accessible at pin 29 of the X26 Expansion Connector (with net name X_MMC3_DAT0). 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 AM57x processor, which can be downloaded from the Texas Instruments AM57x 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!
blink.c
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
// Setup gpio6_31 (NET X_MMC3_DAT0)
#define GPIO6_ADDR_START 0x4805D000
#define GPIO6_ADDR_END 0x4805DFFF
#define GPIO6_SIZE (GPIO6_ADDR_END - GPIO6_ADDR_START)
#define GPIO6_PORT (1 << 31)
#define GPIO_DATA_OFFSET 0x00000013C
#define GPIO_DIR_OFFSET 0x000000134
#define GPIO_CLEAR_OFFSET 0x000000190
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, GPIO6_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO6_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 &= ~(GPIO6_PORT);
while (1)
{
*gpio_setdataout_addr |= GPIO6_PORT;
delay(1000);
*gpio_cleardata_addr |= GPIO6_PORT;
delay(1000);
}
}
Compile the project using the GCC toolchain, which you had to manually add to the phytec-qt5demo-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 gpio6_31 signal is enabled and configured as an output on the mmc3_dat0 processor pad. We can do this easily using the ‘devmem2’ utility to directly access nd modify the AM57x 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_MMC3_DAT0 in the carrier board schematic back to the SOM and to the AM57x processor itself. You should find that this signal is accessible at the processor ball number AC7, named mmc3_dat0.
Looking up the mmc3_dat0 processor pad within the AM57x Datasheet, we can see that this pad is configured within the CTRL_CORE_PAD_MMC3_DAT0 register which has the memory address 0x4A003784.
We can read this register like so:
Target (Linux)
devmem2 0x4A003784
We should see the following output by default:
Example Output
root@phycore-am57xx-1:~# devmem2 0x4A003784 /dev/mem opened. Memory mapped at address 0xffff9fc5f000. Read at address 0x4A003784 (0xffff9fc5f084): 0x00060000
The value held in the CTRL_CORE_PAD_MMC3_DAT0 memory address is 0x00060000, which can be broken down according to the CTRL_CORE_PAD_MMC3_DAT0 Register Field Descriptions within the TRM (see Table 18-1611). Here we can see that the register is configured as an input, with an internal pull-up enabled, and is in mux mode 0 which is mmc3_dat0. This is not the direction or mux mode we need for driving an LED so it will need to be changed.
Modify the CTRL_CORE_PAD_MMC3_DAT0 register in order to configure the mmc3_dat0 as the desired GPIO mux mode we need (gpio6_31):
Target (Linux)
devmem2 0x4A003784 w 0x0000000e
Writing the value 0x0000000e to CTRL_CORE_PAD_MMC3_DAT0 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 gpio6_31 as an output, we can connect up an LED to X_MMC3_DAT0 and blink it!
Reference the following circuit diagram to help you connect up an LED to pin 29 of the X26 Expansion Connector on the phyCORE-AM57x 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.