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.

IWR1443: How to set up basic EDMA transfer

Part Number: IWR1443

I want to set up a basic EDMA transfer to copy from one memory location to another.  I do not need chaining, automatic triggering, multiple parameter sets, etc.  Just a basic transfer using a manual start.  I have watched the videos located at training.ti.com/using-c6000-edma3-part-2-14-15, and the documentation at file:///C:/ti/mmwave_sdk_02_01_00_04/packages/ti/drivers/edma/docs/doxygen/html/index.html.  While they give an overview of the many capabilities, I am still confused as to how to set up the configuration for just a basic transfer.

I have the following as a start to try copying from one variable to another:

static uint32_t test_source;
static uint32_t test_destination;
int32_t iwr_hw_test_config_EDMA(MmwDemo_DataPathObj *obj)
{
    int32_t errorCode = EDMA_NO_ERROR;
    EDMA_Handle handle = obj->edmaHandle;
    EDMA_channelConfig_t config;
    HWA_SrcDMAConfig dmaConfig;
    test_source = 0x01020304;
    test_destination = 0;
    config.channelId = 30;
    config.channelType = (uint8_t)EDMA3_CHANNEL_TYPE_DMA;
    config.paramId = 30;
    config.eventQueueId = 0;
    config.paramSetConfig.sourceAddress = (uint32_t) &test_source;
    config.paramSetConfig.destinationAddress = (uint32_t) &test_destination;
    config.paramSetConfig.aCount = 4;
    config.paramSetConfig.bCount = 1;
    config.paramSetConfig.cCount = 1;
    config.paramSetConfig.bCountReload = config.paramSetConfig.bCount;
    config.paramSetConfig.sourceBindex = 0;
    config.paramSetConfig.destinationBindex = 0;
    config.paramSetConfig.sourceCindex = 0;
    config.paramSetConfig.destinationCindex = 0;
    config.paramSetConfig.linkAddress = EDMA_NULL_LINK_ADDRESS;
    config.paramSetConfig.transferType = (uint8_t)EDMA3_SYNC_A;
    config.paramSetConfig.transferCompletionCode = 0;
    config.paramSetConfig.sourceAddressingMode = (uint8_t) EDMA3_ADDRESSING_MODE_LINEAR;
    config.paramSetConfig.destinationAddressingMode = (uint8_t) EDMA3_ADDRESSING_MODE_LINEAR;
    /* don't care because of linear addressing modes above */
    config.paramSetConfig.fifoWidth = (uint8_t) EDMA3_FIFO_WIDTH_8BIT;
    config.paramSetConfig.isStaticSet = false;
    config.paramSetConfig.isEarlyCompletion = false;
    config.paramSetConfig.isFinalTransferInterruptEnabled = false;
    config.paramSetConfig.isIntermediateTransferInterruptEnabled = false;
    config.paramSetConfig.isFinalChainingEnabled = false;
    config.paramSetConfig.isIntermediateChainingEnabled = false;
    config.transferCompletionCallbackFxn = NULL;
    config.transferCompletionCallbackFxn = (EDMA_transferCompletionCallbackFxn_t)MmwDemo_EDMA_transferCompletionCallbackFxn;
    config.transferCompletionCallbackFxnArg = MMWDEMO_EDMA_TRANSFER_COMPLETION_CODE_CFAR_DONE;
    if ((errorCode = EDMA_configChannel(handle, &config, false)) != EDMA_NO_ERROR)
    {
        System_printf("Error: EDMA_configChannel() failed with error code = %d\n", errorCode);
        goto exit;
    }
exit:
    return(errorCode);
}

It is unclear to me what to put in for the config.paramid field when I want to use the configuration in the config structure and not a separate parameter set.  Is the rest of the configuration appropriate?  Are there any code examples of setting up a basic manual transfer?

Thanks,

