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.

MSP432P401R: DMA External Trigger by external ADC data ready -> SPI Starts

Part Number: MSP432P401R

Hi,

is there any example of the external DMA input pin "DMAE0"  that start a SPI communication?

I want to use an external 24Bit ADC with the MSP432.

The interrupt PIN "Data ready" from the ADC should trigger the DMA on the DMAE0 channel.

Once the DMA is triggered it should start a SPI transfer with the new data and write the values to a buffer.

If the buffer value size is achieved, the DMA should wake the CPU.

There is an example using the internal 14Bit ADC whit DMA writting a 512 size buffer.

But how can i use it for external ADC? 

  • Michael,

       I am not aware of an example that has the level of integration and coordination that you are describing.  The idea is that you can take the existing examples and create the application you describing.

       What you are describing would be the integration of three separate DMA channels.  The first would be channel 6 mapped to source 7, the second would be the SPI transmitter (MOSI) which could be on any of the channels  0,2,4 (but not 6 because you need that for the IO trigger), and the third would be for the SPI reciever (MISO), channels 1,3,5.  All of these would be configured for 'basic' mode of operation, meaning that the corresponding trigger would be required for the DMA action to take place.  

       The first DMA, the DMAE0, has a source destination of the SPI transmit buffer and a source destination of some location in memory with a dummy value.  SPI transactions are only started when something is written to the TX buffer, so it is necessary to access the TX even if you are only reading data.  This transaction only happens one time and is complete, so there is no increment of source or destination registers.   Depending upon your application it may be simpler to just have a GPIO interrupt that writes a singular word to the transmit buffer.  You can have this DMA channel mapped to an interrupt but that is not necessary.

     The second DMA channel is to write to the TX buffer repeatedly as the TX buffer is empty (TXIFG is set).  The number of transfers is 512-1 because the first one was done by the first DMA channel.  Again, the value being written to the TX buffer is a don't care, so again neither the source nor the destination addresses are incremented.

      The third DMA actually takes the received data and places it into a buffer.  Please note that the DMA size is the size of the SPI buffer which is 8-bit.  This would mean that you would actually need to make 1536 writes to the SPI TX to get the 24-bit data.  In this implementation you would increment the destination address but not the source and after the transfer of all of the data you would need to concatenate the data into the original 24-bit values.  

      The example below is for eUSCIB0 which are channels 0 and 1.

       /* Setup the TX transfer characteristics & buffers */

       MAP_DMA_setChannelControl(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,

       UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1);

       MAP_DMA_setChannelTransfer(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,

       UDMA_MODE_BASIC, mstxDummyData,

               (void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),

               1);

       /* Setup the TX transfer characteristics & buffers */

       MAP_DMA_setChannelControl(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,

       UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1);

       MAP_DMA_setChannelTransfer(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,

       UDMA_MODE_BASIC, mstxDummyData,

               (void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),

               MAP_SPI_MSG_LENGTH-1);

       /* Setup the RX transfer characteristics & buffers */

       MAP_DMA_setChannelControl(DMA_CH1_EUSCIB0RX0 | UDMA_PRI_SELECT,

       UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);

       MAP_DMA_setChannelTransfer(DMA_CH1_EUSCIB0RX0 | UDMA_PRI_SELECT,

       UDMA_MODE_BASIC,

               (void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B0_BASE),

               msrxData,

               MAP_SPI_MSG_LENGTH);

    Regards,

    Chris

  • Have to go through IRQ (and waking up the mcu if sleeping)

    There is a msp competitor  that have exactly what you describe: Peripheral Reflex System
    Cousin to that lizard dude that sells car insurance.

  • Hi Chirs,

    thank you for your answer!
    So DMAE0 dont support SPI TX since i can only use him as INT for setting DMA to write to the SPI TX Buffer.
    So is there any other way to extern trigger the SPI TX and RX without needing the CPU for it?

    Here is the DMAE0 set up with the ADC14 setup to receive and transmitt all bytes:

    /* Configuring DMA module */
    DMA_enableModule();
    DMA_setControlBase(controlTable);


    DMA_disableChannelAttribute(DMA_CH7_ADC14,
    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK);


    /* Setting Control Indexes. In this case we will set the source of the
    * DMA transfer to ADC14 Memory 0
    * and the destination to the
    * destination data array. */
    MAP_DMA_setChannelControl(UDMA_PRI_SELECT | DMA_CH7_ADC14,
    UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_DMA_setChannelTransfer(UDMA_PRI_SELECT | DMA_CH7_ADC14,
    UDMA_MODE_PINGPONG, (void*) &ADC14->MEM[0],
    data_array1, SAMPLE_LENGTH);

    MAP_DMA_setChannelControl(UDMA_ALT_SELECT | DMA_CH7_ADC14,
    UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_DMA_setChannelTransfer(UDMA_ALT_SELECT | DMA_CH7_ADC14,
    UDMA_MODE_PINGPONG, (void*) &ADC14->MEM[0],
    data_array2, SAMPLE_LENGTH);

    /* Assigning/Enabling Interrupts */
    MAP_DMA_assignInterrupt(DMA_INT1, 7);
    MAP_Interrupt_enableInterrupt(INT_DMA_INT1);
    MAP_DMA_assignChannel(DMA_CH7_ADC14);
    MAP_DMA_clearInterruptFlag(7);
    MAP_Interrupt_enableMaster();

    /* Now that the DMA is primed and setup, enabling the channels. The ADC14
    * hardware should take over and transfer/receive all bytes */
    MAP_DMA_enableChannel(7);
  • Hello Michael,
    The sequence that I tried to describe above would not require any CPU interaction until the last DMA (the one associated with the RX) completed. At this time you would need to reconfigure all of the DMAs to perform another SPI reception.

    I did fail to notice that the message size is greater than 1024 and therefor you would need to use the ping-pong method instead of the basic. This means that you would have one additional interrupt for the DMA associated with the RX. The first interrupt is associated with the primary finishing and the second would be associated with the alternate. The completion of the alternate would signify the completion of SPI transaction.

    Just to reiterate: the first DMA is triggered by the actual GPIO, DMAE0, when the first DMA writes to the eusci TX buffer this triggers the second DMA to write to the TX buffer 'n-1' times (each time the TX buffer is shifted out), while this is taking place the eusci RX is triggering the third DMA which reads in 'n' times. After the third DMA performs 'n' transfers then an interrupt can be used to wake the CPU to process the received data or reset the DMAs.

    Hope that helps,
    Chris
  • Hi Chris,

    Seems to be a good idea! We were also looking for a way to receive data from 2 SPI slave peripherals. So 6 DMA channels would be used?

    However, there was still a problem when the SPI slave peripherals did not transmit out data constantly. What if there were some intervals between each data transmittings? In this situation since the second DMA channel's constantly dummy TX , erroneous data would be received by the third DMA channel. Do you have any idea about this issue?

    Best regards

**Attention** This is a public forum