在 PIC32 上通过 DMA 接收 SPI 数据

发布于 2024-10-19 23:43:25 字数 3582 浏览 6 评论 0原文

我知道这个主题(DMA 和 SPI)已经在微芯片论坛的许多线程中讨论过,实际上我已经阅读了关键字“dma”搜索结果中的所有 15 页,并阅读了有关 dma 的所有主题& spi。

我仍然被我的问题困扰,我希望有人可以帮助我:)

这就是问题所在。

我的芯片是PIC32MX775F512H。 我正在尝试通过 DMA 使用 SPI 接收(仅接收)数据。 由于您不能“仅”在 SPI 中接收,并且仅当您写入 SPIBUF(对我来说 SPI1ABUF)时,SPI 内核才开始切换 SPI 时钟,因此我尝试使用 2 个 DMA 通道接收数据。 DMA_CHANNEL1为发送部分。 DMA_CHANNEL2为接收部分。

我复制粘贴了 中的代码http://www.microchip.com/forums/tm.aspx?tree=true&high=&m=562453&mpage=1#

并试图让它工作但没有任何运气。它只接收几个字节(5 或 6)。

我已将两个 DMA 通道的事件启用标志设置为 DMA_EV_BLOCK_DONE,没有发生中断。

你有什么想法吗?

这是我正在使用的代码:

int Spi_recv_via_DMA(SPI_simple_master_class* SPI_Port, int8u *in_bytes, int16u num_bytes2) 
{ 
DmaChannel   dmaTxChn=DMA_CHANNEL1; 
DmaChannel   dmaRxChn=DMA_CHANNEL2; 
SpiChannel   spiTxChn=SPI_Port->channel; 
    int8u           dummy_input; 

    DmaChnOpen(dmaTxChn, DMA_CHN_PRI3, DMA_OPEN_DEFAULT); 
    DmaChnOpen(dmaRxChn, DMA_CHN_PRI3, DMA_OPEN_DEFAULT); 

    DmaChnSetEventControl(dmaTxChn, DMA_EV_START_IRQ_EN | DMA_EV_START_IRQ(_SPI1A_RX_IRQ)); 
    DmaChnSetEventControl(dmaRxChn, DMA_EV_START_IRQ_EN | DMA_EV_START_IRQ(_SPI1A_RX_IRQ)); 

    DmaChnClrEvFlags(dmaTxChn, DMA_EV_ALL_EVNTS); 
    DmaChnClrEvFlags(dmaRxChn, DMA_EV_ALL_EVNTS); 
    DmaChnSetEvEnableFlags(dmaRxChn, DMA_EV_BLOCK_DONE); 
    DmaChnSetEvEnableFlags(dmaTxChn, DMA_EV_BLOCK_DONE); 

    //SpiChnClrTxIntFlag(spiTxChn); 
    //SpiChnClrRxIntFlag(spiTxChn); 

    DmaChnSetTxfer(dmaTxChn, tx_dummy_buffer, (void *)&SPI1ABUF, num_bytes2, 1, 1); 
    DmaChnSetTxfer(dmaRxChn, (void *)&SPI1ABUF, in_bytes, 1, num_bytes2, 1); 

    while ( (SPI1ASTAT & SPIRBE) == 0) 
        dummy_input = SPI1ABUF; 
    SPI1ASTAT &= ~SPIROV; 

    DmaRxIntFlag = 0; 
    DmaChnEnable(dmaRxChn); 
    DmaChnStartTxfer(dmaTxChn, DMA_WAIT_NOT, 0); 


    while(!DmaRxIntFlag); 
    return 1;    
} 

与这两个中断处理程序:

// handler for the DMA channel 1 interrupt 
void __ISR(_DMA1_VECTOR, ipl5) DmaHandler1(void) 
{ 
int evFlags;     // event flags when getting the interrupt 
    //LED_On(LED_CFG); 
INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL1)); // acknowledge the INT controller, we're servicing int 

evFlags=DmaChnGetEvFlags(DMA_CHANNEL1); // get the event flags 

    if(evFlags&DMA_EV_BLOCK_DONE) 
    { // just a sanity check. we enabled just the DMA_EV_BLOCK_DONE transfer done interrupt 
        DmaTxIntFlag = 1; 
    DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE); 
    } 
   // LED_Off(LED_CFG); 
} 

