目录
- 一、参考资料
- 二、裸机下,读写DDR
- 三、LINUX下,读写DDR
- 四、简单的核间通信
Zynq构建SoC系统深度学习笔记-03-PS读写DDR内存(1)
通过devmem访问物理地址
ZYNQ有两个CPU?(二)——OCM共享内存
测试代码如下:
#include
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#include "xil_mmu.h"
#define TEST_ADDR 0x1F000000
void WRITE_DDR(u8 ddr_value)
{
xil_printf("\r\nwrite data\r\n");
u32 addr=TEST_ADDR;
u32 i;
for(i=0;i<10;i++)
{
Xil_Out8(addr++,ddr_value);
xil_printf("ddr_value=0x%X,",ddr_value);
}
xil_printf("\r\n");
}
void READ_DDR(void)
{
xil_printf("\r\nraed data\r\n");
u32 addr=TEST_ADDR;
u32 i;
u8 ddr_value;
for(i=0;i<10;i++)
{
ddr_value=Xil_In8(addr++);
xil_printf("ddr_value=0x%X,",ddr_value);
}
xil_printf("\r\n");
}
void soft_delay(u32 count)
{
for(;count>0;count--);
}
int main()
{
print("Hello World\n\r");
Xil_SetTlbAttributes(TEST_ADDR,0x14de2); //关闭cache
READ_DDR();
u8 value=0x0;
while(1)
{
READ_DDR();
WRITE_DDR(value++);
READ_DDR();
soft_delay(0xfffffff);
}
return 0;
}
1.涉及到一个工具:devmem。其用法如下:
root@zedboard:~# devmem
BusyBox v1.24.1 (2019-11-28 16:33:01 CST) multi-call binary.
Usage: devmem ADDRESS [WIDTH [VALUE]]
Read/write from physical address
ADDRESS Address to act upon
WIDTH Width (8/16/...)
VALUE Data to be written
实验效果如下:
root@zedboard:~# devmem 0x10000000 8
0xD0
root@zedboard:~# devmem 0x10000000 8 0x63
root@zedboard:~# devmem 0x10000000 8
0x63
2.LINUX应用程序调用函数
/*
* ddr read linux application interface
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*****************************************************************************/
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
#define MAP_SIZE 4096UL //映射的内存区大小(一般为一个叶框大小)
#define MAP_MASK (MAP_SIZE - 1) //MAP_MASK = 0XFFF
/*****************************************************************************/
#define TEST_ADDR 0x1F000000
/*****************************************************************************/
/**
* @brief 从实际物理地址读取数据。
* @details 通过 mmap 映射关系,找到对应的实际物理地址对应的虚拟地址,然后读取数据。
* 读取长度,每次最低4字节。
* @param[in] readAddr, unsigned long, 需要操作的物理地址。
* @param[out] buf,unsigned char *, 读取数据的buf地址。
* @param[in] bufLen,unsigned long , buf 参数的容量,4字节为单位,如 unsigned long buf[100],那么最大能接收100个4字节。
* 用于避免因为buf容量不足,导致素组越界之类的软件崩溃问题。
* @return len,unsigned long, 读取的数据长度,字节为单位。如果读取出错,则返回0,如果正确,则返回对应的长度。
*/
static int Devmem_Read(unsigned long readAddr, unsigned long* buf, unsigned long len)
{
int i = 0;
int fd,ret;
int offset_len = 0;
void *map_base, *virt_addr;
off_t addr = readAddr;
unsigned long littleEndianLength = 0;
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
{
fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
return 0;
}
/* Map one page */ //将内核空间映射到用户空间
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr & ~MAP_MASK);
if(map_base == (void *) -1)
{
fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
close(fd);
return 0;
}
for (i = 0; i < len; i++)
{
// 翻页处理
if(offset_len >= MAP_MASK)
{
offset_len = 0;
if(munmap(map_base, MAP_SIZE) == -1)
{
fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
close(fd);
return 0;
}
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr & ~MAP_MASK);
if(map_base == (void *) -1)
{
fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
close(fd);
return 0;
}
}
virt_addr = map_base + (addr & MAP_MASK); // 将内核空间映射到用户空间操作
buf[i] = *((unsigned long *) virt_addr); // 读取数据
addr += 4;
offset_len += 4;
}
if(munmap(map_base, MAP_SIZE) == -1)
{
fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
close(fd);
return 0;
}
close(fd);
return i;
}
/*
* test sample
*/
int main(void)
{
unsigned long len = 2;
unsigned long readData[1024*1024]; //1MB
unsigned long addr = TEST_ADDR;
unsigned long i = 0;
while(1)
{
printf("read data\n");
memset(readData, 0, len);
Devmem_Read(addr, readData, len); // 读取数据
for (i = 0; i < len; i++)
{
printf("address = 0x%08x, data = 0x%08x\n", (addr + i * 4), readData[i]);
}
sleep(1);
}
}
按照《ZYNQ下LINUX+FREERTOS同时运行》这篇文章编译CPU0程序,生成BOOT.BIN文件。运行。
注意要禁止掉cache缓存!如下,0x1F00 0000 是被禁止cache的内存地址,要根据实际情况修改。
Xil_SetTlbAttributes(0x1F000000,0x14de2); //关闭cache
本实验实现了CPU1裸核向DDR写入数据,CPU0 LINUX应用程序读取出刚写入DDR的数据。
实验效果:
CPU1(裸机)效果:
write data
ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,
raed data
ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,
raed data
ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,ddr_value=0xC6,
write data
ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,
raed data
ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,
raed data
ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,ddr_value=0xC7,
write data
ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,
raed data
ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,
raed data
ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,ddr_value=0xC8,
CPU0(LINUX),DEVMEM工具效果:
root@zedboard:~# devmem 0x1F000000 8
0xC6
root@zedboard:~# devmem 0x1F000000 8
0xC7
root@zedboard:~# devmem 0x1F000000 8
0xC8
root@zedboard:~# devmem 0x1F000000 8
0xC8
root@zedboard:~# devmem 0x1F000000 8
0xC9
CPU0(LINUX),APP效果:
read data
address = 0x1f000000, data = 0xcececece
address = 0x1f000004, data = 0xcececece
read data
address = 0x1f000000, data = 0xcececece
address = 0x1f000004, data = 0xcececece
read data
address = 0x1f000000, data = 0xcfcfcfcf
address = 0x1f000004, data = 0xcfcfcfcf