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.

MSP430F5510, multibyte SPI transfer using DMA

Other Parts Discussed in Thread: MSP430F5510

Hi,

I'm using MSP430F5510 acting like SPI master and trying to read 512 bytes of data to the designated buffer with DMA.

As far as I know, I need to use two DMA channels: one triggered by TXIFG and one by RXIFG (since you need to send a byte to get a byte answer from a SPI slave)

My plan is like this:

1. initiliaze two DMA channels [one to send dummy bytes, one to transfer received bytes to buffer]
2. trigger transmission by toggling UCTXIFG bit
3. wait until interrupt happens and flag is reset there

The problem is, ISR is never called (global interrupts are enabled).

My code is as follows (I'm using TI's driver library):

#define FLASH_DMA_CHANNEL_RX    DMA_CHANNEL_2
#define FLASH_DMA_CHANNEL_TX    DMA_CHANNEL_1

// UCB1TX
    DMA_init(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX, DMA_TRANSFER_SINGLE, 1, DMA_TRIGGERSOURCE_23, DMA_SIZE_SRCBYTE_DSTBYTE, DMA_TRIGGER_HIGH);
    DMA_setSrcAddress(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX, (uint32_t)&dummy_byte, DMA_DIRECTION_UNCHANGED);
    DMA_setDstAddress(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX, SPI_getTransmitBufferAddressForDMA(__MSP430_BASEADDRESS_USCI_B1__), DMA_TRIGGER_RISINGEDGE);
    DMA_enableInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX);

    // UCB1RX
    DMA_init(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX, DMA_TRANSFER_SINGLE, 1, DMA_TRIGGERSOURCE_22, DMA_SIZE_SRCBYTE_DSTBYTE, DMA_TRIGGER_HIGH);
    DMA_setSrcAddress(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX, SPI_getReceiveBufferAddressForDMA(__MSP430_BASEADDRESS_USCI_B1__), DMA_TRIGGER_RISINGEDGE);
    DMA_setDstAddress(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX, (uint32_t)&(dst_buffer[0]), DMA_DIRECTION_INCREMENT);
    DMA_enableInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX);

    flash_dma_active = true; // used to determine the end of DMA transfer

    DMA_enableTransfers(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX);
    DMA_enableTransfers(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX);

    // trigger initial symbol transmission
    UCB1IFG &= ~UCTXIFG;
    UCB1IFG |=  UCTXIFG;

    while(flash_dma_active); // flag is reset in ISR

    DMA_clearInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX);
    DMA_clearInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX);
    DMA_disableInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX);
    DMA_disableInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX);

  • Maxim Danilov said:
    2. trigger transmission by toggling UCTXIFG bit

    I'm not sure whether this works. My onw code triggers the transfer by writing the first dummy byte manually.

    Why do you enable DMA interrupt for both, TX and RX channel? RX is sufficient.

    Is the USCI set up properly? Especially you may not configure the USCI to trigger an interrupt itself, or the DMA doesn't get triggered.

    I'm not familiar with the API you use. What are DMA_TRIGGER_HIGH and DMA_TRIGGER_RISINGEDGE  and why do you set DMA_TRIGGER_HIGH on DMA_init, bti DMA_TRIGGER_RISINGEDGE on DMA_setScrAddress?

    Note that you may only use edge-triggered DMA except for external DMA trigger which may be level triggered too.

    Maxim Danilov said:
    while(flash_dma_active); // flag is reset in ISR

    I hope that flash_dma_active is a volatile variable?

  • Jens-Michael, thanks for your reply!

    Jens-Michael Gross said:

    2. trigger transmission by toggling UCTXIFG bit

    I'm not sure whether this works. My onw code triggers the transfer by writing the first dummy byte manually.

    [/quote]

    That trick works!

    Jens-Michael Gross said:

    Is the USCI set up properly? Especially you may not configure the USCI to trigger an interrupt itself, or the DMA doesn't get triggered.

    Thanks, that was the case, USCI interrupts were enabled.

    Jens-Michael Gross said:

    I'm not familiar with the API you use. What are DMA_TRIGGER_HIGH and DMA_TRIGGER_RISINGEDGE  and why do you set DMA_TRIGGER_HIGH on DMA_init, bti DMA_TRIGGER_RISINGEDGE on DMA_setScrAddress?

    That was a typo.

    Jens-Michael Gross said:

    while(flash_dma_active); // flag is reset in ISR

    I hope that flash_dma_active is a volatile variable?

    [/quote]

    Yes, it's volatile.

    Final version of code (works properly) looks like this:

    #define FLASH_DMA_CHANNEL_RX            DMA_CHANNEL_2
    #define FLASH_DMA_CHANNEL_TX            DMA_CHANNEL_1
    #define FLASH_DMA_SOURCE_TX                DMA_TRIGGERSOURCE_23
    #define FLASH_DMA_SOURCE_RX                DMA_TRIGGERSOURCE_22

        uint8_t dummy_byte = FLASH_ANY;
        // TX
        DMA_init(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX, DMA_TRANSFER_SINGLE, length, FLASH_DMA_SOURCE_TX, DMA_SIZE_SRCBYTE_DSTBYTE, DMA_TRIGGER_HIGH);

        DMA_setSrcAddress(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX, (uint32_t)&dummy_byte, DMA_DIRECTION_UNCHANGED);

        DMA_setDstAddress(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX, SPI_getTransmitBufferAddressForDMA(__MSP430_BASEADDRESS_USCI_B1__), DMA_DIRECTION_UNCHANGED);
        // no interrupt needed for TX

        // RX
        DMA_init(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX, DMA_TRANSFER_SINGLE, length, FLASH_DMA_SOURCE_RX, DMA_SIZE_SRCBYTE_DSTBYTE, DMA_TRIGGER_HIGH);
        DMA_setSrcAddress(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX, SPI_getReceiveBufferAddressForDMA(__MSP430_BASEADDRESS_USCI_B1__), DMA_DIRECTION_UNCHANGED);
        DMA_setDstAddress(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX, (uint32_t)&(dst[0]), DMA_DIRECTION_INCREMENT);

        DMA_enableInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX);

        flash_dma_active = true; // volatile one, used to indicate the end of transfer

        DMA_enableTransfers(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX);
        DMA_enableTransfers(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_TX);

        UCB1IFG &= ~UCTXIFG;
        UCB1IFG |=  UCTXIFG;

        while(flash_dma_active); // is reset in DMA ISR

        DMA_clearInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX);
        DMA_disableInterrupt(__MSP430_BASEADDRESS_DMAX_3__, FLASH_DMA_CHANNEL_RX);

**Attention** This is a public forum