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.

Frame triggered DMA block transfers with mibspi not generating interrupts

Hello,

I am working on setting up the DMA on the RM57 HDK (XRM57 mcu) to service 3 separate mibspi peripherals. I've managed to get it working transferring data with hardware triggers for each frame in the block (only if the transfer group buffer mode is set to 4), but I can't seem to get it to generate a block transfer complete (BTC) interrupt when the block (should) be finished nor can I get it to transmit more than a single frame when the buffer mode is set to 7 and the trigger type is set to frame, which would make sense if the DMA TX/RX frames aren't being properly triggered. 

Essentially I want to do the following:

I have an ADC that requires a 24 byte spi operation once every 65 microseconds. The ADC itself is currently clocked at 10MHz. The mibspi and DMA should handle all these operations and the DMA should copy each 24B transfer to internal memory and notify the cpu once for every 128 transfers (~ every 8.3ms). The CPU should then change the DMA RX block pointer and restart the DMA.

To accomplish this I've setup the following:

I have setup the mibspi for 8 byte operations with a transfer group size of 24 and a buffer mode of 7 (wait until TX/RX full/empty). Oneshot transfer is not set.

The mibspi is triggered off the rising edge of an internal HET signal once every 65 microseconds.

The DMA TX control packet is configured as shown:

where frameCount = 128

hwInfo->transferGroupSize_elements = 24

  dmaControlPacketTX.SADD = sourceAddress;
  dmaControlPacketTX.DADD = (uint32_t)&(hwInfo->ramBaseAddress->tx[0].data);
  dmaControlPacketTX.CHCTRL = 0;
  dmaControlPacketTX.FRCNT = frameCount; 
  dmaControlPacketTX.ELCNT = hwInfo->transferGroupSize_elements;
  dmaControlPacketTX.ELDOFFSET = 4;
  dmaControlPacketTX.ELSOFFSET = 2;
  dmaControlPacketTX.FRDOFFSET = 0;
  dmaControlPacketTX.FRSOFFSET = 0;
  dmaControlPacketTX.PORTASGN = PORTA_READ_PORTB_WRITE;
  dmaControlPacketTX.RDSIZE = ACCESS_16_BIT;
  dmaControlPacketTX.WRSIZE = ACCESS_16_BIT;
  dmaControlPacketTX.TTYPE = FRAME_TRANSFER;
  dmaControlPacketTX.ADDMODERD = ADDR_OFFSET;
  dmaControlPacketTX.ADDMODEWR = ADDR_OFFSET;
  dmaControlPacketTX.AUTOINIT = AUTOINIT_ON;

The DMA RX packet is configured as follows:

  dmaControlPacketRX.SADD = (uint32_t)&(hwInfo->ramBaseAddress->rx[0].data);
  dmaControlPacketRX.DADD = destAddress;
  dmaControlPacketRX.CHCTRL = 0;
  dmaControlPacketRX.FRCNT = frameCount; 
  dmaControlPacketRX.ELCNT = hwInfo->transferGroupSize_elements;
  dmaControlPacketRX.ELDOFFSET = 2;
  dmaControlPacketRX.ELSOFFSET = 4;
  dmaControlPacketRX.FRDOFFSET = hwInfo->transferGroupSize_elements*2;
  dmaControlPacketRX.FRSOFFSET = 0;
  dmaControlPacketRX.PORTASGN = PORTB_READ_PORTA_WRITE;
  dmaControlPacketRX.RDSIZE = ACCESS_16_BIT;
  dmaControlPacketRX.WRSIZE = ACCESS_16_BIT;
  dmaControlPacketRX.TTYPE = FRAME_TRANSFER;
  dmaControlPacketRX.ADDMODERD = ADDR_OFFSET;
  dmaControlPacketRX.ADDMODEWR = ADDR_OFFSET;
  dmaControlPacketRX.AUTOINIT = AUTOINIT_ON;

My understanding of the DMA is that with TTYPE=FRAME_TRANSFER every dma req. signal the mibspi generates should trigger a single frame transfer until all 128 frames have been transferred, causing a block complete transfer interrupt. With an SPI buffer mode of 7, once the TX buffer is empty the DMA TX packet should refresh it, and once the RX buffer is full the DMA RX packet should empty it, and once this has been done the next HET trigger event should cause another SPI bus operation and the cycle should repeat until the DMA RX BTC interrupt is complete 128 operations later.

I've had success getting the DMA BTC interrupts when when I only want to transmit a single frame, however I don't want to tie the CPU up with an spi interrupt every 65us if possible. I can also see the SPI transfers on the scope once every 65us (as triggered by the HET) if the TTYPE is set to BLOCK_TRANSFER or if the spi buffer mode is set to 4 (always transmit) but this obviously doesn't give the quite the behavior I want.