Alan

  • I tried modifying the code above to align with the EDMAutil_configType1() function in the dss_condig_edma_util.c file located in the 68xx_vital_signs lab.  I set the chId to EDMA_TPCC0_REQ_FREE_2 since it was not used anywhere else in the high accuracy lab.  Thus the channelId, paramId and transferCompletionCode parameters are set to EDMA_TPCC0_REQ_FREE_2.  I then have the following in the main.c file:

            iwr_hw_test_config_EDMA(dataPathObj);
            EDMA3EnableTransfer(EDMA_CC0_BASE_ADDRESS, EDMA_TPCC0_REQ_FREE_2, EDMA3_TRIG_MODE_MANUAL);
            EDMA_startDmaTransfer(dataPathObj->edmaHandle, EDMA_TPCC0_REQ_FREE_2);

    When I run the code and try to step past the starting of the DMA transfer, it ends up in theMmwDemo_EDMA_transferControllerErrorCallbackFxn() function, indicating that there is an error.  Looking at the errorInfo structure, isBusError is set to 1, and errorCode in the busErrorInfo structure is set to 1.  The EDMA User Guide indicates that the 1 means there is a read error.  Reference the Error Details Register (ERRDET).  I do not find any description of what that read error code of 1h means (as opposed to the 2h - 7h values for STAT that would also indicate a read error.

    How do I determine what was the cause of the read error?

  • Hi Alan,

    Please refer to the EDMA test provided in the EDMA driver directory given below.

    C:\ti\mmwave_sdk_02_01_00_04\packages\ti\drivers\edma\test\

    The driver test includes example for manually triggered, unchained and un-linked transfer in function Test_unchainedUnlinked in main.c.

    -Nitin

  • Hi Nitin,

    My concern is with how to configure a EDMA channel for a single, unlinked transfer.  Looking at the function you mention, it configures the channel using the testChannelConfig argument, which is therefore defined by the function calling the Test_unchainedUnlinked() function.  If I do a search for where the function is called, I get 5 locations.  All are within the Test_simultaneousUnchainedUnlinkedTransfersSuite() function.  The last three instances are for multi transfers, which is not what I want.  The second is for a mix of EDMA and QDMA, which I also do not want.  That leaves the first as a possibility, so I did a search for the definition of testChannelConfig__DBG

    The testChannelConfig__DBG defines the channelId and channelType for the 1st channel as QDMA, which is not what I want.

    So I still do not see how to configure an EDMA channel for a single, unlinked transfer.

    Alan

  • The driver API interface is edma.h which is well documented (you can also look up the doxygen documentation for a neater read). You should be able to understand the interface and code to what you need. In the test code which calls the driver APIs, there is sort of a framework but you should pay more attention to where the actual driver APIs are called. The simultaneous tests simply configure 4 channels but there is no reason why you couldn't setup one channel. There are no special APIs in the driver to configure 4 channels [as the EDMA IP has nothing special in h/w for this], the simultaneous test simply calls the config API 4 times with different parameters and calls transfer start APIs 4 times and so on. You should also be able to change the parameters of the __DBG one to whatever it is that you want to setup your transfer to, it shouldn't be that difficult for example to modify the channel type from QDMA to DMA and other parameters once you understand the driver API.

  • Hello Piyush,

    I have been looking through the documentation.  Based on what I read and looking at examples, I tried setting up an EDMA transfer with a manual start.  I ended up in an assert as noted in my post of Jan 6, 2020 3:44 PM above.  The documentation says that the errorCode in the busErrorInfo structure being set to 1 means there was a read error, but not what are possible causes of the read error.  The fact that the errorCode can have values from 1h to 7h implies that the value may correspond to different causes.  I asked if there is some documentation what the different values mean, but have not received a response on that.  If the reason for the 1h error code can be determined, troubleshooting the configuration would be simplified.

  • The different causes are internal to the bus infrastructure so they are not public. It is sufficient to know whether it is a read or a write error, what it basically means is that the address EDMA is reading from (source) or writing to (destination) is invalid address in the SoC. You need to check your programming to see if the source points to valid memory. Note also that address translation may be required, we have APIs in soc driver to do this and their use is illustrated in the edma unit test code and demo. I observed that in the code you quoted you were using some APIs that are deeper in the implementation of EDMA driver, you should only use the top level APIs in edma.h which is the public interface.

  • Hello Piyush,

    Based on your comments, I changed the APIs to use what are in the edma.h file and added a check on the transfer completion as a test:

            iwr_hw_test_config_EDMA(dataPathObj);
            error_code = EDMA_enableChannel(dataPathObj->edmaHandle, EDMA_TPCC0_REQ_FREE_2, EDMA3_CHANNEL_TYPE_DMA);
            error_code = EDMA_startTransfer(dataPathObj->edmaHandle, EDMA_TPCC0_REQ_FREE_2, EDMA3_CHANNEL_TYPE_DMA);
            error_code = EDMA_isTransferComplete(dataPathObj->edmaHandle, EDMA_TPCC0_REQ_FREE_2, &transfer_complete);
            while (!transfer_complete)
            {
                error_code = EDMA_isTransferComplete(dataPathObj->edmaHandle, EDMA_TPCC0_REQ_FREE_2, &transfer_complete);
            }

    The enable and start APIs in the above return 0 as the error_code, so it appears that everything is OK.  Just trying to copy 5 bytes as a test (so my present code is a bit different than at the start of this thread).

    The buffers are:

    uint8_t test_source[10];
    uint8_t test_destination[10];

    I have verified that the sourceAddress and destinationAddress parameters are correct in the config setup by putting a breakpoint there:

    chId = EDMA_TPCC0_REQ_FREE_2;
    config.channelId = chId;
    config.channelType = (uint8_t)EDMA3_CHANNEL_TYPE_DMA;
    config.paramId = chId;
    config.eventQueueId = 0;
    config.paramSetConfig.sourceAddress = (uint32_t)test_source;
    config.paramSetConfig.destinationAddress = (uint32_t)test_destination;

    I went through my configuration function and compared it to the MmwDemo_edmaBlockCopy() function in the 16xx_traffic_monitoring lab since the header notes said that it performs a simple block copy.  They seem to match, with just the channel and source/destination being different as expected.

    When the code runs, it still crashes after the EDMA_startTransfer statement.  The Debug window shows:

    So still not working.

    Best regards,

    Alan

  • I had mentioned about address translation before, but your code does not show it, can you explain why you didn't do it? Didn't you see it in the block copy code you referenced?

  • Hello Piyush,

    The MmwDemo_edmaBlockCopy() function that I used as an example has in the header,

        *      Performs simple block copy using EDMA. Used for the purpose of copying
        *      linker table for L3 to L1PSRAM copy. memcpy cannot be used because there is
        *      no data bus access to L1PSRAM.

    I was not trying to copy from the L1 or L3, but rather just from one array in the code to another.  The expectation from the description above was that the translation is needed for the L1/3 because of the data bus access, and that an array within the code should not have that issue.

    I added the translation, and the transfer now works.  Thanks!

    Please note that this is our first exposure to the IWR1443 chipset and a SOC system.  It is a very different environment from the STM32 chips that we have been using for over a decade.  I have asked several times whether training is available for the IWR1443 or at least that chipset family, but I was informed that there was none.  I was told that this support forum was the only way to get help.  That is unfortunate as I think the result is often frustration for both the people asking questions and those providing answers.

    I do very much appreciate your persistence and patience in helping me.

    Best regards,

    Alan


  • Thank you for using our products and your patience during development. I understand your pain of transition from a product family from another company that you have been using for a while to our product, we can expect more pain going forward but hopefully we can do our part to help ease that. If you haven't already, I would suggest to spend a good amount of time looking at the TRM at a somewhat higher level [chip arch etc] and also the SDK user guide and module documentation [start from top level docs/ directory].

    Regarding address translation, the EDMA view of addresses is different from the CPUs (R4F/C674X) view of the address hence translation is required. You can see this in the device TRM if you look at the "memory map" section where different views are presented and you can see the TCM (local) addresses in different views. To make it easy we have provided the APIs in soc driver so user does not have to worry about this, so I would suggest to always call the translation APIs before passing the addresses to the EDMA driver. We didn't do translation inside the driver itself as we wanted to keep it purer in terms of programming just the EDMA IP as is.