ZYNQ有两个CPU?(二)——OCM共享内存

在上一篇文章中,我们搭建了一个AMP的环境,而且在CPU0和CPU1上分别跑了两个没有交集的线程。这篇文章中我们需要让两个CPU之间能够进行通信。而传递数据采用了共享内存,我们将共享内存设置在OCM(On Chip Memory)内。

在我们的设计中CPU0负责进行显示控制7段数码管和LED灯,显示的数据从OCM中定义的显示缓冲区读取,采用定时器中断进行刷新扫描显示;CPU1负责进行键盘扫描,通过GPIO中断扫描4位独立按键和4×4矩阵键盘的键值,将对应键值的显示码按照循环的方式写入OCM中的显示缓冲区。


#define DISPLAY_BUF             ((volatile unsigned char *)(0xFFFF0000U))
//显示缓冲区按字节访问限定为8字节


我将显示缓冲区的8个字节定义在了OCM的最后一块儿中。

在没有做其他设置的情况下ZYNQ上电后地址空间分别如上图所示。OCM共256KB按照64KB分为4块,其中前三块在SDK中表述为RAM0占192KB处于地址空间的最开头和DDR共用地址空间,最后一块64KB处于地址空间的最后。ZYNQ的DDR固定占地址空间的最开头1GB字节因而ZYNQ的DDR最大容量就只有1GB。为了避开OCM从上图可知实际使用的DDR只有1023MB(最开头的1MB被保留避开OCM的前三块)。从0x40000000到0xDFFFFFFF的2GB空间留给了自定义IP或者其他IP的寄存器,从BSP的xparameters.h可以看出在PL部分添加的IP其基址都是从0x40000000开始的,而ZYNQ自己的寄存器则从0xE0000000开始编制,具体寄存器内容请查阅UG585的附录B Register Details。其实Standalone作为基础的BSP所作的工作都是在通过指针访问各个寄存器而已,在不考虑安全性的前提下可以完全不用BSP直接操作寄存器对ZYNQ进行操作。


下面是程序运行后的几张效果图:

由于工程比较大,这里就只把和OCM相关的代码贴出来和大家分享了。

在CPU0和CPU1的C源文件中均在相同的地址定义OCM的8字节为显示缓冲区:

#define DISPLAY_BUF             ((volatile unsigned char *)(0xFFFF0000U))
//显示缓冲区按字节访问限定为8字节该定义应在两个CPU的源文件中均定义

CPU0中唤醒CPU1的地址定义

#define CPU1STARTADR            0x20000000U//CPU1的DDR起始地址从512MB字节开始
#define CPU1_START_UP_REG       0xFFFFFFF0U//用来存储上面地址的指针地址

CPU0中禁止OCM的Cache属性和唤醒CPU1的代码

    //Disable cache on OCM
    Xil_SetTlbAttributes(0xFFFF0000,0x14de2);  
    // S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0
    print("CPU0: writing startaddress for cpu1\n\r");
    Xil_Out32(CPU1_START_UP_REG, CPU1STARTADR);
    //该函数需包含xil_io.h
    //CPU1STARTADR=0xFFFFFFF0, CPU1STARTADR=0x20000000);
    dmb(); //waits until write has finished
    print("CPU0: sending the SEV to wake up CPU1\n\r");
    sev();
    dmb(); //waits until write has finished

CPU1中禁止OCM的Cache属性

    //Disable cache on OCM
    Xil_SetTlbAttributes(0xFFFF0000,0x14de2);           
    // S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0

CPU1扫描到按键后填充显示缓冲区的代码

   TimerExpired=(TimerExpired+1)%BUF_SIZE;
   //循环移动显示缓冲区的写入指针
   DISPLAY_BUF[TimerExpired]=Display_Code[KEY_Value-1];
   //在指针位置写入键值
   DISPLAY_BUF[BUF_SIZE]=TimerExpired;
   //记录新按键键值的指针位置
   xil_printf("CPU1: New key has been pushed ,update the display buffer.\r\n");

CPU0在定时器中断中读取显示缓冲刷新显示的代码

   XScuTimer_ClearInterruptStatus(TimerInstancePtr);
   //清除定时器中断标志
   TimerExpired=(TimerExpired+1)%4;
   //循环移动显示缓冲区读取指针
   XGpio_DiscreteWrite(&Gpio_LEDS, SEG_CHANNEL, 
    emerge_ledbus(DISPLAY_BUF[TimerExpired],
    DISPLAY_BUF[TimerExpired+4],Selected_Code[TimerExpired]));
   //将对应缓冲区内容送到7段数码管上
   XGpio_DiscreteWrite(&Gpio_LEDS, LED_CHANNEL, DISPLAY_BUF[DISPLAY_BUF[BUF_SIZE]]);
   //将最新一个按键的键值送到LED灯上

接下来是验证视频

如有问题欢迎评论留言或关注码峰社嵌入式群541931432进行讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值