您的位置: OpenADSP社区论坛 -> Blackfin专区 -> 新手上路 -> bf609双核通信内存共享的问题
本帖共有221个阅读者
发表帖子 发表投票 回复主题
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地址:*.*.*.*
2018/4/9 17:18:41
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
1信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
答:简单回答下问题。
1. 这个在bf609_ezkit的软件包中就有一些MCAPI例程。mpeg4_enc软件包中也有相关的应用(双核编码,每一个核编码一半的图像数据),这个例程使用MCAPI来进行核间通信,看起来更标准化,单初学者会感到很复杂。
2. 你应该看下bf609的芯片手册,有中文版的。主要关注内存地址的映射。至于速度就自己测了。
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可以随意访问到)。
如果我们将{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占用后一半。
上述就是内存布局的一个简单的描述。
知道了内存的布局,结合自己以前学习的进程间通信的方式。就不难想出使用共享内存的方法。
把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)},
coreA的ldf:
不改。

我是OP...
等级:管理员 参考IP地址:*.*.*.*
2018/4/9 17:20:16
尊贵身份标志
OpenADSP(管理员)
OpenADSP
头衔:社区公民
帮派:无帮无派
帖数:5187
金钱:34761
积分:6369
注册时间:2011/6/7
2信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
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;
结构体的定义和声明以及地址赋值在两个core都要写。 赋值在一个core就行了。因为内存地址是一样的吗。
这样的话,当任意一个核去改变goMyIcc中的值时,另外一个核中的值也会跟着变化。
剩下的就靠用户自己发挥了。
当然还有一些细节,比如要避免两个核频繁的访问共享内存。
while(1)
{
if(goMyIcc->flagA)
{
    ;
}
}  //这样的代码是不能出现的。
可以这么写
while(1)
{
if(goMyIcc->flagA)
{
    ;
}
else
{
   延时1ms,或者去干些别的事儿。
  }
}
最后第四个问题。 我写的一个批处理文件。 参考板是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"
:输入命令参数
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地址:*.*.*.*
2018/4/9 17:20:33
ooaa123(论坛新手)
ooaa123
头衔:社区公民
帮派:无帮无派
帖数:18
金钱:222
积分:20
注册时间:2018/3/13
3信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
正在前期调研中,非常好的资料,学习了!

这家伙很懒,什么也没有留下!
等级:论坛新手 参考IP地址:*.*.*.*
2018/4/11 15:00:49
Powered by OpenADSP Copyright © 2010 www.Openadsp.com. All rights reserved.154292 Call, 1 Queries, Processed in 0.031250 second(s),