KV260 Kria Starter Kit Series: 4 - Petalinux BRAM Application

KV260 Kria Starter Kit Series: 3 makalesindeki Vivado projesinde bazı değişiklikler yapıldı. Interrupt kontroller yerine BRAM Controller ve BRAM generator kullanıldı. Bu uygulamanın amacı bir Block RAM donanımı kurup onun adresini istediğimiz gibi ayarlamak ve bu adrese Linux User Space'de Vitis uygulamamızı çalıştırarak bir data yazmak ve onu geri okumak.

Vivado projesi oluşturma, Platform oluşturma  vs donanım tasarım işleri önceki makale ile aynı prosedürde yapıldı. Sadece biraz tasarım farklılığı var. Bunun dışında Petalinux ile proje oluşturma, rootfs, sysroot, dtsi vs oluşturma adımları da aynı yalnız pl.dtsi dosyası açılıp bir kontrol edilir ve PL tasarımı device tree dosyasına yansımış mı diye kontrol edilir:

/*
 * CAUTION: This file is automatically generated by Xilinx.
 * Version: XSCT 2022.1
 * Today is: Sun Aug 18 10:08:02 2024
 */
/dts-v1/;
/plugin/;
/ {
    fragment@0 {
        target = <&fpga_full>;
        overlay0: __overlay__ {
            #address-cells = <2>;
            #size-cells = <2>;
            firmware-name = "kv260_vitis_platform_20221.bit.bin";
            resets = <&zynqmp_reset 116>;
        };
    };
    fragment@1 {
        target = <&amba>;
        overlay1: __overlay__ {
            afi0: afi0 {
                compatible = "xlnx,afi-fpga";
                config-afi = < 0 0>, <1 0>, <2 0>, <3 0>, <4 0>, <5 0>, <6 0>, <7 0>, <8 0>, <9 0>, <10 0>, <11 0>, <12 0>, <13 0>, <14 0xa00>, <15 0x000>;
            };
            clocking0: clocking0 {
                #clock-cells = <0>;
                assigned-clock-rates = <99999001>;
                assigned-clocks = <&zynqmp_clk 71>;
                clock-output-names = "fabric_clk";
                clocks = <&zynqmp_clk 71>;
                compatible = "xlnx,fclk";
            };
            clocking1: clocking1 {
                #clock-cells = <0>;
                assigned-clock-rates = <99999001>;
                assigned-clocks = <&zynqmp_clk 72>;
                clock-output-names = "fabric_clk";
                clocks = <&zynqmp_clk 72>;
                compatible = "xlnx,fclk";
            };
        };
    };
    fragment@2 {
        target = <&amba>;
        overlay2: __overlay__ {
            #address-cells = <2>;
            #size-cells = <2>;
            axi_bram_ctrl_0: axi_bram_ctrl@80000000 {
                /* This is a place holder node for a custom IP, user may need to update the entries */
                clock-names = "s_axi_aclk";
                clocks = <&misc_clk_0>;
                compatible = "xlnx,axi-bram-ctrl-4.1";
                reg = <0x0 0x80000000 0x0 0x2000>;
                xlnx,bram-addr-width = <0xb>;
                xlnx,bram-inst-mode = "EXTERNAL";
                xlnx,ecc = <0x0>;
                xlnx,ecc-onoff-reset-value = <0x0>;
                xlnx,ecc-type = <0x0>;
                xlnx,fault-inject = <0x0>;
                xlnx,memory-depth = <0x800>;
                xlnx,rd-cmd-optimization = <0x0>;
                xlnx,read-latency = <0x1>;
                xlnx,s-axi-ctrl-addr-width = <0x20>;
                xlnx,s-axi-ctrl-data-width = <0x20>;
                xlnx,s-axi-id-width = <0x10>;
                xlnx,s-axi-supports-narrow-burst = <0x1>;
                xlnx,single-port-bram = <0x0>;
            };
            misc_clk_0: misc_clk_0 {
                #clock-cells = <0>;
                clock-frequency = <99999000>;
                compatible = "fixed-clock";
            };
            zyxclmm_drm {
                compatible = "xlnx,zocl";
            };
        };
    };
};