void __ISR(_DMA2_VECTOR, ipl5) DmaHandler2(void) 
{ 
int evFlags;     // event flags when getting the interrupt 

INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL2)); // acknowledge the INT controller, we're servicing int 

evFlags=DmaChnGetEvFlags(DMA_CHANNEL2); // get the event flags 

    if(evFlags&DMA_EV_BLOCK_DONE) 
    { // just a sanity check. we enabled just the DMA_EV_BLOCK_DONE transfer done interrupt 
        DmaRxIntFlag = 1; 
    DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_BLOCK_DONE); 
    } 
} 

所以我最终在线上永远等待: while(!DmaRxIntFlag);

我已在中断向量中放置断点,但它们从未被调用。

这是永久等待期间几个寄存器的状态:

DMACON 0x0000C800
DMASTAT 0x00000001

我使用的是 SPI1A 端口,因此 SPI1ABUF 和 _SPI1A_RX_IRQ

DCH1SPTR 0x5
DCH1SSIZ 0x2B

DCH2DPTR 0x6
DCH2DSIZ 0x2B

DCH2CON 0x00008083
DCH2ECON 0x1B10
DCH2INT 0x00800C4
DCH2SSA 0x1F805820
DCH2DSA 0x00000620

通道1用于传输
通道2用于接收

I know that this topic (DMA & SPI) has already been talked about on numerous threads in the microchip forum, actually i've read all the 15 pages in result of the search with keyword "dma" and read all the topics about dma & spi.

And I am still stuck with my problem I hope someone can help me :)

Here is the problem.

My chip is a PIC32MX775F512H.
I am trying to receive (only receive) data using SPI via DMA.
Since you cannot "just" receive in SPI, and that the SPI core starts toggling the SPI clock only if you write into the SPIBUF (SPI1ABUF for me) I am trying to receive my data using 2 DMA channels.
DMA_CHANNEL1 for the transmitting part.
DMA_CHANNEL2 for the receiving part.

I copy pasted the code from http://www.microchip.com/forums/tm.aspx?tree=true&high=&m=562453&mpage=1#

And tried to make it work without any luck. It only receives several bytes (5 or 6).

I've set the Event Enable Flags to DMA_EV_BLOCK_DONE for both dma channels, no interrupt occurs.

Do you have any idea ?

Here is the code I am using :

int Spi_recv_via_DMA(SPI_simple_master_class* SPI_Port, int8u *in_bytes, int16u num_bytes2) 
{ 
DmaChannel   dmaTxChn=DMA_CHANNEL1; 
DmaChannel   dmaRxChn=DMA_CHANNEL2; 
SpiChannel   spiTxChn=SPI_Port->channel; 
    int8u           dummy_input; 

    DmaChnOpen(dmaTxChn, DMA_CHN_PRI3, DMA_OPEN_DEFAULT); 
    DmaChnOpen(dmaRxChn, DMA_CHN_PRI3, DMA_OPEN_DEFAULT); 

    DmaChnSetEventControl(dmaTxChn, DMA_EV_START_IRQ_EN | DMA_EV_START_IRQ(_SPI1A_RX_IRQ)); 
    DmaChnSetEventControl(dmaRxChn, DMA_EV_START_IRQ_EN | DMA_EV_START_IRQ(_SPI1A_RX_IRQ)); 

    DmaChnClrEvFlags(dmaTxChn, DMA_EV_ALL_EVNTS); 
    DmaChnClrEvFlags(dmaRxChn, DMA_EV_ALL_EVNTS); 
    DmaChnSetEvEnableFlags(dmaRxChn, DMA_EV_BLOCK_DONE); 
    DmaChnSetEvEnableFlags(dmaTxChn, DMA_EV_BLOCK_DONE); 

    //SpiChnClrTxIntFlag(spiTxChn); 
    //SpiChnClrRxIntFlag(spiTxChn); 

    DmaChnSetTxfer(dmaTxChn, tx_dummy_buffer, (void *)&SPI1ABUF, num_bytes2, 1, 1); 
    DmaChnSetTxfer(dmaRxChn, (void *)&SPI1ABUF, in_bytes, 1, num_bytes2, 1); 

    while ( (SPI1ASTAT & SPIRBE) == 0) 
        dummy_input = SPI1ABUF; 
    SPI1ASTAT &= ~SPIROV; 

    DmaRxIntFlag = 0; 
    DmaChnEnable(dmaRxChn); 
    DmaChnStartTxfer(dmaTxChn, DMA_WAIT_NOT, 0); 


    while(!DmaRxIntFlag); 
    return 1;    
} 

