您的位置: OpenADSP社区论坛 -> Blackfin专区 -> 新手上路 -> BF609双核通信内存共享的问题(很不错的技术... 
本帖共有2589个阅读者
发表帖子 发表投票 回复主题
BF609双核通信内存共享的问题(很不错的技术问答帖)
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
楼主信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
精华主题 精华帖子
BF609双核通信内存共享的问题(很不错的技术问答帖)

1. 有没有BF609双核内存共享的例子,特别是实时,大量数据共享传输的问题?

2. BF609双核通信时,如果CORE1定义一个变量(怎么定义在共同使用的内存区),CORE1要怎么才能获取到其内存地址,实现对该变量的设置和读取,BSP例子有个消息机制实现的方式,不晓得实时性和传输速度怎么样?

3. 怎么实现内存的同步保护机制?

4. 双核时两个核core的工程是分别编译成LDR文件,在通过命令链接成一个LDR,那要生产双核的Bin格式(实际烧写到flash中的内存数据),要怎么搞?


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:23:17
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
1信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线

简单回答下问题。

1. 这个在bf609_ezkit的软件包中就有一些MCAPI例程。mpeg4_enc软件包中也有相关的应用(双核编码,每一个核编码一半的图像数据),这个例程使用MCAPI来进行核间通信,看起来更标准化,单初学者会感到很复杂。

2. 你应该看下bf609的芯片手册,有中文版的。主要关注内存地址的映射。至于速度就自己测了。


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:24:50
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
2信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线

3. 简单的就是信号量了,全局变量。

总结下3个问题:

bf609的内存可以分为三部分:L1 L2 L3。

其中L1对于两个核心来说是独立的, 两个核心有自己的L1。coreA的L1,coreB是无法访问到的。

而L2和L3就是共享的。两个核都可以访问的到。

为了防止访问冲突。cces在创建工程的时候就会自动的生成两个和内存相关的文件。

startup_ldf目录下的app_cplbtab.c和app.ldf文件。

这两个文件对内存进行了划分。两个和的project目录下都有对应的文件。

其中app_cplbtab.c负责管理当前内核可以访问的内存区域。以及对应内存区域的访问方式。

比如core0中一段描述:

   {0x00000000, (ENUM_DCPLB_DATA_16MB | CACHE_MEM_MODE)},

   {0x01000000, (ENUM_DCPLB_DATA_16MB | CPLB_DNOCACHE)},

   {0x02000000, (ENUM_DCPLB_DATA_16MB | CACHE_MEM_MODE)},

   {0x03000000, (ENUM_DCPLB_DATA_16MB | CACHE_MEM_MODE)},

   {0x04000000, (ENUM_DCPLB_DATA_16MB | CACHE_MEM_MODE)},

   {0x05000000, (ENUM_DCPLB_DATA_16MB | CPLB_DNOCACHE)},

   {0x06000000, (ENUM_DCPLB_DATA_16MB | CPLB_READONLY_ACCESS)},

   {0x07000000, (ENUM_DCPLB_DATA_16MB | CPLB_READONLY_ACCESS)},

这一共是128MB的内存空间。

CACHE_MEM_MODE 开CACHE

CPLB_DNOCACHE 关cache

CPLB_READONLY_ACCESS  只对的。

前两个就不说了,第三个表明,该区域的内存对于core0来说是只读的,不可写。如果写的话就会产生错误。

一个cplb错误。debug时候控制台就会是红字提示。(不过貌似DMA可以随意访问到)。


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:25:56
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
3信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线

如果我们将{0x05000000, (ENUM_DCPLB_DATA_16MB | CPLB_DNOCACHE)},删除的话,

那么这段空间对于当前内核来说,就是不可见的。如果通过绝对地址来访问的话,也会产生cplb错误。

比如 char *p = 0x05000000; *p = 1;  这样的代码在执行的时候就会出错。因为该地址对于当前内核来说是不可见的。(DMA除外)

而char *p = 0x01000000; *p = 1; 这样的代码执行起来没有大的问题。

这应该是Blackfin DSP的内存保护机制。不过类似这样通过绝对地址访问的代码通常是很危险的。

你要保证你访问的内存地址是安全的,不会被系统用到。

再去看看ldf文件。我自己对ldf的文件了解的不是很多。只是会用而已。从使用的观点来描述。

ldf文件描述了具体内存空间的分布。

比如ldf文件开头定义了这些段:

   MEM_SDRAM_BANK0         { TYPE(RAM) START(0x00000004) END(0x00ffffff) WIDTH(8) }

   MEM_SDRAM_BANK1         { TYPE(RAM) START(0x01000000) END(0x01ffffff) WIDTH(8) }

   MEM_SDRAM_BANK2         { TYPE(RAM) START(0x02000000) END(0x02ffffff) WIDTH(8) }

   MEM_SDRAM_BANK3         { TYPE(RAM) START(0x03000000) END(0x03ffffff) WIDTH(8) }

这些是64MB的内存空间。表明当前coreA中的一些数据和代码都放在了DDR2的前64MB内存中。

后面会有对这些内存空间的具体定义。比如代码段,数据段,堆栈等。

有了这些定义,就可以保证,工具链在连接生成可执行程序时,不会访问到其他的内存空间。

L1和L2类似。

你去看下coreB project中的cplbtab.c和app.ldf文件。会发现有同样的内存定义。只是内存的地址和参数是不一样的。

既然懒的看英文文档,那就要通过多试验多对比来发现他们的原理。

默认情况下新生成的project。L2和L3是这么定义的。

L2分为三部分。ICC两个核心都可见,是共享区域,内存地址是一样的(这是MCAPI用于通信的)。 另外两个区域coreA和coreB各占一个,内存地址是不一样的。

L3就分为两部分。 coreA占用前一半,coreB占用后一半。

上述就是内存布局的一个简单的描述。


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:26:10
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
4信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线

知道了内存的布局,结合自己以前学习的进程间通信的方式。就不难想出使用共享内存的方法。

把coreA和coreB看做两个独立的程序。两个程序都有自己的main函数。那两个程序如何通信呢?

如果带有操作系统的话,可以使用共享内存,共享内存的地址就是一个文件描述符。 对于Blackfin这种没有MMU的芯片

来说就很简单了,直接通过绝对地址就OK了。那共享内存怎么创建的呢? 前面不是说过对于两个核来说 L2和L3都是共享的吗?

对边在L2和L3开辟一段空间就行了。共享的地址,你知,coreA知,coreB也知。

这里完全抛开MCAPI的方式来实现共享内存。(MCAPI没用过,一直懒的去看)

我们定义两个共享内存,分别放在L2和L3中。一个作为双核通信用到的变量标记,一个作为大的缓冲区。

L2的速度要比L3快,因为L2的共享内存用于核间通信时的信号量。 L3就是缓冲区了。

L2的共享内存就用现成的。

MEM_L2_SRAM_ICC         { TYPE(RAM) START(0xC8080000) END(0xC808041F) WIDTH(8) }

这个段的定义,在两个核中是完全一模一样的。

L3的共享内存需要修改各自的cplb和ldf文件。我们把整个DDR2最后8MB空间作为共享内存。

coreA的cplbtab.c这么改: 这样的话coreA就可以访问该内存空间了。

{0x07000000, (ENUM_DCPLB_DATA_16MB | CPLB_READONLY_ACCESS)},  --》{0x07000000, (ENUM_DCPLB_DATA_16MB | CACHE_MEM_MODE)},


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:26:31
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
5信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线

coreA的ldf:

不改。

coreB的cplbtab.c这么改:

不改能用吗?

coreB的ldf:

MEM_SDRAM_BANK3         { TYPE(RAM) START(0x07000000) END(0x07ffffff) WIDTH(8) } -----》

MEM_SDRAM_BANK3         { TYPE(RAM) START(0x07000000) END(0x077fffff) WIDTH(8) }

MEM_SDRAM_BANK_SHARE    { TYPE(RAM) START(0x07800000) END(0x07ffffff) WIDTH(8) }   (我没分错误吧?)

好了,内存的分配完成了。0x07800000和0xC8080000这两个内存地址。就由用户自己来管理了。(注意是在没有用MCAPI的情况下)

然后我们编写代码:(coreA和coreB都加入同样的代码。)

typedef struct

{

   uint8_t flagA;

   uint8_t flagB;

   void  *pBuf;

}MY_ICC;

struct MY_ICC *goMyIcc = (struct MY_ICC *)0xC8080000;   (对于c语言不太自信,不知道写的对否。大概意就是把结构体的地址指向固定的内存地址。 结构体定义根据需要自己发挥)。

goMyIcc->flagA = 0;

goMyIcc->flagB = 0;

goMyIcc->pBuf = (void *)0x07800000;


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:26:52
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
6信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线

结构体的定义和声明以及地址赋值在两个core都要写。 赋值在一个core就行了。因为内存地址是一样的吗。

这样的话,当任意一个核去改变goMyIcc中的值时,另外一个核中的值也会跟着变化。

剩下的就靠用户自己发挥了。

当然还有一些细节,比如要避免两个核频繁的访问共享内存。

while(1)

{

if(goMyIcc->flagA)

{

    ;

}

}  //这样的代码是不能出现的。

可以这么写

while(1)

{

if(goMyIcc->flagA)

{

    ;

}

else

{

   延时1ms,或者去干些别的事儿。

  }

}


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:27:07
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
7信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线

最后第四个问题。 我写的一个批处理文件。 参考板是zekit。

下面的脚本看懂,然后复制到文件文件,改名为cces.cmd。

::===============================================

@echo off

mode con cols=113 lines=50 &color 9f

cls

echo 迈松MSVL SPI FLASH烧写工具

echo.

echo 程序正在初始化. . .

echo.

echo ┌──────────────────────────────────────┐

set/p= ■<nul

for /L %%i in (1 1 38) do set /p a=■<nul&ping /n 1 127.0.0.1>nul

echo 100%%

echo └──────────────────────────────────────┘

echo 盗版不究  

echo.

echo 提示: 确保开发板供电这正常,JTAG已经插牢,CCES开发环境的调试模式关闭。

echo        该程序非通用程序,需要修改烧写文件的话,请用记事本打开该脚本,修改对应的变量。

::定义变量信息   dxe的名字 和ldr的名字 可执行命令的路径。。 这些地址需要根据CCES安装目录,DEX文件,引导程序,FLASH驱动文件的目录做修改。

set elfloaderExe="D:\Analog Devices\CrossCore Embedded Studio 1.1.0\elfloader.exe"

set cldpExe="D:\Analog Devices\CrossCore Embedded Studio 1.1.0\cldp.exe"

set flashDevice="D:\Analog Devices\CrossCore Embedded Studio 1.1.0\bf609_w25q32bv_dpia.dxe"

set initCode="D:\Analog Devices\CrossCore Embedded Studio 1.0.2\myDxe\BF609_init_v00.dxe"

set dxeCore0="E:\myWork\MSVL630C11-TEST\MSVL_Core0\Debug\MSVL_Core0.dxe"

set dxeCore1="E:\myWork\MSVL630C11-TEST\MSVL_Core1\Debug\MSVL_Core1.dxe"

set ldrFile="D:\Analog Devices\CrossCore Embedded Studio 1.0.2\myDxe\test2.ldr"


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:27:29
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
8信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线

:输入命令参数

Echo.    

Echo ------------------------------------------------------------------------

Echo                 ║ [1] 生成ldr文件                ║

Echo                 ║                               ║

Echo                 ║ [2] 烧写ldr文件                ║

Echo                 ║                               ║

Echo                 ║ [3] 生成并烧写ldr文件          ║

Echo                 ║                               ║

Echo                 ║ [Q] 退出             ║

Echo ------------------------------------------------------------------------

Echo.          

Set Choice=

Set /P Choice=   请选择要进行的操作 (1/2/3/Q) ,然后按回车:

if "%Choice%" == "1" Goto 生成ldr文件

if "%Choice%" == "2" Goto 烧写ldr文件

if "%Choice%" == "3" Goto 生成并烧写ldr文件

if "%Choice%" == "Q" Goto 退出终端

Echo 该序列%Choice%是未定义的命令。请重新输入

goto 输入命令参数

exit

:生成ldr文件

echo 开始生成ldr文件

%elfloaderExe% -proc ADSP-BF609 -si-revision 0.0 -b SPI -f binary -width 8 -bcode 0x5 -MaxBlockSize 0xFFF0 -MaxZeroFillBlockSize 0x7FFFFFF0 -init %initCode% %dxeCore0% %dxeCore1% -NoFinalTag=%dxeCore0% -verbose -o %ldrFile%

pause

goto 输入命令参数

:烧写ldr文件

echo 开始烧写ldr文件

%cldpExe% -proc ADSP-BF609 -emu 100b -driver %flashDevice% -cmd prog -erase affected -format bin -file %ldrFile%

pause

goto 输入命令参数

:生成并烧写ldr文件

echo 开始执行

%elfloaderExe% -proc ADSP-BF609 -si-revision 0.0 -b SPI -f binary -width 8 -bcode 0x5 -MaxBlockSize 0xFFF0 -MaxZeroFillBlockSize 0x7FFFFFF0 -init %initCode% %dxeCore0% %dxeCore1% -NoFinalTag=%dxeCore0% -verbose -o %ldrFile%

%cldpExe% -proc ADSP-BF609 -emu 100b -driver %flashDevice% -cmd prog -erase affected -format bin -file %ldrFile%

pause

goto 输入命令参数

pause

:退出终端

exit


我是OP...
等级:管理员 参考IP地址:*.*.*.*
2014/11/27 10:27:45
chiliwang(论坛新手)
chiliwang
头衔:社区公民
帮派:无帮无派
帖数:7
金钱:162
积分:10
注册时间:2014/4/11
9信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
这样是会有很大隐患的。
1,手动指定一个L2地址为结构的话,系统并不知情,系统以后分配内存的时候还是可能会用到这块内存,还是需要采用malloc分配。
2,虽然双方都知道共享内存的地址,但是双核程序是两个独立程序,你无法保证二者在访问这段内存的时候是互斥的,一旦双核在同一时刻访问将可能直接异常。


所以:
还是需要MCAPI的,至少需要一些简单的交互,如上2点,1需要通过通信告诉malloc分配的结构地址,2,需要在访问的时候询问对方状态。

i can so i live.
等级:论坛新手 参考IP地址:*.*.*.*
2015/5/23 11:33:22
11
1
1/2
Powered by OpenADSP Copyright © 2010 www.Openadsp.com. All rights reserved.154597 Call, 1 Queries, Processed in 0.046997 second(s),