Получение данных SPI через DMA на PIC32 - PullRequest
3 голосов
/ 02 марта 2011

Я знаю, что эта тема (DMA & SPI) уже обсуждалась в многочисленных темах на форуме по микрочипам, на самом деле я прочитал все 15 страниц в результате поиска по ключевому слову "dma" и прочитал все темы о дма и спи.

И я все еще застрял со своей проблемой, надеюсь, кто-то может мне помочь :)

Вот проблема.

Мой чип - PIC32MX775F512H. Я пытаюсь получать (только получать) данные, используя SPI через DMA. Поскольку вы не можете «просто» получать в SPI, и что ядро ​​SPI начинает переключать тактовую частоту SPI, только если вы записываете в SPIBUF (SPI1ABUF для меня), я пытаюсь получить свои данные, используя 2 канала DMA. DMA_CHANNEL1 для передающей части. DMA_CHANNEL2 для принимающей части.

Копирую вставленный код из http://www.microchip.com/forums/tm.aspx?tree=true&high=&m=562453&mpage=1#

И безуспешно пытался заставить его работать. Он получает только несколько байтов (5 или 6).

Я установил флаги разрешения событий на DMA_EV_BLOCK_DONE для обоих каналов dma, прерывание не происходит.

У вас есть идеи?

Вот код, который я использую:

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 используется для приема

Ответы [ 2 ]

1 голос
/ 30 апреля 2013

Вам не хватает этих:

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); 

Удачи!

0 голосов
/ 12 июля 2011
  1. Используете ли вы SPI в подчиненном режиме? или вы находитесь в режиме мастера, пытаясь прочитать ответ на команду?
  2. Проверяли ли вы кремниевые ошибки для этого чипа? У семейства dspic 33fj была проблема, из-за которой режим SPI slave просто не работал.

Кроме этого, я не думаю, что это хорошая идея - заняться ожиданием изменения DmaRxIntFlag. Вы должны настроить передачу DMA и продолжить ваш основной цикл. DMA активирует обработчик прерываний.

Надеюсь, это поможет.

...