with those two interrupt handlers :

// handler for the DMA channel 1 interrupt 
void __ISR(_DMA1_VECTOR, ipl5) DmaHandler1(void) 
{ 
int evFlags;     // event flags when getting the interrupt 
    //LED_On(LED_CFG); 
INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL1)); // acknowledge the INT controller, we're servicing int 

evFlags=DmaChnGetEvFlags(DMA_CHANNEL1); // get the event flags 

    if(evFlags&DMA_EV_BLOCK_DONE) 
    { // just a sanity check. we enabled just the DMA_EV_BLOCK_DONE transfer done interrupt 
        DmaTxIntFlag = 1; 
    DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE); 
    } 
   // LED_Off(LED_CFG); 
} 

void __ISR(_DMA2_VECTOR, ipl5) DmaHandler2(void) 
{ 
int evFlags;     // event flags when getting the interrupt 

INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL2)); // acknowledge the INT controller, we're servicing int 

evFlags=DmaChnGetEvFlags(DMA_CHANNEL2); // get the event flags 

    if(evFlags&DMA_EV_BLOCK_DONE) 
    { // just a sanity check. we enabled just the DMA_EV_BLOCK_DONE transfer done interrupt 
        DmaRxIntFlag = 1; 
    DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_BLOCK_DONE); 
    } 
} 

So I end up waiting forever at the line : while(!DmaRxIntFlag);

I have put breakpoints in the interrupt vectors, they are never called.

This is the state of several registers during the ever lasting wait :

DMACON 0x0000C800
DMASTAT 0x00000001

I am using SPI1A port, so SPI1ABUF and _SPI1A_RX_IRQ

DCH1SPTR 0x5
DCH1SSIZ 0x2B

DCH2DPTR 0x6
DCH2DSIZ 0x2B

DCH2CON 0x00008083
DCH2ECON 0x1B10
DCH2INT 0x00800C4
DCH2SSA 0x1F805820
DCH2DSA 0x00000620

Channel 1 is used to transmit
Channel 2 is used to receive

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我三岁 2024-10-26 23:43:25

您错过了这些:

INTEnable(INT_SOURCE_DMA(dmaTxChn), INT_ENABLED);   // Tx
INTEnable(INT_SOURCE_DMA(dmaRxChn), INT_ENABLED);   // Rx

就在祝

DmaRxIntFlag = 0; 
DmaChnEnable(dmaRxChn); 
DmaChnStartTxfer(dmaTxChn, DMA_WAIT_NOT, 0); 

您好运!

You are missing these:

INTEnable(INT_SOURCE_DMA(dmaTxChn), INT_ENABLED);   // Tx
INTEnable(INT_SOURCE_DMA(dmaRxChn), INT_ENABLED);   // Rx

rigth before

DmaRxIntFlag = 0; 
DmaChnEnable(dmaRxChn); 
DmaChnStartTxfer(dmaTxChn, DMA_WAIT_NOT, 0); 

Good luck!

感受沵的脚步 2024-10-26 23:43:25
  1. 您是否在从机模式下使用 SPI?或者您处于主模式,尝试读取命令的一些响应?
  2. 您检查过该芯片的硅勘误表吗? dspic 33fj 系列存在 SPI 从机模式根本无法工作的问题。

除此之外,我认为忙于等待 DmaRxIntFlag 更改不是一个好主意。您应该配置 DMA 传输并继续主循环。 DMA 将触发中断处理程序。

希望这有帮助。

  1. Are you using the SPI in slave mode? or you are on master mode, trying to read some response for a command?
  2. Have you check the silicon errata for this chip? The dspic 33fj family had an issue where SPI slave mode simply didn't work.

Other than that, I don't think it is a good idea to busy wait for DmaRxIntFlag change. You should configure the DMA transfer and continue with your main loop. The DMA will trigger the interrupt handler.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文