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.

LAUNCHXL-CC1352R1: Timer triggered DMA Scatter-Gather stops running upon debugger detaching

Part Number: LAUNCHXL-CC1352R1


Hi all,
this is my first post and I hope someone can help me to solve this very strange problem I'm struggling to for about 2 months now.
I'm trying to control some data exchange via GPIOs without the use of bit-banging (it's a custom protocol I'm working on for my customer, which is not using any of standard buses like I2C, SPI, UART and so on) more or less like a "multi" onewire protocol.
To achieve this, I'm developing a custom driver based on driverlib, since no high level driver can be used for the purpose, basically I'd like to use the Scatter-Gather DMA transfer by creating a task list of DMA requests each driving directly a separate GPIO by writing '1' or '0' directly on the GPIO data register.
To avoid CPU usage (I have very strict constraints related to power management), I want to drive the DMA by using a timer, in this way, using the Peripheral Scatter-Gather mode, I can use the timeout interrupt of the timer to trigger each of the DMA tasks and control the GPIO in sync with the timer without the need to process anything using the CPU or use software delays to respect the protocol timings.
What I want to achieve is control the communication by simply starting the timer which triggers the DMA requests one task at a time (so it can drive a single GPIO high or low according to the protocol) and terminate it by stopping the timer without any CPU intervention (so an entire message can be sent enabling and disabling the timer within a specific amount of time).
As reference for my code I used this document: "CC13x2, CC26x2 SimpleLink Wireless MCU Technical Reference Manual", where the Peripheral Scatter-Gather DMA is described in par. 14.3.6.6 and the timer triggered DMA request feature is described in par. 15.4.5. and as reference code for the configuration of timer and DMA I used also the ADCBufCC26X2 driver which uses a ping-pong based mode DMA management and the timer triggers the ADC instead of directly the DMA.
I'm using GPTimer 0 configured as 16bit continuous upcounting timer and channel 9 of DMA (which is triggered by the timeout event of GPT0).
Everything seems to work quite well, except that I can see the data flow only when I have the firmware running with the debugger attached (I use a Launchpad CC1352R1 eval board), while if I run it without debugging the DMA stops working (same firmware built with debug profile no optimizations).
I did some tests using also a logic analyzer to display the status of the signals and adding some other GPIOs used as test signals to collect information regarding the state of the timer and if the interrupts are triggered correctly. I also have a UART console I can use to access registers in order to set/get values of registers to see what happens when I'm not attached with the debugger.
I discovered the main difference is the REQDONE state of the DMA, precisely: when I activate the timer and the DMA starts processing the Scatter-Gather task list, if I have the firmware running with the debugger attached, the REQDONE NEVER occurs and everything works flawlessly; on the contrary if I simply press the "Stop" button in the IDE or if I run the firmware directly without debugger attached, after the first task or at most the second one, the REQDONE is raised and the DMA stops processing the rest of the tasks stopping the sequence.
My question is: is this an expected behavior? Is there something different I need to configure to avoid such event to occur when I run the firmware without the debugger?
For NDA reasons (I'm a consultant for my customer) I cannot provide full source code of the project, but if necessary I can copy/paste here some parts related strictly to the configuration of DMA and Timer; anyway to provide a sample of the expected outcome I attach two screenshots of my logic analyzer output, the first with the correct behavior (2 GPIOs and the timer toggling trace as reference) and the bad behavior (I registered a HWI/SWI couple attached to the timer interrupt and in the SWI I simply reenable the DMA channel if the REQDONE flag raises, but this creates gaps in the protocol because the HWI is triggered randomly so I loose some DMA transactions).
Sorry for the long text, I wanted to provide as many information as possible, thank you very much in advance for any suggestion.
Dario

  • Hi Dario

    If you have code running as expected with the debugger connected, but not stand-alone, the problem is most likely related to power modes.

    When running with the debugger connected, you are preventing the device from entering standby.

    When running stand-alone, it might enter standby, and you can have issues because you are not handling powering of the different domains in a proper manner.

    To verify if this is the problem, you can try to disallow standby in your code (Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY);)

    If it works as it should when the debugger is disconnected, you know that the issue is related to  power modes.

    Siri

  • Hi Siri,

    thank you for your reply, I already thought about the power management during my investigations and setup the Power constraint as you suggested.
    Just to give a more clear view: I made the driver using a structure similar to the driverlib, with a set of *Init, *Open, *Close, *Start and *Stop functions and I have the Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY) call in my *Start function (which starts the timer and therefore the DMA) and a Power_releaseConstraint(PowerCC26XX_DISALLOW_STANDBY) call in my *Stop function.

    Moreover I also tried to set a dependency on the involved peripherals when I use the driver so I added:
        Power_setDependency(PowerCC26XX_PERIPH_UDMA);
        Power_setDependency(PowerCC26XX_PERIPH_GPT0);
    in my *Open function and:
        Power_releaseDependency(PowerCC26XX_PERIPH_UDMA);
        Power_releaseDependency(PowerCC26XX_PERIPH_GPT0);
    in my *Close function, but those functions are not involved in the process: basically the *Open is called during the startup of my thread (I use TI-RTOS in my project) and *Close is not called during my tests (I can start and stop the transmission via UART console by simply call the *Start and *Stop functions, so I don't close the driver).

    Is there some other check I can do to verify any problem with the power management (i.e. some registers configuration) just to exclude the behavior is due to the  standby state of the CPU?

    Thank you very much, in advance,
    Dario


  • Unfortunately I am not sure how you could debug this in a best possible way.

    Normally we only support the use of our drivers, so when you stop using them and implement drivers on your own, it is hard for us to advice on what is going on.

    If you just do Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY) in the beginning of your code (never release it again), do you still have issues when not running with the debugger? You just said what you had tried, but you did not say what the results were.

    Other than that, I guess I would recommend to simplify your code as much as possible while debugging. I guess you have a lot of other stuff going on in your code other than the DMA stuff, so make a demo example that is a simple as possible. Maybe there are some other driver etc. that are messing things up. 

    You could also try looking at the current profile using energy trace to see if that can give you any hints on power modes etc.

    I am sorry that I could not be of better help.

    Siri

  • Hi Siri,

    thank you for your reply, I know you don't provide support for other than your drivers, in this case my problem is there isn't any driver that can fulfill my current needs.

    Anyway, I confirm using Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY) in the beginning of my code doesn't solve the problem (I also disabled the release of the constraint to be double sure about this).

    I didn't try to profile using energy trace yet since I didn't have time to work on it in the last days, I'll try and report back, thank you for the suggestion.

    Just a last question: if I prepare a simple example using my driver can I post here the project to get some additional help or is something you don't/can't consider?

    Thank you again for the support,

    Dario

  • Hi Dario

    If you for example uses the empty example from our latest SDK and make a small demo code that we can run on our LP to reproduce the problem, we will take a look at it, but I cannot promise that we will be able to solve it. 

    However, trying to make such a small example might probably be good for you as well when debugging your code, so it will not be a waste of time in any case.

    Siri

  • Hi Siri,

    thank you very much for your reply and support.

    In a few days I'll try to prepare such example with as few code as possible (even because of my NDA with the customer).

    Thank you again,

    Dario

  • Hi Siri,

    sorry for the late reply but I had some task with higher priority and I couldn't prepare the code.

    Anyway I think I found the problem even though I cannot explain 100% why.

    Basically it seems related to how I configured the task list for the Scatter-Gather DMA request, I copy here for more clarity:

    static uint8_t outLevelHigh = 1;
    static uint8_t outLevelLow = 0;
    
    /* DMA Scatter-Gather tasks table */
    tDMAControlTable txTimerDmaTableEntry[] =
    {
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT1), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
    
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelHigh, UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        uDMATaskStructEntry(1, UDMA_SIZE_8, UDMA_SRC_INC_NONE, &outLevelLow , UDMA_DST_INC_NONE, (void *)(GPIO_BASE + CONFIG_GPIO_OUT2), UDMA_ARB_1, UDMA_MODE_MEM_SCATTER_GATHER),
    };
    

    The idea is basically to use the DMA peripheral to directly drive the state of GPIOs (actually it's more complex but due to NDA I cannot copy the entire code, sorry), so the source pointer is a variable which contains '0' or '1' according to the state to drive and the destination is the GPIO data register.
    Every state is driven by a task of the Scatter-Gather executed at each toggling of the timer which generates the DMA requests.
    In my original code the outLevelHigh and outLevelLow variables were declared as "static const uint8_t" and this caused the issue.

    My assumption is the "const" qualifier links the variable in flash instead of RAM, so probably the DMA wasn't able to access the pointer correctly, what I don't understand is why it worked flawlessly with the debugger attached, while it hanged upon detaching the debugger (does the DMA access memory in different ways when the CPU is debugging or not?).

    Anyway the suggestion to provide a sample code was useful for the solution, because in my original project I didn't have any warning from the compiler, while in the project I was preparing for you the compiler warned about this with a "initialization discards 'const' qualifier from pointer target type" message so I tried to remove the const qualifier and everything worked correctly.

    Thank you very much for the support.

    Best Regards,

    Dario