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 Read Data with ScatterGather

Part Number: MSP432P401R

Hi,

i'm trying to communicate to a Cypress FRAM with help of DMA over the SPI. Writing data seems to work fine. Reading data via ScatterGather and a task list is my problem.

I first need to send the opcode to read followed by the address. Then the data is presented as long as CS is active an there are clock-cycles. I'm trying to setup a task list to receive the data but it does not work.

Here is my tasklist

DMA_ControlTable SPI_FRAM_ReadLine[2] =
{
     //Task 1 READ + Adresse senden
     DMA_TaskStructEntry(10, UDMA_SIZE_8,
                         UDMA_SRC_INC_8, &ui_fram_tx_buf[0],
                         UDMA_DST_INC_NONE, &EUSCI_B2_SPI->TXBUF,
                         UDMA_ARB_1, (UDMA_MODE_PER_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
     DMA_TaskStructEntry(10, UDMA_SIZE_8,
                              UDMA_SRC_INC_NONE, &EUSCI_B2_SPI->RXBUF,
                              UDMA_DST_INC_8, &ui_fram_rx_buf[0],
                              UDMA_ARB_1, (UDMA_MODE_BASIC))
};

And here the start of DMA:

MAP_DMA_setChannelScatterGather(DMA_CH4_EUSCIB2TX0,2,(void*)&SPI_FRAM_ReadLine[0],1);
MAP_DMA_clearInterruptFlag(DMA_CH4_EUSCIB2TX0 & 0x0F);
MAP_DMA_enableChannel(4);

Is it the correct channel that i'm activating? Is the task list correct ?

  • Hi TF,

    Do you use our example code? I think we should provide some example code for SPI.

    Or do you try use SPI without DMA?

    If you use our example code and also have some issue, maybe can capture some wave for SPI.

    Thanks!

    Best Regards

    Johnson 

  • Hi Johnson,

    Thank you for the Reply.

    I took a look at the examples and tried to change them to my needs.

    I need to send first the operationcode followed by the startaddress. The the following CLK-cycles are used to read the data from the FRAM (Cypress CY15B104).

    today i tried a different approach by using the task list with only one task (Opcode, 3 Byte Address and 6 dummys) and configured the receive-channel (EUSCI_B2_RX) without a task list. Berfor i startet the transmit of the opcode, address and dummybytes, i enabled the receiving channel 5 (eusci_B2). The FRAM does output ist data, but the configured destination (ui_fram_rx_buf) only gets a  single wrong value in all fields.

    This is my initialisation:

    //DMA-Settings
    MAP_DMA_enableModule();
    MAP_DMA_setControlBase(RTC_SPI_DMAControlTable);
    
    /* Assign DMA channel 4 to EUSCI_B2_TX0, channel 5 to EUSCI_B2_RX0 */
    /* Assign DMA channel 6 to EUSCI_B3_TX0, channel 7 to EUSCI_B3_RX0 */
    MAP_DMA_assignChannel(DMA_CH4_EUSCIB2TX0);
    MAP_DMA_assignChannel(DMA_CH5_EUSCIB2RX0);
    MAP_DMA_assignChannel(DMA_CH6_EUSCIB3TX0);
    MAP_DMA_assignChannel(DMA_CH7_EUSCIB3RX0);
    
    /* Setup the TX transfer characteristics & buffers */
    //FRAM
    MAP_DMA_setChannelControl(DMA_CH4_EUSCIB2TX0 | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
    MAP_DMA_setChannelControl(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_16);
    //RTC
    MAP_DMA_setChannelControl(DMA_CH6_EUSCIB3TX0 | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
    MAP_DMA_setChannelControl(DMA_CH7_EUSCIB3RX0 | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    
    /* Enable DMA interrupt */
    MAP_DMA_clearInterruptFlag(4);
    MAP_DMA_clearInterruptFlag(5);
    MAP_DMA_clearInterruptFlag(6);
    MAP_DMA_clearInterruptFlag(7);
    MAP_DMA_assignInterrupt(DMA_INT1,5);
    MAP_DMA_assignInterrupt(DMA_INT2,7);
    
    /* Assigning/Enabling Interrupts */
    DMA_registerInterrupt(DMA_INT1,DMA_INT1_IRQHandler);
    Interrupt_enableInterrupt(INT_DMA_INT1);
    MAP_DMA_enableInterrupt(INT_DMA_INT1);
    DMA_registerInterrupt(DMA_INT2,DMA_INT2_IRQHandler);
    Interrupt_enableInterrupt(INT_DMA_INT2);
    MAP_DMA_enableInterrupt(INT_DMA_INT2);
    MAP_Interrupt_enableInterrupt(INT_DMA_INT0);
    MAP_DMA_enableInterrupt(INT_DMA_INT0);

    Here the ISR:

    void DMA_INT0_IRQHandler(void)
    {
        //Get Status
        uint32_t DMA_Int_Status=MAP_DMA_getInterruptStatus();
    
    
        if (DMA_Int_Status && (DMA_CH6_EUSCIB3TX0 & 0x0F))
        {
            MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P10,GPIO_PIN0);
            if(!DMA_isChannelEnabled(6) && (SPI_isBusy(EUSCI_B3_BASE)==EUSCI_SPI_NOT_BUSY) )
            {
                //Wenn der SPI fertig ist, den Interrupt löschen
                MAP_DMA_clearInterruptFlag(6);
            }
        }
        if (DMA_Int_Status && (DMA_CH4_EUSCIB2TX0 & 0x0F))
        {
            //CS des Speichers wieder High Schalten
            //FRAM_ResetCS();
            if(!DMA_isChannelEnabled(4) && (SPI_isBusy(EUSCI_B2_BASE)==EUSCI_SPI_NOT_BUSY) )
            {
                //Wenn der SPI fertig ist, den Interrupt löschen und Channel Disable
                MAP_DMA_disableChannel(4);
                MAP_DMA_clearInterruptFlag(4);
            }
        }
    }
    
    /* Interrupt wenn FRAM/Speicher Daten fertig gelsen worden sind*/
    void DMA_INT1_IRQHandler(void)
    {
    
        x_Speicher_Message_t xspeicher_message;
        BaseType_t xHigherPriorityTaskWoken=pdFALSE;
        MAP_DMA_clearInterruptFlag(5);
        //FRAM_ResetCS();
        //Info an den Speicher-Task, das Daten fertig sind
        xspeicher_message.telegram_type=TeleSpeicher_Zeile_gelesen;
        xQueueSendToBackFromISR(xQueueSpeicher,(void *) &xspeicher_message,&xHigherPriorityTaskWoken);
        //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }
    
    /* Interrupt wenn RTC Daten fertig gelsen worden sind*/
    void DMA_INT2_IRQHandler(void)
    {
        BaseType_t xHigherPriorityTaskWoken=pdFALSE;
        RTC_Message_t rtc_task_message;
        //was anderes tun, da Datenempfang fertig
        MAP_DMA_clearInterruptFlag(DMA_CH7_EUSCIB3RX0 & 0x0F);
        rtc_task_message.ucMessageID=RTC_GET_TIME_FROM_PC2129_FINISH;
        xQueueSendToBackFromISR(xQueueRTCSend,(void *) &rtc_task_message,&xHigherPriorityTaskWoken);
        xTaskResumeFromISR(xTaskHandle_RTC);
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }
    

    Now the part where i want to start the reading

    while(MAP_DMA_isChannelEnabled(4))
    {__nop();}
    taskENTER_CRITICAL();
    MAP_DMA_setChannelTransfer(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
                                 UDMA_MODE_BASIC,
                                 (void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B2_BASE),
                                 ui_fram_rx_buf,
                                 10);
    MAP_DMA_clearInterruptFlag(5);
    MAP_DMA_enableInterrupt(INT_DMA_INT1);
    MAP_DMA_enableChannel(5);
    
    ui_fram_tx_buf[0]=OPCODE_READ;
    ui_fram_tx_buf[1]=((uxAdresse>>16)&0xFF);
    ui_fram_tx_buf[2]=((uxAdresse>>8)&0xFF);
    ui_fram_tx_buf[3]=(uxAdresse&0xFF);
    ui_fram_tx_buf[4]=0x00;
    ui_fram_tx_buf[5]=0x00;
    ui_fram_tx_buf[6]=0x00;
    ui_fram_tx_buf[7]=0x00;
    ui_fram_tx_buf[8]=0x00;
    ui_fram_tx_buf[9]=0x00;
    ui_fram_tx_buf[10]=0x00;
    //FRAM_SPI_Send_Bytes(10,ui_fram_tx_buf);
    MAP_DMA_setChannelScatterGather(DMA_CH4_EUSCIB2TX0,TASK_COUNT_READ_LINE,(void*)&SPI_FRAM_ReadLine[0],1);
    MAP_DMA_clearInterruptFlag(DMA_CH4_EUSCIB2TX0 & 0x0F);
    MAP_DMA_enableChannel(4);
    taskEXIT_CRITICAL();

    The second DMA (channel 6+7) are used for a RTC and are working fine. Following a screenshot with the result on SPI. The value in my destination is 0x9E.

    I'm trying to use this part in a Project with FreeRTOS.

  • Hi TF,

    You means that the wave of SPI is normal? I see the MISO(....  9E.. ) and MOSI(03 ... ) is match your code?

    Thanks!

    Best Regards

    Johnson

  • Hi Johnson,

    yes it matches. 0x03 is the Opcode for a Readoperation followed by three bytes as the address. MOSI/MISO are only the interpretation of D1 and D2. D0 is the clocksignal and D3 is the chipselect (active low).

    It seems that only the Last byte gets copied in my buffer (ui_fram_rx_buf[0-9] is filled with 0x9e). I checked this with help of CCS  debugger and the code itself by printing the values in my display. something is going terribly wrong during the copy from EUSCI_B2_RXBUF to my buffer ui_fram_rxbuf. But i dont find my mistake.

    I'm shortly befor testing with another SPI-interface of the MSP. But i think it must work with every interface of the controller.

  • Hi,

    i think i found a solution for my problem. After changing the the part from ScatterGather to basic mode for the read operation nothing changed. I needed to cast the buffers.

    DMA_setChannelTransfer(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
                                     UDMA_MODE_AUTO,
                                     (uint8_t *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B2_BASE),
                                     (uint8_t *) ui_fram_rx_buf,
                                     12);

    After this change, the reading of tzhe FRAM works, if i do not send any write befor. This is maybe another problem in my code or the initialisation of the write with ScatterGather