RM48L952 可以用CAN中断的方式接收数据, 我想用DMA的方式接收CAN数据. 有没有好的方法和例程..
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi Ken,
我有查看HALCOGEN里面的关于MIBSPI的例程,当时这几个函数不是太明白,需要一一解释:
sam,
第一个函数是DMA channel的mapping操作,这里选择的是将DMA的第一个request 1 mapping到channel 0 上面。request 1 是有我们芯片定义的硬件触发MIBSPI的请求,这个可以在我们datasheet的4.16.2 的default DMA request map表格里查到。channel 数也是自己设置的,channel 0的优先级最高。
第二个函数是设置DMA的源地址,终端地址,以及DMA传输数据的长度
第三个函数是配置DMA的package, 里面包括DMA的传输方式,终端盒源端地址的offet 和每次地址跳转的大小,element的大小,frame的大小,读写的具体位数等等。这个DMA配置的重点
第四个函数是这是我们前面定义的channel 0 通道硬件触发。
第五个函数是设置具体的MIBSPI发送和接收的channel。
谢谢
Hi Ken,
下面是例程但是有问题.不能进入DMA中断。
void main(void)
{
/* Enable IRQ interrupt in ARM CPSR register */
_enable_interrupt_();
/* Reset the Flag */
DMA_Comp_Flag = 0xAAAA5555;
/* initialize can 1 */
canInit();
// Enable DE3 bit in CTL register to trigger DMA when IF3 receives data
// canREG1->CTL |= (1U << 20U);
/* At present HALCoGen does not support IF3 configuration,
* hence doing it here
*/
// Read ARB, DATA A & B - 8 bytes */
//canREG1->IF3OBS = 0x1A;
// Read DATA A & B - 8 bytes */
canREG1->IF3OBS = 0x18;
// Message box 2 configured for auto update
canREG1->IF3UEy[0]= 0x0000002A;
/* - DMA Configuration */
/* Enable DMA */
dmaEnable();
/* Enable Interrupt after reception of data */
dmaEnableInterrupt(DMA_CH0, FTC);
/* assigning dma request: channel-0 with request line - 16 ( DCAN1IF3) */
/* Refer Datasheet DMA request Line connection Table */
dmaReqAssign(DMA_CH0,16);
while(1)
{
/* - Populate dma control packets structure */
/* Source Address = IF3 Data register
* Destination = Receive Buffer in Sys RAM
* Length = 1 ( i.e., 64bits = 8 * 8 Bytes)
*/
dmaConfigCtrlRxPacket((uint32)(&(canREG1->IF3DATx[0])),
(uint32)(&RX_DATA1),
1);
/* - setting dma control packets for transmit */
dmaSetCtrlPacket(DMA_CH0, g_dmaCTRLPKT);
/* - setting the dma channel to trigger on h/w request */
dmaSetChEnable(DMA_CH0, DMA_HW);
canEnableloopback(canREG1,Internal_Lbk);
dmaEnable();
/* transmit on can1 */
canTransmit(canREG1, canMESSAGE_BOX1, TX_DATA1);
/* Wait for the DMA interrupt ISR to set the Flag */
// while(DMA_Comp_Flag != 0x5555AAAA);
/* Disable Loopback */
canDisableloopback(canREG1);
/* Check the RX_DATA1 for the received message */
}
/* USER CODE END */
}
/* USER CODE BEGIN (4) */
void dmaConfigCtrlRxPacket(uint32 sadd,uint32 dadd,uint32 dsize)
{
g_dmaCTRLPKT.SADD = sadd; /* source address */
g_dmaCTRLPKT.DADD = dadd; /* destination address */
g_dmaCTRLPKT.CHCTRL = 0; /* channel control */
g_dmaCTRLPKT.FRCNT = 1; /* frame count */
g_dmaCTRLPKT.ELCNT = dsize; /* element count */
g_dmaCTRLPKT.ELDOFFSET = 0; /* element destination offset */
g_dmaCTRLPKT.ELSOFFSET = 0; /* element source offset */
g_dmaCTRLPKT.FRDOFFSET = 0; /* frame destination offset */
g_dmaCTRLPKT.FRSOFFSET = 0; /* frame source offset */
g_dmaCTRLPKT.PORTASGN = 4; /* port b */
g_dmaCTRLPKT.RDSIZE = ACCESS_64_BIT; /* read size */
g_dmaCTRLPKT.WRSIZE = ACCESS_64_BIT; /* write size */
g_dmaCTRLPKT.TTYPE = FRAME_TRANSFER ; /* transfer type */
g_dmaCTRLPKT.ADDMODERD = ADDR_FIXED; /* address mode read */
g_dmaCTRLPKT.ADDMODEWR = ADDR_FIXED; /* address mode write */
g_dmaCTRLPKT.AUTOINIT = AUTOINIT_ON; /* autoinit */
}
void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
{
DMA_Comp_Flag = 0x5555AAAA;
}
请问有什么问题??
Hi Ken ,
的确是从英文论坛里面修改过来的..
现在CAN1发送数据, DMA能进入中断.
如果将Read and write 配置成64BIT:
g_dmaCTRLPKT.RDSIZE = ACCESS_64_BIT; /* read size */
g_dmaCTRLPKT.WRSIZE = ACCESS_64_BIT; /* write size
调试时会出现如下错误:
CortexR4: GEL Output: Memory Map Setup for Flash @ Address 0x0CortexR4: Trouble Reading Memory Block at 0x8001584 on Page 0 of Length 0x1: (Error -1170 @ 0x0) Unable to access the DAP. Reset the device, and retry the operation. If error persists, confirm configuration, power-cycle the board, and/or try more reliable JTAG settings (e.g. lower TCLK). (Emulation package 5.0.872.0)
而且RX_DATA1 什么数据都不能收到,
如果将Read and write 配置成32BIT:
g_dmaCTRLPKT.RDSIZE = ACCESS_32_BIT; /* read size */
g_dmaCTRLPKT.WRSIZE = ACCESS_32_BIT; /* write size
DAM进入中断,当时RX_DATA1只能收到前4byte 数据, 后4byte不能收到。
很疑惑啊,为什么??
Hi sam,
因为我手上只有一块板子,所以我只能用loopback模式测试CAN接收的DMA功能,我这边测试都是没问题的,接收的数据都是8个字节。
关于DMA的配置如下:
void dmaConfigCtrlRxPacket(uint32 sadd,uint32 dadd,uint32 dsize)
{
g_dmaCTRLPKT.SADD = sadd; /* source address */
g_dmaCTRLPKT.DADD = dadd; /* destination address */
g_dmaCTRLPKT.CHCTRL = 0; /* channel control */
g_dmaCTRLPKT.FRCNT = 1; /* frame count */
g_dmaCTRLPKT.ELCNT = dsize; /* element count */
g_dmaCTRLPKT.ELDOFFSET = 0; /* element destination offset */
g_dmaCTRLPKT.ELSOFFSET = 0; /* element source offset */
g_dmaCTRLPKT.FRDOFFSET = 0; /* frame destination offset */
g_dmaCTRLPKT.FRSOFFSET = 0; /* frame source offset */
g_dmaCTRLPKT.PORTASGN = 4; /* port b */
g_dmaCTRLPKT.RDSIZE = ACCESS_64_BIT; /* read size */
g_dmaCTRLPKT.WRSIZE = ACCESS_64_BIT; /* write size */
g_dmaCTRLPKT.TTYPE = FRAME_TRANSFER ; /* transfer type */
g_dmaCTRLPKT.ADDMODERD = ADDR_FIXED; /* address mode read */
g_dmaCTRLPKT.ADDMODEWR = ADDR_FIXED; /* address mode write */
g_dmaCTRLPKT.AUTOINIT = AUTOINIT_OFF; /* autoinit */
}
我觉得你需要把autoinit设为off,然后再测试一下接收情况。
谢谢
Hi Ken,
我将设置成 g_dmaCTRLPKT.AUTOINIT = AUTOINIT_OFF; 也试过..
因为购买RM48L952 开发板有两个CAN,(CAN1 和 CAN2), 是CAN2发送8个Byte , CAN1 DMA接收..
如果将
g_dmaCTRLPKT.RDSIZE = ACCESS_64_BIT; /* read size */
g_dmaCTRLPKT.WRSIZE = ACCESS_64_BIT; /* write size
设置成这样DEBUG 模式下有时就会出现这样错误提示:
CortexR4: GEL Output: Memory Map Setup for Flash @ Address 0x0CortexR4: Trouble Reading Memory Block at 0x8001584 on Page 0 of Length 0x1: (Error -1170 @ 0x0) Unable to access the DAP. Reset the device, and retry the operation. If error persists, confirm configuration, power-cycle the board, and/or try more reliable JTAG settings (e.g. lower TCLK). (Emulation package 5.0.872.0)
Hi Ken,
谢谢你的回复,看了例程后,有两个疑问具体如下:
1. DMA中断接收数据, 为什么在这里要用CAN中断, 难道为了中断接收每个Message ID, 采用CAN 中断? 能否在DMA的中断处理函数里去处理将IF3中更新的数据搬运到RAM里面?
2. 此函数功能 dmaConfigCtrlRxPacket((uint32)(&(canREG1->IF3DATx[0])), (uint32)(&RX_DATA1),1); 应该是RX_DATA1 这个buffer 这与IF3 建立地址关系, 怎么也能与RX_DATA2, RX_DATA3 建立地址访问关系?
估计我对CAN DMA理解有点问题。。请回复。谢谢。。
sam,
首先这个只是个例程,实现的功能是发送不同的ID的CAN报文信息,然后通过DMA去接收。这里有可能和你期望的功能有点出入,不过没关系。你可以按你自己的想法来。具体的回答你参考下面的信息:
1. DMA中断接收数据, 为什么在这里要用CAN中断, 难道为了中断接收每个Message ID, 采用CAN 中断? 能否在DMA的中断处理函数里去处理将IF3中更新的数据搬运到RAM里面?
我这里采用CAN中断主要是为了更新DMA的中断地址,这样方便讲不同的报文信息放到不同的RAM区间。如果你不要这样操作的话,大可把这个中断禁用掉。只用给一个源地址和一个终端地址。将IF3的数据搬到RAM里面,DMA自己会去操作,不用在DMA中断里面去做这个动作。你也可以把DMA中断禁用.DMA 的工作就是自己搬用数据,不需要MCU的干预。
2. 此函数功能 dmaConfigCtrlRxPacket((uint32)(&(canREG1->IF3DATx[0])), (uint32)(&RX_DATA1),1); 应该是RX_DATA1 这个buffer 这与IF3 建立地址关系, 怎么也能与RX_DATA2, RX_DATA3 建立地址访问关系?
确实每个DMA操作只能对应一个源地址和一个终端地址。我这里的操作时要实现不同的源地址对应不同的终端地址,所以才会在CAN中断程序里面更改终端地址,这样方便讲不同的CAN 报文分开存放。就像上面描述的一样,你的程序完全可以用一个源,一个终端。
不知道这样解释,你能不能接受。如果还有疑惑的,欢迎提出。
谢谢
Hi Ken,
谢谢你的回复及例程, 经过测试程序OK,今天不知道怎么回事,在办公室不能发帖(就是回帖时,帖子内容下写不了字)。
还有问题就是:
1.在测试过程中发现这个函数为软触发 dmaSetChEnable(DMA_CH0, DMA_SW) 如果要接收一次DMA数据,必须进行一次软触发,有了这次软触发后,DMA也能进入中断. 没有软触发的话, DMA是进入不了中断处理函数的,现在就有个实际问题:
a)如果一台主设备与多台从设备进行CAN通讯时, 主设备就发一条消息找从设备要数据, 这是从设备全部要回多条数据给主设备,如果只用DMA来接收数据,(不采用CAN中断模式), 用软触发方式来接收数据的话就比较麻烦(在不知道从设备有多少台的情况下, 需要连续软触发多少次?). 之前一次认为DMA有新数据后,会触发DMA中断,但是没有这种情况(不知道对这个理解是否有误,这是测试得来的结论)。
b).什么情况下需要用到dmaSetChEnable(DMA_CH0, DMA_HW) 硬件触发?
c) 关于a的问题有没有更好的处理办法?
请回复 谢谢!
sam,
如果你用软件触发DMA的话,确实需要每次触发,才能进DMA中断。这个就是软件触发的一个特点。它是的DMA运行的时间可控,但是带来的不便就是需要每次去触发它。
a)如果一台主设备与多台从设备进行CAN通讯时, 主设备就发一条消息找从设备要数据, 这是从设备全部要回多条数据给主设备,如果只用DMA来接收数据,(不采用CAN中断模式), 用软触发方式来接收数据的话就比较麻烦(在不知道从设备有多少台的情况下, 需要连续软触发多少次?). 之前一次认为DMA有新数据后,会触发DMA中断,但是没有这种情况(不知道对这个理解是否有误,这是测试得来的结论)。
如果不采用CAN中断模式更改终端地址的话,你的程序里面有没有设置相关的区分各个从设备发过来的数据呢。因为你是主设备类似发一个广播报文,然后每个从设备都回复,除非你事先都设好他们的ID,也就是说设定他们的报文优先级。不然你在主设备端很难区分收到了那个从设备的数据。或者还有一种办法就是在报文数据的第一个字节设定一个类似ID的数据,这样比较好区分。缺点就是牺牲了总线报文的有效数据长度。
b).什么情况下需要用到dmaSetChEnable(DMA_CH0, DMA_HW) 硬件触发?
用硬件触发,完全能解决你不想每次启动DMA的操作需求。硬件的DMA是在CAN总线的IF3收到数据后,会自动的触发DMA的转换,不需要CPU再去干预,使能DMA的操作。如果要使用dmaSetChEnable(DMA_CH0, DMA_HW)的话,你需要设置好DMA和CAN模块之间的相应设置。比如,DMAchannel, request line之类的。
c) 关于a的问题有没有更好的处理办法?
参考上面的回复。
所以说你现在需要做的是,试试DMA硬件触发的功能。
谢谢
Hi Ken,
谢谢你的回复及例程, 测试OK,DMA硬件触发可以运行..
还有问题:
1. CAN总线有数据进来, DMA自动会硬件触发, 将接收到数据转移的RAM空间..这里想问, DMA在收到数据后有没有一个回复机制(如DMA其他寄存器有标志位),从而能保证CAN总线数据更有效的接收? 如下第2个问题.
2.如将DMA 32个通道全部开启来接收CANBUS发过来的数据..假如32个从设备同时各发一条 8byte数据. 让主设备的32个DMA通道一一对应来接收(一个通到负责一条消息)..此时DMA肯定有优先级来依次接收每一条数据. 现在想问硬件是否有种机制来保证32条DMA 都有收到消息..不会出现漏消息或空消息的情况...如果出现漏消息, 硬件是否有种回复机制(如反映到寄存器上的标识位?)
3.以上两个问题其实可以合并成一个问题. 不知道我的意思有没有表达清楚. 请回复...
sam,
2.如将DMA 32个通道全部开启来接收CANBUS发过来的数据..假如32个从设备同时各发一条 8byte数据. 让主设备的32个DMA通道一一对应来接收(一个通到负责一条消息)..此时DMA肯定有优先级来依次接收每一条数据. 现在想问硬件是否有种机制来保证32条DMA 都有收到消息..不会出现漏消息或空消息的情况...如果出现漏消息, 硬件是否有种回复机制(如反映到寄存器上的标识位?)
首先CAN总线发送报文不是一起发送的,每次总线上面只有一个优先级最高的报文发送,这样的话,接收端也是一个个报文接收的。这样就比较难出现你描述的32个从设备一起发送报文的情况。另外在CAN里面有报文状态寄存器可以查报文是发送成功刚还是pending状态。同时在DMA模块中也有类似的状态寄存器可以查询,看DMA是否传输完成,还是说是在等待传输。
谢谢
Ken,
能否直接 告诉我DMA哪个寄存器可以查询,DMA是否传输完成,还是在等待..
今天主设备RM48L952 CAN与从设备进行通讯. 主设备会发一个8 Byte数据(如: TX_DATA1[8] = {0xF1, 0xF2, 0xF3, 0xF4 ,0xF5 ,0xF6 ,0xF7, 0xF8}), 从设备会回3byte 数据(假如从设备会回0x55, 0x00, 0x00).. 主设备通过DMA中断来接收从设备的数据(主设备接收buffer定义 RX_DATA1[8] = {0} ), 但是发现一个问题: 主设备接收到的数据为: RX_DATA1 = {0xF1, 0xF2, 0xF3, 0xF4 ,0xF5 ,0xF6 ,0xF7, 0xF8}, 发现发过去的数据与接收的数据一样,但是从设备回的数据呢?。。求解..
请回复,谢谢。。
sam,
关于“设置IF3更新的时候,设置更新的messagbox有问题,有可能设成了接收数据的messagebox了”的意思是说:
因为你这里采用的是IF3来触发DMA的操作,IF3是在CAN总线通信的过程中将IF1或IF2发送和接收的数据,同步更新到它的数据区域里面来。这里面可以通过设置IF3UEy寄存器来选择你需要同步更新的messagebox。你需要注意的是,你这个寄存器设置成了更新哪几个messagebox,这些messagebox对应的是你发送还是接受的操作。只有这样才能准确的实现硬件触发DMA的发送操作还是DMA的接收操作。
鉴于你收到了你发送出去的数据,我觉得你应该是这个问题上面出了差错。你可以检查一下。
谢谢
Ken Wang,
如你所说IF3UEy 对应接收的messagebox 设置有问题, 更改正确的messagebox后, 从设备可以接受到正确数据..
还有些问题:
1. 能否 通过DMA发送CAN 数据?
2.怎样使用DMA 32 通道去接收数据? CAN DMA接收数据基本上会对应一个IF3DATx 的源地址? 难道一个源地址对应32个通道, 使用32通道接收数据,需要不对切换通道?? 是否我的理解有问题?
3.DMA接收从设备数据能否直接通过DMA register 知道从设备ID, 难道非要通过CAN中断的方式接收ID ??
sam,
1. 能否 通过DMA发送CAN 数据?
可以,就像我前面说的,你可以通过IF3更新发送端的messagebox来触发DMA,或使用IF1来触发DMA。
2.怎样使用DMA 32 通道去接收数据? CAN DMA接收数据基本上会对应一个IF3DATx 的源地址? 难道一个源地址对应32个通道, 使用32通道接收数据,需要不对切换通道?? 是否我的理解有问题?
首先你用32个通道都去接收数据的话,每个通道都有自己的ID,有自己的优先级,每次总线上只有一个报文的传输。对应于IF3来说,你需要将它设置成更新所有的接收通道。当通道里有数据来了,它就会自动更新数据到他的buffer里面,同时也会触发DMA进行操作。关键的地方是,你需要确定DMA传输的时间和你的每个通道发送报文之间的间隔时间是否匹配,不然会出现DMA pending或是DCAN pending的状况。
3.DMA接收从设备数据能否直接通过DMA register 知道从设备ID, 难道非要通过CAN中断的方式接收ID ??
DMA没有那个功能知道CAN的ID,因为CAN控制器在接收数据的时候,已经进行了解包操作,把相应的ID和数据分离出来了,IF3更新的数据到buffer里面,然后出发DMA。对于DMA来说,它操作的只是数据,没有任何识别ID的功能。
谢谢