Zynq 【SDK裸机开发之PS】——DDR的内存分配使用详解

5 篇文章 17 订阅
5 篇文章 0 订阅

关注+星标G众,及时获取更多技术分享~ 

 作者 | 冰茶奥利奥

G众号 | 嵌入式电子创客街

Zynq如果跑操作系统的话,内存管理的工作都会交给系统来操作,但是如果是裸机的话,则需要

自己对DDR3的内存进行管理。

PS端操作DDR3相对简单,因为在vivado导出硬件时候,就已经给我们分配好了DDR3的地址,如下图所示,Ps7_ddr_0是系统给DDR分配的地址映射,因为我只有一片DDR3,所以Size大小是0x1FF00000,也就是512MB。

网上的一些操作DDR的教程大多是直接操作的地址,对DDR中一个地址的直接操作是没有问题的,因为程序编译时会识别你对这些地址的操作,就不会往这些地址里放变量或者其他的一些数据。

但是如果你是在程序中,以数组的方式来操作DDR3的话,就有很大概率可能性发生内存泄漏,也叫段错误,也叫野指针等等。直接进xil的程序异常中断,这种情况下,就不要在铤而走险强行操作DDR了。那么怎么办呢,我们需要在工程生成的lscript.ld中分配我们的memory。

我们打开这个界面后看下方的选项卡可以在UI和脚本文件进行切换,我们先在界面里点击Add Memory。我这里添加了一个叫做ps7_ddr_0_user的内存空间,编辑我们需要的地址和长度。保存后切换到脚本文件可以看到memory里已经为我们写好了好了地址和长度。

MEMORY
{
   axi_bram_ctrl_0_Mem0 : ORIGIN = 0x40000000, LENGTH = 0x1000
   ps7_ddr_0 : ORIGIN = 0x100000, LENGTH = 0x1FF00000
   ps7_qspi_linear_0 : ORIGIN = 0xFC000000, LENGTH = 0x1000000
   ps7_ram_0 : ORIGIN = 0x0, LENGTH = 0x30000
   ps7_ram_1 : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00
   ps7_ddr_0_user  : ORIGIN = 0x6500000, LENGTH = 0x9B00000
}

那么我们程序里引用他的时候则需要指定一块空间,怎么指定这段内存空间呢,则需要在脚本里添加下面的语句,我这里把这段空间命名为了user_memory。

.user_memory : {
   __user_memory_start = .;
   *(.user_memory)
   *(.user_memory.*)
   __user_memory_end = .;   

} > ps7_ddr_0_user

点击保存后可以看到内存映射里已经把我的设置添加进来了。

空间开辟成功,我们在程序里怎么引用呢,我们需要定义一个全局的指针变量或者数组,用attribute强制修饰符来修饰,让他指定分配到我们的"user_memory"这个section。接下来就可以使用指针直接操作这片空间了。

我自己想写一个DDR的malloc,现在还没有时间实现,现在只是返回了一个指针,用于app层调用。

uint8_t *DDR3UserMemory __attribute__((section(".user_memory")));

以下是源文件和头文件,供参考。

/*
 * ddr_mem_manage.h
 *
 *  Created on: 2022年4月20日
 *      Author: Lisboa
 * DDR3留给系统占用 0~100M处
 * 分配用户占用 100~156M处
 *             eeprom  100~101M处
 *             远程升级 101~处
 * PL地址映射0x10000000 255~512M处
 */

#ifndef SRC_DDR_MEM_MANAGE_H_
#define SRC_DDR_MEM_MANAGE_H_

/***************************** Include Files *********************************/

#include <stdio.h>
#include "xparameters.h"
#include "xil_types.h"
/************************** Constant Definitions *****************************/

#define DDR_BASEADDR        XPAR_PS7_DDR_0_S_AXI_BASEADDR
#define DDR_HIGHADDR        XPAR_PS7_DDR_0_S_AXI_HIGHADDR
#define DDR_MEM_MAX_SIZE    (DDR_HIGHADDR - DDR_BASEADDR)
/**************************** Type Definitions *******************************/

#define _ADDR_OFFSET       unsigned int
typedef _ADDR_OFFSET       _addr_offset;
/************************** Function Prototypes ******************************/

extern _PTR ddr_calloc(size_t __nmemb, size_t __size, _addr_offset __ddroffset);
extern _PTR ddr_get_baseaddr(_addr_offset __ddroffset);
/************************** Variable Prototypes ******************************/



#endif /* SRC_DDR_MEM_MANAGE_H_ */

/*
 * ddr_mem_manage.c
 *
 *  Created on: 2022年4月20日
 *      Author: Lisboa
 */

/***************************** Include Files *********************************/
#include "ddr_mem_manage.h"

/************************** Constant Definitions *****************************/

#define DDR_USER_BASEADDR   0x6500000
#define DDR_USER_SIZE       0x9B00000   //155M
/**************************** Type Definitions *******************************/


/************************** Variable Definitions *****************************/

uint8_t *DDR3UserMemory __attribute__((section(".user_memory")));
/************************** Function Definitions *****************************/


_PTR ddr_calloc(size_t __nmemb, size_t __size, _addr_offset __ddroffset)
{
    if((__nmemb * __size <= DDR_USER_SIZE) && (__ddroffset <= DDR_USER_SIZE))
    {
        return (_PTR)(&DDR3UserMemory + __ddroffset);
    }
    else
    {    
    	return NULL;
    }
}
_PTR ddr_get_baseaddr(_addr_offset __ddroffset)
{
    if(__ddroffset <= DDR_USER_SIZE)
    {
        return (_PTR)&DDR3UserMemory + __ddroffset;
    }
    else
    {
		return NULL;
    }
}

解决这个问题时在网上找了一大圈,就一个答案来回抄,答案还是半个的。用Zynq的人全国可能超不多1w人,裸机开发的不到5000人,PS-PL全栈开发的可能不足1000人。这个圈子实在太小,大多数人又都是研究所或者院校的,属于不太分享的那一种人,这也就让大家遇到问题只能抓瞎,我决定从我自己做起改善国内的Zynq环境,有什么积累就及时分享,一是为锻炼自己的总结能力,二也算为后人栽树了。

如果您觉得这篇文章帮到了你,请点赞或者留下您的评论,您的鼓励是我前进的动力~

关注博主G众号 “嵌入式电子创客街” 获取更多及时技术分享~

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值