完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
我有一个关于SPI和DMA的问题,也许有人可以帮助我BIti有2个PIC32 MX795F512L用SPI互相连接。在SPI i上发送64个字节的包,并且我用DMA来发送和接收。问题是在15。20分钟之后,主机停止在SPI上发送数据(它不CR)。ASH,因为其他进程仍在运行),我将在这里发布我使用DMA和SPI(主)的代码:我使用FIFO将帧放入,将帧加载到FIFO:在主循环中(我选择在主干中做这个,而不是从ISR中执行,以避免它同时运行两次):我使用UART发送帧指针,我看到的是在15到20分钟后,SPILoADFrice仍然在计数,但是SPIProcFrame不是(当我注释SeaStFF行和UART5WrdLead时,我看到它停止),我用逻辑分析仪检查,我再也看不到SPI数据。我做了什么错事?是DmaChnEnable(DMAYChhanel1);DmaChnStartTxfer(DMAZhanNeL2,DMAWAWITITY NOT,0);不是重新启动DMA控制器的方法吗?
以上来自于百度翻译 以下为原文 I have an issue with SPI and DMA, maybe someone can help me a bit I have 2 PIC 32MX795F512L connected to each other with SPI. Over the SPI I send packages of 64 bytes each and I use DMA to send and receive. The problem is that after 15..20 minutes the Master stops sending data over SPI (it does not crash, because other processes are still running) I'll post here the code I use Init of DMA and SPI (Master): SpiChnOpen(SPI_CHANNEL1, SPI_CON_MODE8|SPI_CON_ON|SPI_OPEN_MSTEN, 64); DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_ALL_EVNTS); DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_ALL_EVNTS); DmaChnOpen(DMA_CHANNEL1, DMA_CHN_PRI2, DMA_OPEN_DEFAULT); DmaChnOpen(DMA_CHANNEL2, DMA_CHN_PRI3, DMA_OPEN_DEFAULT); DmaChnSetEventControl(DMA_CHANNEL1, DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI1_RX_IRQ)); DmaChnSetEventControl(DMA_CHANNEL2, DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI1_TX_IRQ)); DmaChnSetTxfer(DMA_CHANNEL1, (void*)&SPI1BUF, (UINT8*)&SPiRxData, 1, SpiPacketSize, 1); DmaChnSetTxfer(DMA_CHANNEL2, (UINT8*)&SPiTxData, (void*)&SPI1BUF, SpiPacketSize, 1, 1); DmaChnSetEvEnableFlags(DMA_CHANNEL2, DMA_EV_ERR); // enable the transfer done interrupt, when all buffer transferred INTSetVectorPriority(INT_VECTOR_DMA(DMA_CHANNEL2), INT_PRIORITY_LEVEL_5); // set INT controller priority INTSetVectorSubPriority(INT_VECTOR_DMA(DMA_CHANNEL2), INT_SUB_PRIORITY_LEVEL_3); // set INT controller sub-priority INTEnable(INT_SOURCE_DMA(DMA_CHANNEL2), INT_ENABLED); // enable the chn interrupt in the INT controller DmaChnSetEvEnableFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE); // enable the transfer done interrupt, when all buffer transferred INTSetVectorPriority(INT_VECTOR_DMA(DMA_CHANNEL1), INT_PRIORITY_LEVEL_5); // set INT controller priority INTSetVectorSubPriority(INT_VECTOR_DMA(DMA_CHANNEL1), INT_SUB_PRIORITY_LEVEL_3); // set INT controller sub-priority INTEnable(INT_SOURCE_DMA(DMA_CHANNEL1), INT_ENABLED); // enable the chn interrupt in the INT controller I use a FIFO for putting the frames into, loading a frame to FIFO: void SPILoadFrame(UINT8 *FrPointer) { // TEST Clear the overflow (in case we have one) SPI1STATCLR=0x40; // clear the Overflow SPIAppSendPointer++; if (SPIAppSendPointer >= FrambufferSize) { SPIAppSendPointer = 0; } memcpy((UINT8*)&FramebufferTx[SPIAppSendPointer],FrPointer,SpiPacketSize); // For test send pointer over uart sprintf(txt,"%u ",SPIAppSendPointer); Uart5WriteString(txt); } In the main loop (I choosed to do this in main and not from the ISR to avoid it wil be run twice at the same time): void SPIProcFrame(void) { UINT8 pntr=SPIDMASendPointer; SPIProcFrameRunning = 1; SPI1STATCLR=0x40; // Test: Clear overflow if we have one if (!DCH1CONbits.CHBUSY) { // See if we have a frame ready to load if (SPIDMASendPointer != SPIAppSendPointer) { // we need to load the next frame pntr++; if (pntr >= FrambufferSize) { pntr = 0; } // next is not really necessary because we checked DMA1 channel = receive if (!SPI1STATbits.SPITBE) { while (!SPI1STATbits.SPITBE); // wait until we send everything out //delay_us(1); // wait a bit longer to process } memcpy((UINT8*)&SPiTxData,(UINT8*)&FramebufferTx[pntr],SpiPacketSize); SPIDMASendPointer=pntr; //sprintf(txt,"%u ",SPIDMASendPointer); //Uart5WriteString(txt); // now restart the DMA sender DmaChnEnable(DMA_CHANNEL1); DmaChnStartTxfer(DMA_CHANNEL2, DMA_WAIT_NOT, 0); } } } I used the uart to send the frame pointer, what I saw is after 15 to 20 minutes SPILoadFrame is still counting but SPIProcFrame is not (when I comment out the sprintf line and Uart5writeline I see it stops) I checked with logic analyser and I do not see any SPI data anymore. What do I do wrong? is DmaChnEnable(DMA_CHANNEL1); DmaChnStartTxfer(DMA_CHANNEL2, DMA_WAIT_NOT, 0); not the way to restart the DMA controller? |
|
相关推荐
7个回答
|
|
在PIC32寄存器中改变位时,使用掩码和SET、CLR或IV偏移寄存器地址。对于PIC32,位值不是原子的,但使用偏移寄存器地址是。你不显示你的ISR,但是如果使用多个中断的原子指令不被使用,你可以得到RMW错误,这些错误可以显示为不经意地清除中断标志多于中断。执行(缺少另一个中断)。/ Ruben
以上来自于百度翻译 以下为原文 Use a mask and the SET, CLR or INV offset register address when changing bits in a PIC32 register. Register.bit=value is not atomic for a PIC32 but using the offset register address is. You don't show your ISRs but if atomic instructions are not used where multiple interrupts are used, you can get RMW errors which can show itself as inadvertently clearing interrupt flags for more than the interrupt that is executed (missing another interrupt). /Ruben |
|
|
|
|
|
|
|
感谢Ruben的回答,SPIPROSTRAMS是从主程序(循环中)开始的,所以原子在这里不应该是个问题,因为程序在一个中断被触发后继续等待,而当它完全结束时,我是对的?第一次审判我是从DMA的中断开始的,但是我得到了同样的结果。现在,它从主程序运行,以消除这个问题。在第二部分,你键入,我得到你,坏的做法,我会改变代码,但也在这里,在此刻(稍后我会)我不使用中断,错过它不应该拖延完整的DMA,对不对?“NKurZman是的,我看到了下面的代码。ISR在MimeTrr.SP中什么也不做。我也尝试将MeMeX移出并直接将FIFO帧馈送到DMA,但是结果相同。
以上来自于百度翻译 以下为原文 Thanks for the answer @Ruben, the SPIProcFrame gets started from the main routine (in a loop) so the Atomic shouldn't be a problem here as the procedure goes to wait when an interrupt is fired and continues while it's completely finished, I am right? First trial I started this from the interrupt fired by the DMA, but I got the same result.. now it runs from the main routine to eliminate the issue. At the 2nd part you type, I get you, bad practice, I'll change that code, but also here, at the moment (later on I will) I do not use the interrupt, missing it should not stall the complete DMA, right? @NKurzman Yes I do, see the code beneath. The ISR is doing nothing at the moment ISR's void __ISR(_DMA1_VECTOR, IPL5AUTO) DmaHandler1(void) { int evFlags; INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL1)); evFlags=DmaChnGetEvFlags(DMA_CHANNEL1); if (evFlags&DMA_EV_BLOCK_DONE) { //SPI_TransferDone(); DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE); } if(evFlags&DMA_EV_ERR) { // To do, report this! sprintf(txt,"DMA Error rn "); Uart1WriteString(txt); DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_ERR); } DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_ALL_EVNTS); } // handler for the DMA channel 2 interrupt void __ISR(_DMA2_VECTOR, IPL5AUTO) DmaHandler2(void) { int evFlags; INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL2)); evFlags=DmaChnGetEvFlags(DMA_CHANNEL2); // get the event flags if (evFlags&DMA_EV_BLOCK_DONE) { //DmaChnAbortTxfer(DMA_CHANNEL1); // Stop RX //SPI_TransferDone(); DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_BLOCK_DONE); } if(evFlags&DMA_EV_ERR) { // To do, report this! DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_ERR); } DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_ALL_EVNTS); } P.S. I also tried to leave the memcopy out and feed the FIFO frame directly to the DMA, but that ended up with the same result. |
|
|
|
只是一个小更新,我正好赶上DH1CON(DMA1=接收)在PIC停止发送(稍后),值是十六进制8082,这意味着该频道仍然繁忙!如果“!{“总是”为“false”(BTW,我将它改为“如果”!(DCH1CON&0x8000){“但这并没有改变结果”DMA控制器跳过了字节吗?(DMA 2用于发送,它设置为发送64字节,DMA 1用于接收也被设置为接收64字节)
以上来自于百度翻译 以下为原文 Just a little update, I happen to catch the DH1CON (DMA1 = receiving) at the moment the PIC stops sending (and later), the value is Hex 8082 ,that means the channel is still busy! and "if (!DCH1CONbits.CHBUSY) {" is always false (btw, I changed it to "if (!(DCH1CON&0x8000)) {" but that didn't change the outcome) Did the DMA controller skipped a byte? (DMA 2 is for sending, it set to send 64 bytes, DMA 1 is for receiving also set to receive 64 bytes) |
|
|
|
又有一个新发现的帖子。(DCH1CON&0x8000){“to”如果(!)“请检查忙线,它不再停止,但奴隶在一段时间后会失去同步。它看起来越来越像一个跳过字节的DMA问题,我在论坛中搜索了这个问题,只找到了一个32 MZ的帖子,解决方案是在RX中触发。T的SPI而不是TX(DMACHANSENELNE2),DMAYEVIGION IGQGEN,DMAYEVGESTARTIZILIQ(OSP-1xEXIGTXYILQ);-GT;DMACHNESETIVENPROTER(DMAZCHANENEL2,DMAYVEVESTATIORIQQEN,DMAYVEVESTARSTIORIQ(πSPI1RXYRQ));但是SOSN不工作于32 MX(SPI不做任何事情),我想知道DMA CO是如何工作的NoTrror跳过字节,我触发DMA错误,没有DMA错误。
以上来自于百度翻译 以下为原文 Again a new post with findings. For test I change the line "if (!(DCH1CON&0x8000)) {" to "if (!(DCH2CON&0x8000)) {" so check the busy line. It does not stop anymore, but the slave gets out of sync after a while. It looks more and more to a skipping byte issue of the DMA, I've searched the forums for this issue, Found only a post for a 32MZ and there the solution was to trigger on the RX int of the SPI instead of the TX ( DmaChnSetEventControl(DMA_CHANNEL2, DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI1_TX_IRQ)); -> DmaChnSetEventControl(DMA_CHANNEL2, DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI1_RX_IRQ)); ) But that soesn't work for a 32MX (the SPI does nothing) I'm wondering how the DMA controller gets skipping bytes, I trigger on DMA errors, there are no DMA errors. |
|
|
|
我发现了这个问题,它是MCU内部的一个设计缺陷(我想所有的32位MCU都在处理这个问题)我所改变的不仅是DMA2的触发DMAYVEVSTARTIORIQ(OSPI1LRXYRQ)(DMA2发送数据),而且是优先级,所以新的INIT现在是这个代码,这意味着INT。缓冲区TX空的错误有时会很快导致缓冲区溢出(这导致字节跳过)。我找到了一个帖子,其中一个32 MZ的人遇到了同样的问题并通过这样的方式解决了(通过将中断触发器更改为RX),但在我看来,这是一个更大的解决方案。在我的逻辑分析器中,我看到它发送的每个字节之间有更大的暂停(相当大,更多的是2个时钟脉冲),这意味着SPI模块需要安静一些时间,从发送字节到SPXBUF并接收它(Lite到很多?)。我想知道你对这个问题的看法。
以上来自于百度翻译 以下为原文 I found the problem, it is a design flaw inside the MCU (and I think all off the 32 bit MCU are dealing with this) What I changed is not only the trigger DMA_EV_START_IRQ(_SPI1_RX_IRQ) for DMA2 (the one for sending out the data) but also the priority So the new init is now this code SpiChnOpen(SPI_CHANNEL1, SPI_CON_MODE8|SPI_CON_ON|SPI_OPEN_MSTEN, 64); DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_ALL_EVNTS); DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_ALL_EVNTS); DmaChnOpen(DMA_CHANNEL1, DMA_CHN_PRI3, DMA_OPEN_DEFAULT); DmaChnOpen(DMA_CHANNEL2, DMA_CHN_PRI2, DMA_OPEN_DEFAULT); DmaChnSetEventControl(DMA_CHANNEL1, DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI1_RX_IRQ)); DmaChnSetEventControl(DMA_CHANNEL2, DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI1_RX_IRQ)); DmaChnSetTxfer(DMA_CHANNEL1, (void*)&SPI1BUF, (UINT8*)&SPiRxData, 1, SpiPacketSize, 1); DmaChnSetTxfer(DMA_CHANNEL2, (UINT8*)&SPiTxData, (void*)&SPI1BUF, SpiPacketSize, 1, 1); DmaChnSetEvEnableFlags(DMA_CHANNEL2, DMA_EV_ERR); // enable the transfer done interrupt, when all buffer transferred INTSetVectorPriority(INT_VECTOR_DMA(DMA_CHANNEL2), INT_PRIORITY_LEVEL_5); // set INT controller priority INTSetVectorSubPriority(INT_VECTOR_DMA(DMA_CHANNEL2), INT_SUB_PRIORITY_LEVEL_3); // set INT controller sub-priority INTEnable(INT_SOURCE_DMA(DMA_CHANNEL2), INT_ENABLED); // enable the chn interrupt in the INT controller DmaChnSetEvEnableFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE); // enable the transfer done interrupt, when all buffer transferred INTSetVectorPriority(INT_VECTOR_DMA(DMA_CHANNEL1), INT_PRIORITY_LEVEL_5); // set INT controller priority INTSetVectorSubPriority(INT_VECTOR_DMA(DMA_CHANNEL1), INT_SUB_PRIORITY_LEVEL_3); // set INT controller sub-priority INTEnable(INT_SOURCE_DMA(DMA_CHANNEL1), INT_ENABLED); // enable the chn interrupt in the INT controller This means the Interrupt for the buffer tx empty is sometimes slightly to soon resulting in a buffer overrun (that causes the byte skipping) I found a post where someone with a 32MZ ran into the same issue and solved it this way (by changing the interrupt trigger to RX, but in my opinion it's more a workaround then a real solution. On my logic analyzer I see bigger pauses (rather big, more then 2 clock pulses) between every byte it sends, this means the SPI module need quiet some time to go from sending a byte to SPxBUF and receiving it back (lite to much?) @microchip I'm wondering what your comment is about this issue Attached Image(s) |
|
|
|
两位PUZE是已知的,并且也发生在例如DSPIC33 E中。
以上来自于百度翻译 以下为原文 The two bit pauze is known, and also happens with e.g. dspic33e. |
|
|
|
只有小组成员才能发言,加入小组>>
5255 浏览 9 评论
2038 浏览 8 评论
1958 浏览 10 评论
请问是否能把一个ADC值转换成两个字节用来设置PWM占空比?
3219 浏览 3 评论
请问电源和晶体值之间有什么关系吗?PIC在正常条件下运行4MHz需要多少电压?
2268 浏览 5 评论
796浏览 1评论
689浏览 1评论
有偿咨询,关于MPLAB X IPE烧录PIC32MX所遇到的问题
618浏览 1评论
PIC Kit3出现目标设备ID(00000000)与预期的设备ID(02c20000)不匹配。是什么原因
687浏览 0评论
587浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 23:54 , Processed in 1.271276 second(s), Total 58, Slave 52 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号