Microchip
直播中

华农武

8年用户 225经验值
私信 关注
[问答]

一段时间后DMA和SPI停止

我有一个关于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)

黄飞高

2018-11-8 15:25:55
在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
举报

陈晨

2018-11-8 15:35:52
另外,您检查SPI错误标志吗?

以上来自于百度翻译


      以下为原文

    Additionally are you checking the SPI error flags?
举报

刘鹏

2018-11-8 15:50:16
感谢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.
 
 
 
 
举报

刘鹏

2018-11-8 16:05:11
只是一个小更新,我正好赶上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)
举报

更多回帖

发帖
×
20
完善资料,
赚取积分