然后写之前的文章,这篇文章将实现RT电影上的1553B0控制器
1、RT配置
*(volatile INT32U *)(BM1553b0REG (0x3 << 2)) = 0x0001; //启动/复位寄存器,D0-复位,D1-BC/MT启动,D2-中断复位,D3-时标复位 *(volatile INT32U *)(BM1553b0REG (0x7 << 2)) = 0x8000; //配置寄存器3#,D15-增强模式使能 *(volatile INT32U *)(BM1553b0REG (0x7 << 2)) = 0x8081; //配置寄存器3#,D0-加强方法码处理,D3-数据接收器无效,D2-RT时标分配失败使能,D4-数据接收器无效非法化,D7-非法化无效, D15-增强模式使能 *(volatile INT32U *)(BM1553b0REG (0x0 << 2)) = 0x0001; //中断屏蔽寄存器,D1-消息结束 *(volatile INT32U *)(BM1553b0REG (0x2 << 2)) = 0x9802; /配置寄存器2#,D0-隔离广播数据,D1-增强RT存储器管理,D11-覆盖非法数据,D12-RT双重缓冲使能,D13-存储器忙位搜索表使能,D15-中断增强模式 *(volatile INT32U *)(BM1553b0REG (0x8 << 2)) = 0x2008; /配置寄存器4#,D3-锁定配置寄存器#5RT地址,D13-忽略繁忙的模式命令 *(volatile INT32U *)(BM1553b0REG (0x9 << 2)) = 0x0902; 配置寄存器5#,D0-RT奇偶校验地址,D1-RT地址0,D8-间隔检测使能,D11-扩大相交使能 ///这里配置地址有一些问题,只能配置到rt1,RT不知道26是不是因为硬件电平问题。 *(volatile INT32U *)(BM1553b0MEM (0x100 << 2)) = 0x0000; ///堆栈初始化
首先还是配置寄存器,这里备注比较详细,可以对照61580的芯片手册查阅具体作用
博主在这里遇到的一个问题是,RT的地址只能设置为1,设置到别的地址就无法通信,这个问题后续会解决。暂时拿RT测试。
int i; for(i=0;i<4096;i ) { *(volatile INT32U *)(BM1553b0MEM (i << 2)) = 0x0; ///初始化存储器 }
清空存储区域。
int i=0,j=0; for(i=1;i<32;i ) { *(volatile INT32U *)(BM1553b0MEM ((0x140 i) << 2)) = 0x400 (i*0x20); /// *(volatile INT32U *)(BM1553b0MEM ((0x160 i) << 2)) = 0x800 (i*0x20); ////发送通道地址初始化 *(volatile INT32U *)(BM1553b0MEM ((0x1A0 i) << 2)) = 0x4200; ///子地址控制字初始化 ,打开发送和接收EOM中断 //0x4200->0100 0010 0000 0000 } *(volatile INT32U *)(BM1553b0MEM (0x120 << 2)) = 0x0000; /// 只有子地址为0x方式词的说法只存在于万物之中
然后配置存储区域,在这里补充一个RT存储区域定义图
从0可以从图中看出x140开始是A查询表,这个RT查询表是接收/发送/广播数据块的地址。通过查询表中存储的地址,可以找到相应的数据块。PS:这应该是给的BC往RT读写数据,BC要知道它在哪里发布或取走数据。
for(i=0;i<8;i ) { *(volatile INT32U *)(BM1553b0MEM ((0x240 i) << 2)) = 0x0000; ///忙位设置,初始化为0空闲 }
然后设置了忙位查询表,不太懂。如果暂时不用,就不注意了。
*(volatile INT32U *)(BM1553b0REG (0x1 << 2)) = 0x8f80; //配置寄存器2#,打开RT
最后是打开RT。
2、RT中断服务程序
u16 tempVar = 0; u16 temp; u16 i; tempVar = *(volatile INT32U *)((BM1553b0REG (channel*0x00100000)) (BUINTSTATUS << 2)); ///阅读中断状态 中断消息结束 tempVar &= BUEOMINT; if(tempVar==BUEOMINT) //判断消息结束 { ///阅读当前消息通道来自A或B tempVar = *(volatile INT32U *)((BM1553b0REG (channel*0x00100000)) (BUCFG1 << 2)); bumsgifm->channelAB=(tempVar>>13) & 0x1; ///读块状态字 我不太明白这是什么 手册上写着BC/RT命令栈点寄存器 bumsgifm->blockStatusWord = *(volatile INT32U *)((BM1553b0REG (channel*0x00100000)) (BUCMDSTACKPOINT << 2)); //读时标 bumsgifm->timeTagWord = *(volatile INT32U *)((BM1553b0REG (channel*0x00100000)) (BUTIMETAG << 2)); //读RT/MT数据堆栈地址寄存器 数据块指针 这是通过翻61580数据手册找到的 BM3610只说了MT 搞不懂 bumsgifm->dataBlockPointer = *(volatile INT32U *)((BM1553b0REG (channel*0x00100000)) (BURTDATASTACKADDR << 2)); //RT最后一个指令寄存器 0dH 接收的命令字 bumsgifm->commandWord = *(volatile INT32U *)((BM1553b0REG (channel*0x00100000)) (BURTLASTCMD << 2)); //命令字 15-11 RT地址 10:T/R 9-5:字地址/方式 4-0:数据字计数/方法码 bumsgifm->remoteTerminalAddr = (bumsgifm->commandWord >> 11) & 0x1f;//RT终端地址 bumsgifm->tr = (bumsgifm->commandWord >> 10) & 0x01;//T/R bumsgifm->subAddModeCode = (bumsgifm->commandWord >> 5) & 0x1f; //字地址/方式 bumsgifm->dataCntModeCode = (bumsgifm->commandWord ) & 0x1f; ///数据字计数/方法码 printf("BUMSG.commandWord :%#x\n",bumsgifm->commandWord); if(bumsgifm->tr == BURX) ///判断接下来接收指令 { memset( bumsgifm->data,BUZERO,BUMSGDATANUM); if(!bumsgifm->dataCntModeCode) { temp=BUMSGDATANUM; } else { temp=bumsgifm->dataCntModeCode; } for(i=0;i<temp;i ) { bumsgifm->data[i] = *(volatile INT32U *)((BM1553b0MEM (channel*0x00100000)) ((0x400 i) << 2)); } rev_1553B_CH0=1; //启动接收标志,解析函数在主循环执行 } }
以上是RT中断服务程序,解析了数据帧的命令字和控制字(至于为什么有这两段字可以解析,可以看前一篇BC端设置的文章,还有更前面的1553B协议解析篇),还有就是读取数据。
这部分程序可以实现BC=>RT的下发,博主目前是跑通了。
3、RT发送数据到BC
这部分是难点,博主卡在这有半个月最少。
首先需要着重强调一点,就是RT所有的动作都需要由BC来主控。
可以理解成:BC对RT有绝对的控制权,除非BC要求RT说话,RT才能说话。
这个过程很多博文没解释清楚一个问题:BC是怎么知道RT有话要说,才去让RT开口说话呢?
解释这个问题就需要提到一个东西:矢量字 (奇奇怪怪的名字,但是就是它来实现的)
RT 如果主动给BC发送数据?矢量字使用问题?
1553中所有的消息控制都是通过BC端控制的。BC端可以发出BCRT、RTBC、ModeCode、RTRT类型消息。实际应用中经常会出现RT需要主动给BC端上报信息,这种情况下可以通过发送矢量字来实现(Mode Code 16)。
1) BC端周期性发送 Mode Code 16 消息(发送矢量字),RT端周期的接收矢量字指令。RT端默认发送的矢量字设为0,BC端检测到RT发送的矢量字是0的时候,不做任何操作。
2) 如果RT端需要主动发送数据给BC,RT端先准备好数据,然后将矢量字对应位置位(对应位写1)。
3) BC端检测到RT端发送过来的矢量字有位为1,BC根据事先约定的对应关系,发送对应的指令(比如RTBC指令)。
4) RT接到RTBC指令后,发送数据给BC,数据发送消息结束后,RT端将矢量字对应位清0。
5) 如果RT有新的数据要发送给BC,重复2)到4)。
矢量字对应位和RT 子地址常用的对应关系如下表所示。
表 矢量字对应位和RT子地址常用对应关系表
SA1对应矢量字第0位
如果BC端检测到矢量字第0位置1,发送对应SA1的RTBC指令
SA2对应矢量字第1位
如果BC端检测到矢量字第1位置1,发送对应SA2的RTBC指令
SA3对应矢量字第2位
如果BC端检测到矢量字第2位置1,发送对应SA3的RTBC指令
SA4对应矢量字第3位
-----------------
SA5对应矢量字第4位
-----------------
SA6对应矢量字第5位
-----------------
SA7对应矢量字第6位
-----------------
SA8对应矢量字第7位
-----------------
SA9对应矢量字第8位
-----------------
SA10对应矢量字第9位
-----------------
SA11对应矢量字第10位
-----------------
SA12对应矢量字第11位
-----------------
SA13对应矢量字第12位
-----------------
SA14对应矢量字第13位
-----------------
SA15对应矢量字第14位
如果BC端检测到矢量字第14位置1,发送对应SA15的RTBC指令
SA16对应矢量字第15位
如果BC端检测到矢量字第15位置1,发送对应SA16的RTBC指令
注:上表只是一般常用的对应的关系,用户应根据实际需要使用矢量字功能。矢量字和RT SA对应关系是BC端和RT端通信之前双方约定好的,不限于RTBC指令。
引用一段某公司的矢量字应用答疑。
个人理解这个矢量字:BC会不断以某个间隔去问RT你有没有需要说的,他们之前提前规定了N种说话类型,RT会在需要说话的时候提前把要说话的类型提前反馈给BC(状态字),就是上引用里提到的SA0-SA30。
矢量字就是包含在状态字里,这个概念也很重要。实际上1553通信由这几种字来实现:控制、命令、数据、状态。(这里怎么玩的,可以去翻看前面的协议介绍篇)
这个过程里,第一个命令字是BC给的,然后RT回一个状态字,这个过程是以某个间隔不断进行的。 状态字给到BC后,RT就会开始发送数据字。
最后一个问题,RT端怎么把需要发送的数据给到BC?这个过程实际上是RT端将数据存到RT端的存储器区域,然后协议芯片会在前面两步骤完成之后,将这部分数据拼凑成数据字发送出去。
所以,对于编程来说,只需要找到放数据的存储器区域即可,提前写进去然后修改矢量字即可(SA1)。
这里不得不提到博主任务书里的RT26-SA30-32→BC这个RT发送数据到BC的过程描述,之前一直没搞明白为什么有个SA30,还有个32。后面博主知道32是代表的子地址32,但是SA30是真的没明白,又没办法直接和甲方交流。这里搞明白了,是RT地址26在置位SA30后,往32子地址里写入数据,就可以发送到BC。PS:这里的32和SA30都说相对于BC来说的。
暂时写到这里,博主的RT上传部分程序编写又卡住了,矢量字有一个对应关系,这个SA30怎么设置呢?