One question as well regarding the frame and element offset: is the element offset reset after every frame? I am assuming so with this setup (reading/writing the SPI does not adjust frame, but reads from SPI to internal buffer do) but it wasn't completely clear to me when I read through the TRM.

Any assistance would be much appreciated,

  • Jonathan,

    This all seems pretty reasonable. What are you seeing exactly in this configuration? Are you seeing even the first 24-bit transfer complete and then nothing else?

    How have you configured the MibSPI (DMAxCTRL) register for the transfer group that you are using?
    This is what would generate DMA requests after the first one..

    And do you have *any other* transfer groups enabled ? One thing we've seen with MibSPI is that it appears it only evaluates one transfer group at a time, so a high priority transfer group that is stalled 'waiting' for data will also stall any lower priority transfer groups. It's best to only try one TG at a time.
  • Anthony,

    With this setup I only get a single 24 (byte) transfer triggered by the HET. I've been using transfer group 0 for everything, nothing else is enabled. That said, I am trying to do this simultaneously with 3 separate mibSPI modules. Each one has its own DMA configuration using separate channels, and if I just try a block transfer triggered by software (HET is unused) it seems to work fine with all 3 enabled simultaneously.
    For the DMA control register setup I've been using code from the mibspi example (formatting adjusted a touch):

    hwInfo->spiBaseAddress->DMACTRL[hwInfo->spiDMACTRLChannel] |= (hwInfo->spiREQChannelRX << 20);
    hwInfo->spiBaseAddress->DMACTRL[hwInfo->spiDMACTRLChannel] |= (hwInfo->spiREQChannelTX << 16);
    hwInfo->spiBaseAddress->DMACTRL[hwInfo->spiDMACTRLChannel] |= 0x8000C000;
    hwInfo->spiBaseAddress->DMACTRL[hwInfo->spiDMACTRLChannel] |= (0 << 8) | ((hwInfo->transferGroupSize_elements - 1) << 24);

    Appreciate the assistance,
  • Hi Jonathan,

    What's in the DMACTRL register when all the steps above are done? (best to check the hex value..)
    I'm looking to see which of the MibSPI buffers you've got the DMA channels triggered on..

    -Anthony
  • Anthony,

    I'm seeing a value of 0x9723C001 after those writes above. Does that appear correct?

    Thanks,
  • Anthony,

    I'm wrapping up today and will continue with this tomorrow AM, but skimming through the TRM having bit 31 set in the DMACTRL looks like a bit of a red flag to me. I will tinker with tomorrow and let you know.

    Cheers,
  • Jonathan,

    Well it's interesting. 

    0x9723C0001:

    So it's saying that the ONESHOT mode of the DMA request is enabled,  which means that the MibSPI would stop making DMA requests once COUNT = 0.  Now not completely sure about COUNT / ICOUNT [it's odd to have ICOUNT=0 but COUNT=1, except the definition of ICOUNT says the real # of transfers is ICOUNT+1 whereas COUNT's definition says it's the # of transfers remaining.   So both indicate that there is one DMA request that needs to be made.

    Now RXDMAENA and TXDMAENA are both set so that means the counter hasn't expired at the point where you are reading it.

    It should be monitoring buffer #23 in the MibSPI RAM - which if you have this setup for TG0 with 24 buffers would be correct.

    That seems right also.


    Ok so the ONESHOT isn't what you want - but i'd expect 2 transfers not 1 because there should be one transfer when you initially enable the transfer group;  and another when buffer 23 is executed the first time.

    I think to run this continually you will also want to remove the DMAxCTRL oneshot.   That should make this continually generate DMA requests.   it would be OK to generate both the transmit and receive DMA requests on the last buffer (#23) I think. 

    The initial transmit DMA request should be triggered when the TG is enabled.  But then the next one will be triggered when buffer 23 is executed - it's transmit data copied to the shift register and it's tx buffer becomes empty.   this would then write the next block of 24 transmit data words.   Likewise when buffer 23's RXREADY is set you want to read all the buffers receive data as a block of 24.

    Since you have told the RAM to wait for TXFULL and RXEMPTY ... there shouldn't be a problem with the first buffer in the TG because it shouldn't start shifting until the receive DMA also empties it's buffer contents. 

    Ok I guess where this is heading is that it looks like there is a problem but more should have happened than just 1 transfer,  assuming this is TG0 and you have buffer 23 assigned as the last buffer in the TG.

    If there's a different organization and it's a different TG that you are trying to DMA with then that may explain what's happening.

    BTW - My comment before about more than one TG was 'within' the same MibSPI.  You shouldn't have an issue with doing this same thing across three separate MibSPI's simultaneously.

    -Anthony

  • Anthony,

    This is one of those perfect examples where you flip a single bit (it was ONESHOT) and everything starts working. Your pointers on where to swing the hammer undoubtedly saved me a lot of time.

    Greatly appreciated,