Daha sonra Vitis ile platform oluşturulmaya başlandı ve önceki makaledeki adımların aynısı izlendi. Application'a geçmeden önceki KV260 board'unun boot edilip /lib/firmware/xilinx dizini altına gönderilmesi gereken .dtbo shell.json ve en önemlisi .bit.bin dosyalarının kopyalanması süreci gerçekleştirildi. Bunu yaparken dtbo ve json zaten elimizde mevcut ancak Vivado'dan elde edilen bitstream'in .bit.bin uzantısına dönüştürülmesi gerekti. Bu adım Xilinx tutorial'ı referans alınarak gerçekleştirildi.

boot.bif isimli bir dosya oluşturuldu ve içerisine aşağıdaki kod yazıldı.                

the_ROM_image:
{   /home/adem/kria_vitis_platform/hardware/kv260_vitis_platform_20221/kv260_vitis_platform_20221.bit
}

Daha sonra Xilinx bootgen uygulaması çalıştırılarak .bit.bin uzantılı dosya oluşturuldu:

bootgen -image boot.bif -arch zynqmp -process_bitstream bin

Oluşan dosya /home/adem/kria_vitis_platform/hardware/kv260_vitis_platform_20221/ dizini altındadır. Bu dosya yukarıda da belirtildiği gibi board içerisinde /lib/firmware/Xilinx dizininde oluşturduğum uygulama klasörü 'bram_app' dizinine pl.dtbo ve shell.json ile birlikte kopyalandı. Daha sonra aşağıdaki komutlar çağrılarak donanım board'a yuklendi.

sudo xmutil listapps
sudo xmutil unloadapp
sudo xmutil loadapp bram_app

Burada artık eksik kalan tek şey Application idi. Xilinx'in KV260 örnek uygulaması olarak tasarladığı ve bir önceki makalede başarılı şekilde çalıştırılan Vector Addition uygulamasında kernel C++ ile yazılmıştı ve xclbin olarak üretilen bir dosya uygulama çıktısı olarak kullanılıyordu. Bunu yapabilmek için hangi kaynaklara ihtiyaç olduğunu araştırdığımda fazlaca karmaşık bir döküman ve komut setiyle karşılaştım. Ben de Vitis'den Linux uygulamasını Hello World taslağı ile açıp yazdığım uygulamayı .elf olarak çıktsını alıp board üzerinde çalıştırmak istedim. Uygulama şu şekilde yazıldı:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

#define BRAM_BASE_ADDR  0x80000000 // Replace with the actual base address from the device tree
#define BRAM_SIZE       0x10000    // Adjust based on the BRAM size
int main()
{
    printf("Hello World\n");
    int fd;
    unsigned long *bram;

    // Open the memory device
    fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    // Map the BRAM address space into user space
    bram = (unsigned long *)mmap(NULL, BRAM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BRAM_BASE_ADDR);
    if (bram == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return -1;
    }

    // Write 32-bit data to BRAM
    bram[0] = 0x12345678; // Writing to the first 32-bit word
    printf("Written 0x12345678 to BRAM at offset 0x0\n");

    // Optionally, read back and verify the data
    unsigned long read_data = bram[0];
    if (read_data == 0x12345678) {
        printf("Read back 0x%lx successfully!\n", read_data);
    } else {
        printf("Read back verification failed! Got 0x%lx instead.\n", read_data);
    }

    // Unmap the BRAM memory and close the file descriptor
    munmap(bram, BRAM_SIZE);
    close(fd);

    return 0;
}

Bu uygulama 0x80000000 adresine AXI4 interface ile bağlı olan BRAM bellek elemanına Petalinux User Space'den erişilmesini ve data yazılıp okunmasını sağlıyor. Bunu Vitis ile derleyip .elf dosyası oluşturuldu ve scp kullanılarak board içerisindeki /home/petalinux dizinine gönderildi. chmod kullanılarak executable yetkisi verildi ve board üzerinde çalıştırıldı.

sudo ./kv260_bram_app.elf

Output:

Hello World

Written 0x12345678 to BRAM at offset 0x0

Read back 0x12345678 successfully!

Ayrıca  devmem 0x80000000 32  komutu kullanılarak da Linux'un kendi memory erişim özelliği ile adres kontrolü yapıldı ve gerçekten 0x12345678 değeri okundu.



Yorumlar

Bu blogdaki popüler yayınlar

KV260 Kria Starter Kit Series: 3 - Petalinux Install and Boot

KV260 Kria Starter Kit Series: 1 - Power and Boot Up

KV260 Kria Starter Kit Series: 2 - Smartcam Application (Ubuntu)