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.

TMS320F28377D: DMA not working after adding some variables

Part Number: TMS320F28377D

Hello Forum,

I have a strange behaviour. My DMA fetches the ADC results into a structure. After several tries, I managed that this is working (destination in global share RAM, writing to the DMA config registers with HWREGH instead of HWREG, checking timing with DMA ready interrupts and setting HW pins). After removing my debug code, it stops working. Content is written via DMA but the calculated values from these measurements are invalid.

Finally, I get the following behaviour. By removing or adding the declaration of one global variable above my DMA configuration code the code will work or not. I do not touch this variable in the code, I declare this only. I checked the .map file and this single variable changes the arrangement significantly. But the destination structure is always in global share RAM. I updated the compiler from 20.2.5 to 21.6.0 but this does not help. The only difference is that with one compiler version it works with this single variable definition and with the other version vice versa.

I run this on CPU1. CPU2 is in an idle loop and is waiting for future implementations. CPU2 global share Ram is defined in the .cmd file (same region) but this is not used as written in the .map file of CPU2.

Any ideas how to solve this issue?

Thanks, Martin

  • Martin,
    Would it be possible to share the values you expect to be written vs the values that are written as well as the good/bad map files?  Since the DMA is writing something into the RAM then I think all the access permissions are OK.  If you can share the DMA related C code that would be helpful as well.

    Best,

    Matthew

  • Hello,

    Thank you for your answer. As I want to put these thinks together I was not able to reproduce this behaviour. My last situation is this. After flashing a software version which is not working I make a power cycle and then the software is working. I use Code Composer Studio and a XDS100 for flashing.

    The software is for a PMSM drive. I use three ePWMs for controlling the hardware and the next ePWM module for triggering the ADC six times per PWM cycle. The four modules are synced. Everything is working well if I fetch the ADC results and write the next ADC SOC value in the ADC ready interrupt. Now I want to use the DMA for fetching the ADC results and a second channel for writing the ADC SOC values, but this in a second step.

    Because of the volatile values which are fetched by the DMA from the ADC it is not possible for me to observe the values in a good or bad situation. I can only evaluate the result of the calculation which is done with these ADC values.

    Here is my DMA init. SYS_SW_DmaInterrupt is disabled. I used this for debugging.

    void DMA_init(void)
    {
    #if SYS_SW_DmaInterrupt == ENABLE
        Interrupt_register(INT_DMA_CH1, &DMA_ready_isr);
        Interrupt_enable(INT_DMA_CH1);
    #endif
        // Perform a hard reset on DMA
        DMA_initController();
    
        // Allow DMA to run free on emulation suspend
        DMA_setEmulationMode(DMA_EMULATION_FREE_RUN);
    
        // DMA channel 1 set up for ADCA
        DMA_configAddresses(DMA_CH1_BASE, (uint16_t *)&ADC_SocResult[0],
                            (uint16_t *)ADCARESULT_BASE);
    
        // DMA channel 1 Burst and Transfer Config
        DMA_configBurst(DMA_CH1_BASE, 6, 2, 2);
        DMA_configTransfer(DMA_CH1_BASE, 6, -4, 12);
        DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_ADCA1,
                       (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE |
                        DMA_CFG_SIZE_32BIT));
    
        DMA_enableTrigger(DMA_CH1_BASE);
    
    #if SYS_SW_DmaInterrupt == ENABLE
        DMA_disableOverrunInterrupt(DMA_CH1_BASE);
        DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_END);
        DMA_enableInterrupt(DMA_CH1_BASE);
    
        SYS_IER_IDLE |= INTERRUPT_CPU_INT7;
        SYS_IER_TSK |= INTERRUPT_CPU_INT7;
        SYS_IER_FAST |= INTERRUPT_CPU_INT7;
        SYS_IER_SLOW |= INTERRUPT_CPU_INT7;
    #endif
    }
    

    At the very beginning of an ePWM zero interrupt I exchange the destination of the DMA and write the ADC SOC for the first SOC. The following SOC values are written by an ADC ready interrupt.

    //unsigned int Adc_DmaStatus, Adc_DmaBurstCnt;//, Adc_DmaTransferCnt;
    SYS_AdcSocResult_t* ADC_WriteFirstSocVal(unsigned int SocVal, int dIImotFiltTime)
    {
        PWM_WriteSocVal(SocVal);
        ADC_SocCnt = 0;
    
    //    Adc_DmaStatus = HWREGH(DMA_CH1_BASE + DMA_O_CONTROL);
        EALLOW;
        HWREGH(DMA_CH1_BASE + DMA_O_CONTROL) = DMA_CONTROL_SOFTRESET;
        NOP;
        EDIS;
    
        ADC_SocResultFinished = ADC_SocResult_p[ADC_SocResultPointerCnt];
        ADC_SocResultPointerCnt = ++ADC_SocResultPointerCnt & 0x0001;
        ADC_SocResultWorking = ADC_SocResult_p[ADC_SocResultPointerCnt];
    
        DMA_configDestAddress(DMA_CH1_BASE, ADC_SocResultWorking);
        EALLOW;
        HWREGH(DMA_CH1_BASE + DMA_O_TRANSFER_SIZE) = ADC_SocResultWorking->AdcSoc.SocNbr;
        EDIS;
        DMA_startChannel(DMA_CH1_BASE);
    
        ADC_SocResultFinished->AdcResult[0].ADCRESULT[ADC_ResultNbr_U_DC] = ADC_readResult(ADCDRESULT_BASE, AdcSocResultNbr_U_DC);
        ADC_SocResultFinished->AdcResult[0].ADCRESULT[ADC_ResultNbr_T_BOARD] = ADC_readResult(ADCDRESULT_BASE, AdcSocResultNbr_T_BOARD);
    
        ADC_dIImotFiltTime = dIImotFiltTime;
    
        ADC_AdcStatForSlow.bit.NewValuesAvailable = 1;
    
        return ADC_SocResultFinished;
    }
    

    The variables Adc_DmaStatus, Adc_DmaBurstCnt changed working / not working. But this was at the time before I cycled the power. Do you need the map files any more?

    Best,

    Martin

  • Martin,

    If things are working, then I don't need to see the map file.  Perhaps there was a value that got changed that was not re-initialized in the previous code?  A power cycle will cause a RAM_init on all the RAMs writing them to 0x0000.  Just a thought.

    Best,

    Matthew

  • Matthew,

    on the one hand I am happy that the code is working. On the other hand I am afraid that there is a timing issue. Or a RAM init problem as you thought.

    The main problem is that I am not able to debug the code with CCS if I need to power cycle the CPU for the DMA issue. After power cycling I lose the target connection? Is there a difference between a start up after a power cycle and a start up in a debugging session? Besides the debugger break point in main?

    Best,

    Martin

  • Martin,

    When you have an active debug session CCS will "take care" of some of the actions normally reserved for the bootloader.  There is a setting in CCS to "go to main" after a file load vs run through the bootloader.  This is also the action when you select to "Restart" from the Run menu.

    To emulate what happens during normal boot, you need to do a Run->Reset, then also under the scripts select the Flash EMU Boot mode.  This will force the debugger and boot ROM to mimic what would normally happen when the device is reset if the debugger was not present.

    Based on what you have mentioned, it seems like this should pass correctly, but please try it out and let me know.  Assuming this works, I'd need to better understand what actions are not happening when we do a "restart" type action.

    Best,

    Matthew

  • Matthew,

    thank you for your support. Now I implemented the second channel. The first fetches the ADC results, the second channel writes the CMP value to trigger the SOC in the same PWM cycle. I got this going to work on the eval board after several tries. But then after pressing the reset button on the board the timing was different. Now everything is working well during the debugging session. Restart from the Run menu, the script Flash EMU Boot mode, all this works. But if I press the reset button or do a hard power cycle the timing is different.

    I have 6 SOCs in one PWM cylce. This results in a DMA transfer number of 6 for the ADC results.

    I have 6 SOCs but I have 7 CMP writes because I set the CMP to 0xFFFF after the 6th SOC to prevent an additional SOC. So I have a DMA transfer number of 7. The first DMA channel 2 trigger is done via software.

    If the software is not running good I get the ADC fetch DMA finish interrupt after 5 SOC events and the CMP write DMA finish after the 6th SOC. I see all 6 SOCs. In a good condition I receive both interrupts after the 6th SOC event. First the CMP then the ADC, as expected.

    Just to clarify. A DMA_CONTROL_SOFTRESET resets all burst and transfer counters? So if I set 6 transfers but only 5 occurs everything is good for the next pwm cycle after a soft reset at the very beginning of the pwm cylce?

    Best,

    Martin

  • Martin,

    I'll answer the last question first, you are correct that this will reset all the burst and transfer counters, if this bit is written while a DMA read/write is in progress that will complete before this bit takes effect.

    Can you elaborate on the trigger you are using for the ADC complete to the DMA for the ADC result read?  I suppose what I'm looking for is how the ADC INT is configured that goes to the DMA CH to start the transfer, is it the end of conversion of SOC5 or early INT for SOC6 etc. 

    Since the CMP is on an independent channel I don't think its timing should change run to run.  If somehow the ADC is not finished when another SOC comes in, it will pend and continue, but perhaps that timing is changing a bit run to run.

    Let me know on the above and we can go from there.

    Best,
    Matthew

  • Matthew,

    the solution is only one bit - arghhh. If I do a

    HWREGH(DMA_CH1_BASE + DMA_O_CONTROL) = DMA_CONTROL_SOFTRESET | DMA_CONTROL_PERINTCLR;

    instead of a simple SOFTRESET it works. My explanation is that the SOCs and therefore the EOCs are present but the DMA is not fetching the results in certain situations. So after enabling the DMA (set the run bit) this pending transfer is executed immediately and causes an "additional" trigger of the DMA. And so the sequence is destructed. Why this is depending from the amount of global variables is not clear for me. That this is in a connection with the boot or debug process is conceivable but a little bit strange.

    I keep in mind that I have to set the PERINTCLR bit if I want to reset the DMA...

    Thank you for your guidance!

    Best,

    Martin

  • Martin,

    Thanks for giving us the update on the cause, and glad the understanding is there.  Let us know if we can be of more assistance.

    Best,
    Matthew