In this post we will create an application in C that controls the hardware we created in a previous one. The application reads via polling the buttons value and propagates it to the counter interface. Then according to the buttons pressed, the counter functions as described in the previous post. The counter output is finally written at the leds interface.
Lets now explain how the code works.
#define BUTTONS_BASE_ADDR 0x41210000
#define LEDS_BASE_ADDR 0x43C00000
#define GRAY_BASE_ADDR 0x43C10000
First of all, we must define the addresses of the peripherals interface. These addresses are set from the Vivado project when we create the peripherals.
void *ptr_buttons, *ptr_gray, *ptr_led;
unsigned page_addr_buttons, page_addr_gray, page_addr_led;
unsigned page_offset_buttons, page_offset_gray,page_offset_led;
unsigned page_size = sysconf(_SC_PAGESIZE);
After that, we declare the above variables in order to communicate with the peripherals.
page_addr_buttons = (BUTTONS_BASE_ADDR & ~(page_size-1));
page_offset_buttons = BUTTONS_BASE_ADDR – page_addr_buttons;
page_addr_gray = (GRAY_BASE_ADDR & ~(page_size-1));
page_offset_gray = GRAY_BASE_ADDR – page_addr_gray;
page_addr_led = (LEDS_BASE_ADDR & ~(page_size-1));
page_offset_led = LEDS_BASE_ADDR – page_addr_led;
fd = open(“/dev/mem”,O_RDWR);
We open a file descriptor which is essential for mapping the peripheral physical address to a virtual one. Here is how the mapping is done using the mmap function
ptr_buttons = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (BUTTONS_BASE_ADDR & ~(page_size-1)));
ptr_gray = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (GRAY_BASE_ADDR & ~(page_size-1)));
ptr_led = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (LEDS_BASE_ADDR & ~(page_size-1)));
Now, in order to read from a peripheral(for example the buttons) we use the following command:
counter = *((unsigned *)(ptr_gray+page_offset_gray+4));
The +4 offset in the command is because in the gray counter module in the vivado project the output of the module is stored in the slv_reg1(for example if we wanted to access the slv_reg3 we would have to use a +12 offset).
Now in order to write we simply use this command:
*((unsigned *)(ptr_led+page_offset_led)) = counter;
In order to write an application which control the custom designed peripherals you have to know the physical address of them and map it to a virtual one. Then use these virtual addresses and offsets in a simple command to read and write to those peripherals.