精华内容
下载资源
问答
  • Linux中,驱动必然会有驱动对应的设备类型。在linux4.4版本中,其设备是以设备树的形式展现的。PS端设备树的devicetree表示如下324 dmac_s: dmac@f8003000 {325 compatible = "arm,pl330", "arm,primecell";326 reg ...

    ecd1497a0c3dda2d4c78bda31283d012.png

    Linux中,驱动必然会有驱动对应的设备类型。在linux4.4版本中,其设备是以设备树的形式展现的。

    PS端设备树的devicetree表示如下

    324 dmac_s: dmac@f8003000 {

    325 compatible = "arm,pl330", "arm,primecell";

    326 reg = <0xf8003000 0x1000>;

    327 interrupt-parent = ;

    328 interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",

    329 "dma4", "dma5", "dma6", "dma7";

    330 interrupts = <0 13 4>,

    331 <0 14 4>, <0 15 4>,

    332 <0 16 4>, <0 17 4>,

    333 <0 40 4>, <0 41 4>,

    334 <0 42 4>, <0 43 4>;

    335 #dma-cells = <1>;

    336 #dma-channels = <8>;

    337 #dma-requests = <4>;

    338 clocks = ;

    339 clock-names = "apb_pclk";

    340 };

    这个文件根据设备树信息创建设备信息,在驱动程序注册时就可以找到该设备信息,执行probe函数。

    zynq下dma的设备channel如下:

    ​root@linaro-ubuntu-desktop:/sys/class/dma# ls

    dma0chan0 dma0chan2 dma0chan4 dma0chan6 dma1chan0

    dma0chan1 dma0chan3 dma0chan5 dma0chan7

    root@linaro-ubuntu-desktop:/sys/class/dma# ll

    total 0

    drwxr-xr-x 2 root root 0 1970-01-01 00:00 ./

    drwxr-xr-x 50 root root 0 1970-01-01 00:00 ../

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma0chan0 -> ../../devices/soc0/amba/f8003000.dmac/dma/dma0chan0/

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma0chan1 -> ../../devices/soc0/amba/f8003000.dmac/dma/dma0chan1/

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma0chan2 -> ../../devices/soc0/amba/f8003000.dmac/dma/dma0chan2/

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma0chan3 -> ../../devices/soc0/amba/f8003000.dmac/dma/dma0chan3/

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma0chan4 -> ../../devices/soc0/amba/f8003000.dmac/dma/dma0chan4/

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma0chan5 -> ../../devices/soc0/amba/f8003000.dmac/dma/dma0chan5/

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma0chan6 -> ../../devices/soc0/amba/f8003000.dmac/dma/dma0chan6/

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma0chan7 -> ../../devices/soc0/amba/f8003000.dmac/dma/dma0chan7/

    lrwxrwxrwx 1 root root 0 1970-01-01 00:00 dma1chan0 -> ../../devices/soc0/fpga-axi@0/43000000.axivdma/dma/dma1chan0/

    dma1chan0是xilinx AXI-VDMA IP生成的DMA控制器,其处于PL端,而dma0相关的控制器是ps端的pl330.本篇看pl330这个驱动程序的注册。

    查看物理地址分布

    ​root@linaro-ubuntu-desktop:~# cat /proc/iomem

    00000000-1fffffff : System RAM

    00008000-006651a3 : Kernel code

    006a2000-00700867 : Kernel data

    41600000-4160ffff : /fpga-axi@0/i2c@41600000

    43000000-43000fff : /fpga-axi@0/axivdma@43000000

    70e00000-70e0ffff : /fpga-axi@0/axi_hdmi@70e00000

    75c00000-75c00fff : /fpga-axi@0/axi-spdif-tx@0x75c00000

    77600000-77600fff : /fpga-axi@0/axi-i2s@0x77600000

    79000000-7900ffff : /fpga-axi@0/axi-clkgen@79000000

    e0001000-e0001fff : xuartps

    e0002000-e0002fff : /amba/usb@e0002000

    e0002000-e0002fff : /amba/usb@e0002000

    e000a000-e000afff : /amba/gpio@e000a000

    e000b000-e000bfff : /amba/eth@e000b000

    e000d000-e000dfff : /amba/spi@e000d000

    e0100000-e0100fff : mmc0

    f8003000-f8003fff : /amba/dmac@f8003000

    f8003000-f8003fff : /amba/dmac@f8003000

    f8005000-f8005fff : /amba/watchdog@f8005000

    f8007000-f80070ff : /amba/devcfg@f8007000

    f8007100-f800711f : /amba/adc@f8007100

    f800c000-f800cfff : /amba/ocmc@f800c000

    fffc0000-ffffffff : f800c000.ocmc

    root@linaro-ubuntu-desktop:~#

    ARM采用统一编址,其访问内存和外设的指令是一样没有差异的,linux内核并不通过物理地址直接访问外设,而是通过虚拟地址,虚拟地址经过MMU转换成物理访问外设。所以外设需要使用ioremap()对将物理地址空间转换成虚拟地址。

    I/O设备使用第三种地址,总线地址。如果一个设备在MMIO(memory mapped IO内存映射地址空间)有寄存器,或者其对系统存储系统执行DMA读写操作,设备使用的就是总线地址。

    在系统枚举阶段,内核知道I/O设备以及他们的MMIO空间。如果一个设备支持DMA方式,驱动通过kmalloc()申请一段内存空间,返回申请空间的首地址,设为X,虚拟地址系统将虚拟地址X映射到物理地址Y。驱动程序可以使用虚拟地址X访问设备地址空间,但是设备本身却不行,这是因为DMA本身并不是通过虚拟地址方式来工作的。

    在zynq7000设备里,DMA可以直接操作物理地址,但另一些处理器使用IOMMU将DMA地址转换物理地址,linux建议使用DMA API而不是特定总线的DMA API,比如使用dma_map_*()接口而不是pci_map_*()接口,在zynq7000中,pl330 DMA已经实现了直接调用通用的DMA框架API即可以。

    DMA开发相关API

    首先得包含

    ​#include

    其提供了dma_addr_t定义,其可以作为设备使用DMA的源地址或者目的地址,并且可以使用DMA_XXX相关的API。

    1.使用大DMA 一致性buffer

    ​void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag)

    分配大小的一致性区域。其返回值能被强制类型转换成unsigned integer,这样就是总线的宽度

    ​void * dma_zalloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag)

    是对dma_alloc_coherent的封装,并且将返回的地址空间内存清零。

    ​void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle)

    释放一致性内存。

    2.使用小DMA一致性buffer

    需要包括如下代码

    ​#include

    其工作有点类似kmem_cache(),不过其使用的是DMA一致性分配器,而非__get_free_pages(),并且需要N-byte对齐。

    ​struct dma_pool *

    dma_pool_create(const char *name, struct device *dev, size_t size, size_t align, size_t alloc);

    “name”字段用于诊断,dev和size和传递给dma_alloc_coherent()类似,align以字节计,且需要是2的指数。如果设备没有跨界限制,传递0;传递4096则意味着分配的DMA空间不能跨越4KByte空间。

    ​void *dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)

    ​void *dma_pool_alloc(struct dma_pool *pool, gfp_t gfp_flags, dma_addr_t *dma_handle);

    从pool分配内存,返回内存将会满足size和alignment要求。传递GFP_ATOMIC防止阻塞,或者如果允许阻塞,则可以传递GFP_KERNEL,和dma_alloc_coherent()类似,返回两个值,一个是CPU使用的地址,以及一个设备使用的DMA地址。

    ​void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr);

    释放由dma_pool_alloc()分配的内存空间到pool。

    ​void dma_pool_destroy(struct dma_pool *pool);

    dma_pool_destroy()将内存池的资源释放。

    part1c DMA寻址限制

    ​int dma_set_mask_and_coherent(struct device *dev, u64 mask)

    检查mask是否合法,如果是跟新设备streaming以及DMA mask参数。返回0是正确。

    ​int dma_set_mask(struct device *dev, u64 mask)

    int dma_set_coherent_mask(struct device *dev, u64 mask

    检查mask是否合法,如果是就跟新。

    ​u64 dma_get_required_mask(struct device *dev)

    检查系统合法的DMA掩码。

    part 1D Streaming(流式) DMA 映射

    ​dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction direction)

    将处理器的虚拟地址空间进行映射,这样让处理器可以访问外设,返回值是DMA地址。

    其direction参数可选字段即意义如下:

    ​DMA_NONEno direction (used for debugging)

    DMA_TO_DEVICEdata is going from the memory to the device

    DMA_FROM_DEVICEdata is coming from the device to the memory

    DMA_BIDIRECTIONALdirection isn't known

    并不是所有的存储空间都能够使用上面的函数进行映射。内核虚拟地址也许是连续的但是其映射的物理地址却可以不一样。由于这个API不提供scatter/gather功能,如果尝试映射非连续物理存储空间。所以由该API进行映射的地址需要确保物理地址连续,如kmalloc。

    设备DMA的地址内存范围必须在dma_mask,需要确保由kmalloc分配的内存空间在dma_mask所能达到的范围之内。驱动程序也许会传递各种flags以限制DMA地址范围(比如X86能够表示的地址范围在前16MB内)。

    对具有IOMMU的平台,物理地址连续性和dma_mask要求也许不再适用。然而,考虑到可移植性,通常会忽略IOMMU的存在。

    内存操作粒度被成为cache line 宽度,为了让这里的API映射的DMA操作成功执行,映射的区域必须在cache line边界开始和结束(目的是不发生对一个cache line出现两个独立的映射区域)。

    DMA_TO_DEVICE,在软件修改内存块后程序退出控制前,需要进行同步。一个这一原语被使用,由这一原语包括的这一区域被成为只读,如果同时设备想写,需要使用DMA_BIDIRECTIONAL标志。

    DMA_FROM_DEVICE 在驱动程序修改数据前先同步。内存块需要被当成只读对待。如果驱动要写功能,则需要设置DMA_BIDIRECTIONAL。

    DMA_BIDIRECTIONAL需要特殊对待。这意味这驱动程序不能确定内存的改变在是否发生在将存储空间交给设备前,同时不能确定设备是否需要改变这块内存。所以,需要双向同步内存块。一次是在内存控制权移交给设置前,一次是在获取数据前。

    ​void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction)

    Unmap先前映射的区域,所有传递进来的参数必须和建立映射接口时的参数一致。

    ​dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size,

    enum dma_data_direction direction)

    void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, enum dma_data_direction direction)

    对页进行映射和逆映射。轻易不要动和这两个参数。

    ​int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)

    在一些场景下,dma_map_single() and dma_map_page()在创建一个映射时也许会失败。调用上面的接口可以检测出错的原因。

    ​int

    dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction)

    返回segment 映射的DMA地址。

    当使用scatterlist方式时,建立映射的过程如下:

    ​int i, count = dma_map_sg(dev, sglist, nents, direction);

    struct scatterlist *sg;

    for_each_sg(sglist, sg, count, i) { hw_address[i] = sg_dma_address(sg);

    hw_len[i] = sg_dma_len(sg); }

    zynq PS端pl330驱动注册

    3002 static struct amba_driver pl330_driver = {

    3003 .drv = {

    3004 .owner = THIS_MODULE,

    3005 .name = "dma-pl330",

    3006 .pm = &pl330_pm,

    3007 },

    3008 .id_table = pl330_ids,

    3009 .probe = pl330_probe,

    3010 .remove = pl330_remove,

    3011 };

    3012

    3013 module_amba_driver(pl330_driver);

    见到此则知道必然是调用probe函数。注册函数调用如下:

    2775 static int

    2776 pl330_probe(struct amba_device *adev, const struct amba_id *id)

    2777 {

    2778 struct dma_pl330_platdata *pdat;

    2779 struct pl330_config *pcfg;

    2780 struct pl330_dmac *pl330;

    2781 struct dma_pl330_chan *pch, *_p;

    2782 struct dma_device *pd;

    2783 struct resource *res;

    2784 int i, ret, irq;

    2785 int num_chan;

    2786

    2787 pdat = dev_get_platdata(&adev->dev);

    上面定义了三个重要的数据结构体,它们的关系如下图:2bd337d17925b67d4c956ee660857669.png

    2806 pl330->base = devm_ioremap_resource(&adev->dev, res);

    2807 if (IS_ERR(pl330->base))

    2808 return PTR_ERR(pl330->base);

    对地址空间进行映射,并且存在了struct pl330_dmac结构体里。

    2812 for (i = 0; i < AMBA_NR_IRQS; i++) {

    2813 irq = adev->irq[i];

    2814 if (irq) {

    2815 ret = devm_request_irq(&adev->dev, irq,

    2816 pl330_irq_handler, 0,

    2817 dev_name(&adev->dev), pl330);

    2818 if (ret)

    2819 return ret;

    2820 } else {

    2821 break;

    2822 }

    2823 }

    每一个channel对应于一个中断,但是它们的中断服务函数是同一个。

    2825 pcfg = &pl330->pcfg;

    2826

    2827 pcfg->periph_id = adev->periphid;

    2828 ret = pl330_add(pl330);

    设置pl330的configure字段。

    2832 INIT_LIST_HEAD(&pl330->desc_pool);

    2833 spin_lock_init(&pl330->pool_lock);

    2834

    2835 /* Create a descriptor pool of default size */

    2836 if (!add_desc(pl330, GFP_KERNEL, NR_DEFAULT_DESC))

    2837 dev_warn(&adev->dev, "unable to allocate desc\n");

    设置pl330的描述符池,并且初始化16个描述符。

    2842 if (pdat)

    2843 num_chan = max_t(int, pdat->nr_valid_peri, pcfg->num_chan);

    2844 else

    2845 num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);

    2846

    2847 pl330->num_peripherals = num_chan;

    2848

    2849 pl330->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);

    2850 if (!pl330->peripherals) {

    初始化channel数,并且为dma channel分配内存空间。

    2856 for (i = 0; i < num_chan; i++) {

    2857 pch = &pl330->peripherals[i];

    2858 if (!adev->dev.of_node)

    2859 pch->chan.private = pdat ? &pdat->peri_id[i] : NULL;

    2860 else

    2861 pch->chan.private = adev->dev.of_node;

    2862

    2863 INIT_LIST_HEAD(&pch->submitted_list);

    2864 INIT_LIST_HEAD(&pch->work_list);

    2865 INIT_LIST_HEAD(&pch->completed_list);

    2866 spin_lock_init(&pch->lock);

    2867 pch->thread = NULL;

    2868 pch->chan.device = pd;

    2869 pch->dmac = pl330;

    2870

    2871 /* Add the channel to the DMAC list */

    2872 list_add_tail(&pch->chan.device_node, &pd->channels);

    2873 }

    初始化dma_pl330_chan相关字段。

    2886 pd->device_alloc_chan_resources = pl330_alloc_chan_resources;

    2887 pd->device_free_chan_resources = pl330_free_chan_resources;

    2888 pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;

    2889 pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;

    2890 pd->device_tx_status = pl330_tx_status;

    2891 pd->device_prep_slave_sg = pl330_prep_slave_sg;

    2892 pd->device_config = pl330_config;

    2893 pd->device_pause = pl330_pause;

    2894 pd->device_terminate_all = pl330_terminate_all;

    2895 pd->device_issue_pending = pl330_issue_pending;

    2896 pd->src_addr_widths = PL330_DMA_BUSWIDTHS;

    2897 pd->dst_addr_widths = PL330_DMA_BUSWIDTHS;

    2898 pd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);

    2899 pd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;

    初始化上图中struct dma_device的若干成员和函数。

    2901 ret = dma_async_device_register(pd);

    2902 if (ret) {

    2903 dev_err(&adev->dev, "unable to register DMAC\n");

    2904 goto probe_err3;

    2905 }

    注册dma设备并创建sys/class接口,会有如下显示:

    ​root@linaro-ubuntu-desktop:/sys/class/dma# ls

    dma0chan0 dma0chan2 dma0chan4 dma0chan6 dma1chan0

    dma0chan1 dma0chan3 dma0chan5 dma0chan7

    将DMA控制器注册到DT DMA helpers。通过of_dma_list就可以找到该DMA控制器。

    2907 if (adev->dev.of_node) {

    2908 ret = of_dma_controller_register(adev->dev.of_node,

    2909 of_dma_pl330_xlate, pl330);

    至此,DMA注册函数基本流程完毕。但是还留下了一个irq函数。

    DMA中断服务函数

    2720 static irqreturn_t pl330_irq_handler(int irq, void *data)

    2721 {

    2722 if (pl330_update(data))

    2723 return IRQ_HANDLED;

    2724 else

    2725 return IRQ_NONE;

    2726 }

    该函数实际上调用了pl330_update去完成中断服务函数的请求。由于其是在中断函数中调用的,则中断函数的那些注意事项还是要遵从的。

    1533 static int pl330_update(struct pl330_dmac *pl330)

    1534 {

    1535 struct dma_pl330_desc *descdone, *tmp;

    1536 unsigned long flags;

    1537 void __iomem *regs;

    1538 u32 val;

    1539 int id, ev, ret = 0;

    1540

    1541 regs = pl330->base;

    该函数的base地址是经过ioremap得到的。

    1545 val = readl(regs + FSM) & 0x1;

    1546 if (val)

    1547 pl330->dmac_tbd.reset_mngr = true;

    1548 else

    1549 pl330->dmac_tbd.reset_mngr = false;

    首先都FSM寄存器,然后看bit0是否需要复位mngr。

    1551 val = readl(regs + FSC) & ((1 << pl330->pcfg.num_chan) - 1);

    1552 pl330->dmac_tbd.reset_chan |= val;

    1553 if (val) {

    1554 int i = 0;

    1555 while (i < pl330->pcfg.num_chan) {

    1556 if (val & (1 << i)) {

    1557 dev_info(pl330->ddma.dev,

    1558 "Reset Channel-%d\t CS-%x FTC-%x\n",

    1559 i, readl(regs + CS(i)),

    1560 readl(regs + FTC(i)));

    1561 _stop(&pl330->channels[i]);

    1562 }

    1563 i++;

    1564 }

    1565 }

    各个通复位。

    1568 val = readl(regs + ES);

    1569 if (pl330->pcfg.num_events < 32

    1570 && val & ~((1 << pl330->pcfg.num_events) - 1)) {

    1571 pl330->dmac_tbd.reset_dmac = true;

    1572 dev_err(pl330->ddma.dev, "%s:%d Unexpected!\n", __func__,

    1573 __LINE__);

    1574 ret = 1;

    1575 goto updt_exit;

    1576 }

    读取事件寄存器,并判断是否出错了。出错则置reset标志。

    1578 for (ev = 0; ev < pl330->pcfg.num_events; ev++) {

    1579 if (val & (1 << ev)) { /* Event occurred */

    1580 struct pl330_thread *thrd;

    1581 u32 inten = readl(regs + INTEN);

    1582 int active;

    1583

    1584 /* Clear the event */

    1585 if (inten & (1 << ev))

    1586 writel(1 << ev, regs + INTCLR);

    1587

    1588 ret = 1;

    1589

    1590 id = pl330->events[ev];

    1591

    1592 thrd = &pl330->channels[id];

    1593

    1594 active = thrd->req_running;

    1595 if (active == -1) /* Aborted */

    1596 continue;

    1597

    1598 /* Detach the req */

    1599 descdone = thrd->req[active].desc;

    1600 thrd->req[active].desc = NULL;

    1601

    1602 thrd->req_running = -1;

    1603

    1604 /* Get going again ASAP */

    1605 _start(thrd);

    1606

    1607 /* For now, just make a list of callbacks to be done */

    1608 list_add_tail(&descdone->rqd, &pl330->req_done);

    1609 }

    1610 }

    处理相应事件。

    文章来源:shichaog的专栏

    声明:本文由原创博主授权转发,如需转载请联系博主

    展开全文
  • ALINX_ZYNQ开发平台Linux应用教程V1.05
  • course_s4_ALINX_ZYNQ开发平台Linux应用教程V1.03,共九章内容,第一章QT,第二章OpenCV,,第三章双摄像头模块OpenCV显示,第四章触摸屏模块应用,第五章AXI DMA读写测试,第六章 基于DMA的ADC波形显示(AN926),第七章...
  • ZYNQ开发全过程概览

    2018-11-15 13:08:04
    详细讲解ZYNQ开发过程所涉及到的技术,包括环境搭建、ZYNQ小系统,fsbl创建、uboot编译以及创建,对刚入门ZYNQ的开发者会有很大帮助
  • 领航者ZYNQLinux开发指南 V1.2 本书我们讲解Linux,而Linux开发可以分为底层驱动开发和应用开发,本书以领航者ZYNQ为硬件平台,从实现到驱动,从底层到应用的讲解linux开发
  • zynq Linux程序开发

    千次阅读 2019-02-27 13:00:30
    开发环境:vivado 2018.2、PetaLinux 2018.2 程序框架: 具体步骤: 1. 打开vivado 2018.2软件 2. 点击Create Project 3. 输入工程名和工程路径 (注意:工程路径中不要有空格,否则后续SDK会无法导入...

    开发环境:vivado 2018.2、PetaLinux 2018.2

    程序框架

    具体步骤:

    1. 打开vivado 2018.2软件

    2. 点击Create Project

    3. 输入工程名和工程路径

    (注意:工程路径中不要有空格,否则后续SDK会无法导入硬件描述文件

    4. 选择RTL工程,下方选项不勾选。

    5. 选择Verilog语言,不添加文件,一直点击Next

    6. 直接点击boards,选择对应的开发板

    7. 打开一个新项目project_led

    8. 创建一个block Design ,在Flow Navigator区域展开IP INTEGRATOR,选择create Block Design,输入块的名称system_1。

    9. 工作域将会打开Diagram的图表画布,我们将在空白区域像画画一样构建自己的系统。这里操作的最小单位为IP核,xilinx提供的免费IP核可以直接添加使用,用户也可以自定义IP核。

    10. 点击空白画布中间的+号来添加IP核(或者在空白板上右键点击Add IP),在search中输入zynq ,在搜索结果中双击ZYNQ7 Processing  system添加PS端到IP核画布

    11. 要使PS模块在zedboard中工作,还要对其进行配置,鼠标左键双击PS模块,即可打开编辑IP核的界面。

    12. 点击Presets -> Zedboard ,使用vivado对zedboard提供的默认配置,点击ok。(此处用户可根据自己的硬件自行配置)

    13. 单击DDR接口,出现笔状时右键,选择 Make External ,FIXED_IO使用同样办法

    14. 添加AXI GPIO IP核到系统中。右键单击空白处添加IP核,搜索栏输入GPIO,双击AXI GPIO 添加完成

    15. 然后单击run connection automation 选择/axi_gpio_o/s_AXI,单击ok有两个新IP核被自动添加了。

    16. 然后再单击run connection automation,Select Board Interface下选择leds_8bits.
    这样就基本配置完成,IP Integrator会自动为AXI总线上的逻辑设备分配地址空间,这样ARM就可以寻址到该设备。如图:

    17. 为AXI GPIO分配64k的地址空间,基地址为0x41200000,保存工程。在Diagram窗口上方工具栏中,选择Validate Design 按钮,检查设计有效性

    18. 至此,IP子系统我们已经设计完成了。下面我们将设计完成Block Design生成可以综合的HDL设计文件。 在Sources 窗口,右键zynq_system_1 选择Generate Output Products

    19. 单击Generate,生成HDL源文件和相应端口的约束文件。再右击zynq_system_1,选择Create HDL Wrapper选型,单击ok。这里vivado为IP子系统生成了一个顶层文件,使我们可以对系统进行综合、实现并生成比特流。

    20. 在Flow Navigator 中展开Program and debug ,单击generate Bitstream。单击ok。此时vivado会生成一个硬件.bit文件,产生的bit文件位于:C:\Users\DELL\vivado_workspace\project_led\project_led.runs\impl_1中

     

    21. 这一过程将持续很长时间,当完成后,会弹出一个对话框,选择open Implementation Design

    22. 将设计导入SDK,然后就可以对ARM编程。选中Sources栏中的zynq_system_1.bd,执行File->Export->Export Hardware 命令,弹出的对话框确保复选按钮被选上。会生成一个project_led.sdk文件夹 (产生的硬件描述文件system_1_wrapper.hdf文件位于C:\Users\DELL\vivado_workspace\project_led\project_led.sdk)

     

    23. 打开VMware虚拟机,运行Ubuntu 16.04.3操作系统。

    24. 定位目录:先在shell中找一个准备存放工程的地方,(我的是/home/admin-hjj/program),命令行

    cd /home/admin-hjj/program/

    25. 定位编译链,启动PetaLinux:根据安装petalinux的路径:

    source /home/admin-hjj/PetaLinux/settings.sh

    26. 创建PetaLinux工程:将在PRO目录下面,创建一个工程:

    petalinux-create --type project --template zynq --name h2_petalinux_test

    ° zynqMP (for UltraScale+ MPSoC)
    ° zynq (for Zynq)
    ° microblaze (for MicroBlaze)

    h2_petalinux_test是工程名,该命令会自动在program文件夹里创建h2_petalinux_test文件夹。

    27. 引用刚才输出的硬件描述文件:把之前导出的硬件描述文件design_ZYNQ_wrapper.hdf拷贝到虚拟机中的h2_petalinux_test工程文件夹下,然后在shell中输入:

    cd h2_petalinux_test         //进入到petalinux工程目录下

    petalinux-config --get-hw-description=/home/admin-hjj/program/h2_petalinux_test

    注意:此命令中不可随意添加空格,要先进入petalinux工程目录下再执行此命令。

    会进入一个配置界面,在里面我们可以配置一些系统参数,主要的配置包括:启动方式,启动存储器分区表,启动文件名称等等,本文暂不对其修改(默认是从SD卡中启动),然后等待其配置(时间较长)

    *** End of the configuration.

    *** Execute 'make' to start the build or try 'make help'.

    [INFO] sourcing bitbake

    [INFO] generating plnxtool conf

    [INFO] generating meta-plnx-generated layer

    [INFO] generating machine configuration

    [INFO] generating bbappends for project . This may take time !

    [INFO] generating u-boot configuration files                                                                              

    [INFO] generating kernel configuration files

    [INFO] generating kconfig for Rootfs

    [INFO] oldconfig rootfs

    [INFO] generating petalinux-user-image.bb

    28. 获取文件夹权限 :在上一步完成后,输入命令sudo chmod -R 777 /home/hlf获取文件夹权限(工程文件夹和petalinux的安装文件夹),否则编译的时候,会发生错误。

    sudo chmod -R 777 /home/admin-hjj/program/h2_petalinux_test

           目前为止,在shell中的命令既可以以超级用户su的身份运行也可以以普通用户的方式运行(建议全部都用普通用户的方式,免得切换),但是等下编译u-boot和kernel以及rootfs的时候,必须以普通用户的身份运行命令行,否则会报错的。

    29. 编译u-boot

           注意:到此处的时候,不能再用超级用户了,要切换到普通用户下,之后的所有操作都在普通用户下
    普通用户的shell中输入

    petalinux-config -c u-boot

    (依然要事先输入source /home/hlf/mnt/petalinux/settings.sh命令),然后等待GUI出来,这里暂时不改动啥,直接save(save为u-boot.config,名字随便取但不要留空),然后继续等(新建工程要等的时间还是比较长的,后来就会好的。

    30. 编译kernel

    petalinux-config -c kernel

    31. 编译文件系统

    petalinux-config -c rootfs

    32. 编译工程

    petalinux-build

    会自动在images/linux生成zynq_fsbl.elf文件。

    33. 生成BOOT.BIN

    把shell定位到image/linux目录下,同时将vivado中生成的.bit文件拷贝至image/linux,执行命令:

    petalinux-package --boot --format BIN --fsbl zynq_fsbl.elf --fpga system_wrapper.bit --u-boot

    在文件夹下就可以发现,多了一个BOOT.BIN

    展开全文
  • 所以又花些时间精力在zynq linux开发上,解决了一些困扰。没有付出就没有回报啊,之前遇到一点小困难就知难而退,现在迎难而上才解决了问题。总的来说,还算蛮顺利的,做一个简单的总结吧。对u...

    这两个月在专业方面落下了不少,下了班之后,基本都是玩。聊天、看视频什么,锻炼身体也不是很多。直到最近,一来是觉得自己有些不像话,有些事一拖再拖,二来是觉得玩得无聊,三是看到别人都那么努力,自己这样子实在不像样。所以又花些时间精力在zynq linux开发上,解决了一些困扰。

    没有付出就没有回报啊,之前遇到一点小困难就知难而退,现在迎难而上才解决了问题。总的来说,还算蛮顺利的,做一个简单的总结吧。

    对uboot和linux内核的理解又多了一些。从接触zynq linux开发,就一直被digilent为zedboard提供的出厂设计oob design限制着,好多学习都是基于当时提供的源码进行修改。但是,毕竟是n年前的东西了,一直用着老的很不爽,而且打印信息时不时就冒出来“zed”、“zedboard”。期间多次想花时间把这些打印信息全部更换掉,由于种种原因没有动手,一直拖到了现在…

    截止到昨天,做了以下变更:

    - 参照adi官网教程搭建了支持linux的vivado工程,版本为2015.2,2015.4应该也可以直接用,更新的版本未测试。

    143506-6361039842761000009185730.png

    - 修改了uboot源码,将编译前配置指令改为make zynq_miz702_defconfig; 将串口终端打印提示符由“zynq>”改为“miz702>”

    143506-6361039842641900005290509.png

    - 修改uboot设备树文件,将“zed”、“zedboard”等字眼替换掉

    143506-6361039842645700001276417.png

    - 修改了linux内核源码和文件系统,将编译前配置指令改为make zynq_miz702_defconfig; 将串口终端打印提示符由“zynq>”改为“miz702>”

    143506-6361039842655200002248232.png

    - 修改内核设备树文件,将“zed”、“zedboard”等字眼替换掉

    143506-6361039842735300005201355.png

    - 使用了新的硬件平台和内核之后,之前调试成功的usb摄像头项目无法正常捕捉图像。分析并解决了该问题

    143506-6361039865065900004584527.png

    既然在新的平台上也能跑起来Ramdisk文件系统,下一步就要把之前做的GPIO demo移植过来了,然后再用Qt做个GUI操作GPIO驱动。

    展开全文
  • Zynq开发简述

    2018-11-20 14:27:36
    1 Zynq开发四种方式 纯PL开发,纯PS开发(helloworld),PS+PL(无操作系统,跑裸跑程序),PS+PL(跑操作系统)。 1.1 纯PL开发 这个和一般的xilinx的FPGA没有很大的区别。 1.2 纯PS开发 典型的就是hello...

    1 Zynq的开发四种方式

    纯PL开发,纯PS开发(helloworld),PS+PL(无操作系统,跑裸跑程序),PS+PL(跑操作系统)。

    1.1 纯PL开发

    这个和一般的xilinx的FPGA没有很大的区别。

    1.2 纯PS开发

    典型的就是helloworld工程, 一种是传统的arm的方式。还一种就是xilinx方法,这个是生成一个elf文件,这个elf文件包括了硬件配置信息(xmp),和裸跑程序(c文件)。

    1.3 PS+PL(不跑操作系统)开发

    这个可以参考懒兔子博客二,三笔记,生成的elf文件包括了硬件配置信息(xmp),还有裸跑程序(c文件),另外还有一个.bit文件可以看出和纯PS开发的区别了。

    1.4 PS+PL(跑操作系统)开发

    这个就需要BOOT.BIN,设备树,linux内核镜像,文件系统了。

    其中BOOT.BIN是由3部分组成的(boot.elf, .bit, fsbl.elf),boot.elf这个是由交叉编译环境产生的,相当于ssbl,.bit文件是PL使用文件,fsbl.elf这个是fsbl。

    2 开发工具

    2.1 独立开发环境

    PL—>Vivado

    PS(ARM)–>SDK(Xilinx)或者第三方ARM开发工具

    2.2 集成开发环境

    SDSoC

    2.3 独立开发环境的四个步骤

    (1) 系统架构师确定硬件-软件分区方案;

    (2) 硬件工程师处理被分配到硬件中的功能,并将它们转换或设计成IP核(Verilog/VHDL,也可用Vivado HLS实现C/C++高层次综合);

    (3) 利用Vivado IP Integrator 创建整个嵌入式系统的模块化设计。包括开发需要的数据移动工具(AXI-DMA、AXI Memory Master、AXI-FIFO 等),以及连接 PL IP 与 PS 的 AXI 接口(GP、HP 和 ACP),之后将此项目导入到SDK中;

    (4) 软件工程师使用SDK,开发PS中ARM处理器的驱动程序和应用。

    对于以硬件为中心的优化流程,矛盾往往出现在不同的数据移动工具和PL-PS接口以及写入和调试驱动程序与应用,为避免重构硬件造成软件的变化,使得PS-PL开发更加紧密,赛灵思推出了SDSoC开发环境。将上述步骤(2)、(3)和(4)实现高度自动化,以缩短开发时间。该开发环境会生成必要的硬件和软件组件,用以同步硬件和软件并保存源程序语义,同时支持任务级并行处理和流水线化的通信与计算,从而实现高性能。SDSoC 环境会自动安排所有必要的赛灵思工具(Vivado、IP Integrator、HLS 和 SDK),以生成针对 Zynq SoC 的完整软硬件系统,而且所需的用户介入程度很小。

    一个SDSoC设计项目是建立在一个“平台”之上的。所谓“平台”包含硬件平台和软件平台两个部分,是一个设计开发可以复用的基础性系统。

    平台是利用标准的Vivado、SDK和OS工具创建的。硬件平台(HPFM)定义了诸如处理系统(PS,Processing System)、I/O子系统、存储器接口等,这些工作都基于一个定义明确的端口接口(AXI、AXI-S,、时钟、复位、中断)。软件平台(SPFM)定义了OS、设备驱动、启动加载程序(boot loaders)、文件系统、库等。

    基于C/C++源代码的定制和专用硬件和软件,用户可以扩展平台。

    SDSoC将平台作为独立的解决方案空间,基于平台提供的资源去生成用于解决方案的IP。每个解决方案都是为一个平台裁剪而成的。

    一个扩展名为xpfm的文件包含了硬件描述符XML文件(HPFM)和软件描述符XML文件(SPFM)位置的参考。

    2.4 Vivado

    Vivado是基于IP的设计,称为block design(BD),调用已有的IP,用户自己编写的逻辑模块也可以封装成IP,然后在模块blcok中连线。逻辑开发完毕,再转到SDK,SDK会根据Vivado的硬件设计设置调用相应的内部驱动代码。(PL部分就如同ARM的总线AXI等挂的外设)

    2.5 SDK

    SDK根据生成的.hdf文件匹配FSBL,只需添加main.c文件即可。

    3 类似嵌入式 C/C++/OpenCL 应用开发的体验–SDSoC

    SDSoC™ 开发环境可为异构 Zynq® AllProgrammable SoC 及 MPSoC 部署提供类似嵌入式 C/C++/OpenCL 应用的开发体验,其中包括简单易用的 Eclipse IDE 和综合设计环境。SDSoC 提供业界首款 C/C++/OpenCL 全系统优化编译器,可实现系统级的特性描述、可编程逻辑中的自动软件加速、自动系统连接生成以及可加速编程的各种库。此外,它还可帮助最终用户及第三方平台开发人员快速定义、集成和验证系统级解决方案,为其最终用户实现定制化编程环境。(软件工程师能够对 Zynq SoC 中的可编程逻辑和 ARM 处理系统进行编程)

    l 简单易用的 EclipseIDE 可用于开发支持嵌入式 C/C++/OpenCL 应用的全面 Zynq All Programmable SoC 和 MPSoC 系统

    l 只需一点按钮,就可对可编程逻辑 (PL) 中的功能进行加速

    l 支持作为目标 OS 的裸机、Linux 与 FreeRTOS

    l Xilinx 库作为 Vivado HLS 的一部分,由联盟成员提供,是可选硬件优化的库。

    l OpenCL 在 2016.3 版中为早期的测试版。请联系您的当地销售代表提出申请

    下图展示的是一个基于基础平台的完整SDSoC设计的整体结构。需要加速的C/C++/SystemC功能成为了FPGA可编程逻辑(PL)中的IP,而其他功能保留在处理器系统(PS)中。同时,SDSoC会在那些IP和PS系统间自动生成互连。
    在这里插入图片描述

    3.1 系统级的特性描述

    l 快速性能估算与面积估算可在几分钟内完成,包括 PS、数据通信以及 PL

    l 高速缓存、存储器以及总线利用率的自动运行时仪表

    l 可实现最佳总体系统架构的便捷生成与探索

    在这里插入图片描述

    3.2 全系统优化编译器

    l 可将C/C++/OpenCL 应用编译成全功能 Zynq SoC 与 MPSoC 系统

    l 可在生成 ARM 软件与 FPGA 比特流的可编程逻辑中实现自动功能加速

    l 不仅可优化系统连接,而且还支持吞吐量、时延以及面积权衡的快速系统探索

    3.3 SDSoC开发流程

    1. SDSoC 环境使用快速估算流程(通过调用内含的Vivado HLS)构建应用项目。这样在数分钟内就能大致估算出性能和资源情况。

    2. 如果有必要,用适当的指令优化 C/C++ 应用和硬件功能,并重新运行估算直到实现所需的性能和占位面积。

    3. 然后,SDSoC 环境构建整个系统。该过程会生成完整的 Vivado Design Suite 项目和比特流,以及一个针对 Linux、FreeRTOS 或裸机的可引导的运行时间软件映像。

    展开全文
  • 基于ZYNQ linux CAN通讯开发。vivado端的PS-PL配置,sdk端例程
  • ZYNQ 7000 Linux工程开发

    2019-12-11 17:52:49
    虚拟机软件版本:VMware14.1.1 Linux系统版本:ubuntu-16.04.6 petalinux版本:petalinux-v2019.2 vivado版本:Vivado 2019.2
  • 笔者之前从事的是imx平台的linux开发,之后工作需求转到Xilinx推出的zynq系列芯片的开发,以下内容是笔者在适用zynq平台中遇到的不同于传统linux开发的内容,期间踩了不少坑,笔者希望能够帮助读者理解zynq开发,...
  • 《领航者ZYNQLinux驱动开发指南_V1.3.pdf》非常好的正点原子zynqlinux驱动资料,值得拥有,希望对你的工作学习有所帮助。
  • ZYNQ 开发

    千次阅读 2015-03-17 17:39:45
    ZED-Board从入门到精通系列(六)——Vivado+OpenRISC...由于更新了开发工具,所以本篇博客有必要重复前面的内容,今天首先演示如何利用Vivado开发纯逻辑工程,即只在PL上进行开发。恰好最近在看雷思磊的《步步惊芯——
  • ZYNQ 开发流程

    2020-05-12 10:38:49
    ZYNQ开发也是先硬件后软件的方法。具体流程如下: 1) 在 Vivado 上新建工程,增加一个嵌入式的源文件。 2) 在 Vivado 里添加和配置 PS 和 PL 部分基本的外设,或需要添加自定义的外设。 3) 在 Vivado 里生成顶层 ...
  • 《领航者ZYNQLinux开发指南》,非常详实的zynqlinux开发资料,希望对你的工作学习有所帮助。
  • 1.烧写Linux相关文件 将生成的uImage,device.dtb,fpga.bit以及uramdisk.image.gz文件烧写到单板的flash当中,步骤如下: 以下是flash的分区规划 BOOT.bin 0x0~0xe0000 Env.txt ...
  • Xilinx Zynq开发教程

    2020-02-17 22:44:01
    首先开发arm cpu的工具有两种,如果不跑linux操作系统,那么就用vitis就够了,如果跑linux操作系统,那么则需要xilinx的petalinux工具,vitis支持linux和windows两种操作系统,但是petalinux只支持linux操作系统。...
  • 该ppt讲述了zynq的普通开发流程,包括vivado block设计,sdk设计,linux内核裁剪等
  • ZYNQ开发笔记

    2018-01-09 17:07:31
    1、Linux编译  将zynq_zed_defconfig文件拷贝到arch/arm/configs目录下  make ARCH=arm xilinx_zynq_defconfig  make ARCH=arm menuconfig  make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- UIMAGE_...
  • 背景: 为了优化socket TCP的传输速率,使代码更具有移植性,遂产生使用nanomsg代替socket TCP的想法。 nanomsg是一个socket library,它提供了几种常见的通信模式,网络层... 本文是在为了开发Xilinx Zynq一款...
  • ZYNQ7000 Linux开发步骤

    2021-08-21 01:09:27
    2、配置ZYNQ7000的ARM核; 3、开发用户自定义的IP核; 4、编译并生成bit文件; 5、导出硬件信息; 参考资料: STEP2.新建和配置Petalinux工程 1、新建Petalinux工程; 2、导入硬件信息; 3、配置Petalinux工程; 4、...
  • HLS自定义IP核在linux下的调用-以adder为例 使用HLS生成自定义IP核 注意:这里将输出输出参数均指定为AXI_Lite接口,并指定return以创建模块的中断端口。 void adder(int a, int b, int& c) { #pragma HLS ...
  • Linux + FreeRTOS 1.创建FreeRTOS工程 使用ps7_cortexa9_1创建FreeRTOS工程,示例如下 修改main.c 去掉xil_printf相关的调用,根据FPGA工程师提供的寄存器地址和bit文件操作LED周期闪烁 修改lscript.ld文件地址...
  • ZYNQ Linux开发——以太网配置

    千次阅读 2017-08-28 20:07:17
    开发环境:Widows下Vivado 2016.2 、 SDK2016.2 、 Linux机器:debin 材料:Xilinx Github中的U-BOOT、Kernel、Ramdisk、Config_patch等在进行NFS启动时配置目标板网络遇到问题:执行ifconfig -a 命令没有出现eht0...
  • ZYNQ开发流程

    2019-01-10 16:19:00
    1 开发工具1.1 独立开发环境PL—>VivadoPS(ARM)-->SDK(Xilinx)或者第三方ARM开发工具1.2 集成开发环境SDSoC1.3 总结Ø 独立开发环境大概分为四个步骤:(1) 系统架构师确定硬件-软件分区方案;(2) 硬件...
  • zynq linux 开发环境搭建

    千次阅读 2015-11-11 13:57:13
    1、安装基本开发工具:sudo apt-get install build-essential ,sudo apt-get install libncurses5-dev; 2、在安装交叉编译工具之前,输入命令“sudo dpkg-reconfigure dash”,选择“否”,退出; 3、运行“xilinx...
  • 移植LinuxZYNQ

    千次阅读 2019-09-06 19:13:25
    ZYNQ移植Linux博客说明开发环境移植u-boot 博客说明 撰写日期 2019.09.06 完稿日期 2019.09.09 最近维护 暂无 本文作者 multimicro 联系方式 multimicro@qq.com 资料链接 本文无附件资料 GitHub ...
  • 这个系列包含了我一步一步让ZYNQ从裸跑到自己的小操作系统,到LinuxC,LinuxDriver在到PYNQ的过程。其中涵盖了许多碎知识,包括AXI总线、C语言内存管理、linux的移植等等,在此也对其做一个整理。 首先,ZYNQ是一个...
  • 虚拟机软件版本:VMware14.1.1 Linux系统版本:ubuntu-...此工程是在《ZYNQ 7000 Linux工程开发》基础上进行的。 一、创建helloworld驱动 进入上次建立好的linux工程中,命令如下: cd test_project 创建hellowor...
  • 菜鸟搭建zynq linux开发平台

    千次阅读 2017-10-19 10:54:29
    本人机械出生,毕业后先做了两年FPGA,然后做IC开发,所以对linux一窍不通。无奈来了一家小公司,所有的环境都要自己搭,这里将自己的坑全部献上,希望能提供一些借鉴 第一步: 安装虚拟机  1、注意事项  linux...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,202
精华内容 880
关键字:

linuxzynq开发

linux 订阅