Blink
This guide will walkthrough the cross-compilation of a Blink executable intended to run on the phyCORE-i.MX8X development kit. This demo will blink the D31 User LED by accessing the underlying GPIO hardware registers, the best reference to explain what is going here at the register level is the Technical Reference Manual for the i.MX8X processor, which can be downloaded from NXP’s i.MX8X Documentation page.
Note
In order to follow this guide, you must first Install the SDK and source the cross compilation environment.
In order to follow this guide, the User LED on your phyCORE-i.MX8X development kit must not be already tied to any drivers. If you followed the Modifying the BSP guide then you might have tied a driver to the User LED, the change introduced by that guide will need to be reverted. An easy way to do this quickly would be to just make a second SD Card using a pre-built image, check out the Create a Bootable SD Card guide for more information!
Let’s make a project directory to contain the Blink source code:
mkdir ~/blink-project
cd ~/blink-project
Create the main Blink application source code file using your favorite text editor:
vim blink.c
Edit the contents of the file to reflect the following and remember to save your changes when you are done!
// This blink example was written for the phyCORE-i.MX8X Development Kit
// and toggles the D31 LED on the PCM-942.A2 Expansion Board. This LED is
// is connected to LSIO_GPIO0_IO28
//
// Authored by True (:
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#define GPIO0_ADDR_START 0x5D080000
#define GPIO0_ADDR_END 0x5D08FFFF
#define GPIO0_SIZE (GPIO0_ADDR_END - GPIO0_ADDR_START)
#define GPIO0_PORT (1 << 28)
#define GPIO0_DATA_OFFSET 0x00000000
#define GPIO0_DIR_OFFSET 0x00000001
static volatile int keepRunning = 1;
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){}
}
void intHandler(int dummy) {
keepRunning = 0;
printf("Blink Stopped\n");
}
int main()
{
unsigned int *gpioAddress;
unsigned int *gpio_setdataout_addr;
unsigned int *gpio_direction_addr;
signal(SIGINT, intHandler);
int fd = open("/dev/mem", O_RDWR);
gpioAddress =(unsigned int *) mmap(0, GPIO0_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO0_ADDR_START);
gpio_setdataout_addr = gpioAddress + GPIO0_DATA_OFFSET;
gpio_direction_addr = gpioAddress + GPIO0_DIR_OFFSET;
*gpio_direction_addr |= GPIO0_PORT;
while (keepRunning)
{
*gpio_setdataout_addr ^= GPIO0_PORT;
delay(1000);
}
int err = munmap(gpioAddress, GPIO0_SIZE);
if(err != 0){
printf("UnMapping Failed\n");
return 1;
}
return 0;
}
Cross-Compile the blink project:
$CC -O blink.c -o blink
You should now see an executable of the name “blink” in the current working directory. Remember that this file was cross-compiled so it won’t work as expected if you try to execute it on your Ubuntu Host Machine. We can confirm the target architecture of the binary like this:
user@ubuntu:~blink-project$ file blink
blink: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=009f2310fb4646103486731e374b979bda901edb, for GNU/Linux 3.14.0, not stripped
Now, transfer the executable to the phyCORE-i.MX8X while it is booted into Linux. Check out the guide, Copying Files to the Device, for a bunch of options on how to do this. I recommend just quickly copying the “blink” file to a USB thumb drive to transfer files to the running target or, if you have time, setting up a network file sharing for long term development.
Once the file is transferred to the phyCORE-i.MX8X, navigate to the directory containing it using the target console and run the binary:
./blink
You should be able to quickly confirm that the User LED D31 is blinking.
To stop the Blink demo, hit Ctrl + C