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.

MSPM0G3507: I2C with DMA high current

Part Number: MSPM0G3507
Other Parts Discussed in Thread: SYSCONFIG,

Hello!

We were previously using I2C in controller mode with FIFO to periodically communicate with another chip on our board and STANDBY1 mode while there is no communication required. Rough format of a typical I2C exchange is below, periodicity of exchange 100ms and duration of exchange including SW overhead <1ms. The MCU is in sleep for the remaining 99ms. Average current consumption of our entire board ~250uA.

send write address + send 2 bytes of register ID that we want to access + restart + send read address + read 8 bytes of data.

But now we want to switch to receive 10 bytes of data at a time. I2C FIFO only goes up to 8 bytes so we switched to DMA for the receive only. Configured the I2C+DMA as below and it works correctly, we get the expected 10 bytes of data:

  • I2C interrupt on DMA event 2
  • I2c RX FIFO level >= 1 byte
  • DMA event 2 trigger = controller RX FIFO trigger
  • Fixed addr to block addr. source is I2C1.MASTER.MRXDATA, destination is some buffer in RAM
  • Source & destination length = byte
  • transfer size = 10
  • DMA transfer mode single

As I said the I2C communication works as expected. But the current consumption jumped from 250uA to ~1.8mA. I confirmed by toggling a pin around the WFI instruction that MCU is indeed in sleep for the ~99ms where it's not doing any I2C exchange. Normally I just call DL_I2C_disableController() instead of fully disabling the I2C peripheral with DL_I2C_disablePower() before sleep, but I have tried that too and there's no change in the consumption.

I'm setting DMAEN once before each 10 byte transfer. When the DMA transfer is finished I've confirmed that:

  • DMAEN is set automatically back to 0
  • I2C interrupt is hit with DL_I2C_IIDX_CONTROLLER_EVENT2_DMA_DONE
  • No other I2C interrupt is hit

I suspect something in the DMA is keeping parts of the CPU awake, hence the high current consumption. Confirmed if I just comment the DL_DMA_enableChannel() call that the power consumption drops to ~0.2mA. But I can't find a way to directly disable/reset the DMA so I'm stuck.

Please help us since this current consumption is way outside of our application's budget.

  • Hi Florin,

    It is little strange and maybe you can take some try, if there is any feedback, please let me aware.

    Can you try manually disable DMA channel before entering low power mode:

    void DL_DMA_disableChannel(DMA_Regs *dma, uint8_t channelNum).

    If not work, please take a try that before enter low power mode, reset the dma configuration manually, including:

    and source & destination address; transferSize.

    B.R.

    Sal

  • Hello Sal,

    I've added the following code before sleep:

    static const DL_DMA_Config gDMA_I2cConfig = {
        .transferMode   = DL_DMA_SINGLE_TRANSFER_MODE,
        .extendedMode   = DL_DMA_NORMAL_MODE,
        .destIncrement  = DL_DMA_ADDR_INCREMENT,
        .srcIncrement   = DL_DMA_ADDR_UNCHANGED,
        .destWidth      = DL_DMA_WIDTH_BYTE,
        .srcWidth       = DL_DMA_WIDTH_BYTE,
        .trigger        = DMA_I2C1_RX_TRIG,
        .triggerType    = DL_DMA_TRIGGER_TYPE_EXTERNAL,
    };
    DL_DMA_disableChannel(DMA, DMA_I2c_CHAN_ID);
    DL_DMA_initChannel(DMA, DMA_I2c_CHAN_ID , (DL_DMA_Config *) &gDMA_I2cConfig);
    DL_DMA_setDestAddr(DMA, DMA_I2c_CHAN_ID, 0);
    DL_DMA_setSrcAddr(DMA, DMA_I2c_CHAN_ID, 0);
    DL_DMA_setTransferSize(DMA, DMA_I2c_CHAN_ID, 0);

    There was no change in behavior. It was unclear if you want me to try with to reinit the DMA with my configuration for I2C or with your configuration for ADC. I've tried both and they both work in the same way. I've tried calling DL_DMA_disableChannel() at both the begining and the end of the block of code above. I've also tried playing with the source/destination address/transfer size, putting them one by one to non-0.

    No change in any of my attempts.

  • Hi Florin,

    Sorry for the description details is misleading.

    Please try below before enter the low power mode:

    static const DL_DMA_Config gDMA_I2cConfig = {
        .transferMode   = DL_DMA_SINGLE_TRANSFER_MODE,
        .extendedMode   = DL_DMA_NORMAL_MODE,
        .destIncrement  = DL_DMA_ADDR_UNCHANGED,
        .srcIncrement   = DL_DMA_ADDR_UNCHANGED,
        .destWidth      = DL_DMA_WIDTH_BYTE,
        .srcWidth       = DL_DMA_WIDTH_BYTE,
        .trigger        = DMA_SOFTWARE_TRIG,
        .triggerType    = DL_DMA_TRIGGER_TYPE_EXTERNAL,
    };
    DL_DMA_initChannel(DMA, DMA_I2c_CHAN_ID , (DL_DMA_Config *) &gDMA_I2cConfig);
    DL_DMA_setDestAddr(DMA, DMA_I2c_CHAN_ID, 0);
    DL_DMA_setSrcAddr(DMA, DMA_I2c_CHAN_ID, 0);
    DL_DMA_setTransferSize(DMA, DMA_I2c_CHAN_ID, 0);
    DL_DMA_disableChannel(DMA, DMA_I2c_CHAN_ID);
    
    /* Here I want to test whether set the DMA register as default reset value and then the power consumption will be lower */

    Here I want to test whether set the DMA register as default reset value and then the power consumption will be lower.

    I have some other suggestions - please reset I2C before you enter the low power mode and check whether it help.

    /* reset I2C and then enter low power mode */
    DL_I2C_reset(I2C_0_INST);

    Looking forward to your feedback.

    B.R.

    Sal

  • Hello Sal,

    I've tried what you suggested, no change. Not even with DL_I2C_reset(). Tried even more by calling DL_I2C_disablePower(), no change.

    We had a related issue with DMA for UART in the past, but this UART was not running while I encountered this I2C issue. DMA would stay on while MCU is in sleep, increasing the current consumption very similarly to this issue. What I found worked for UART was to call DL_UART_disableDMATransmitEvent() before sleep. Also difference is for UART we were fully disabling the peripheral with DL_UART_Main_disablePower(), while for I2C we only disable the controller with DL_I2C_disableController().

    But for I2C calling the similar interface DL_I2C_clearDMAEvent() does not help as it does for UART.

  • Hi Florin,

    Thanks for the feedback.

    I will do test as for your description. The feedback maytake some time. Thanks for your patience.

    If you have any progress, please sync with me.

    B.R.

    Sal

  • Hi Florin,

    To help confirm this issue, could you please upload your SysConfig file to below link of TI Drive? If possible, also upload the C code related to I2C+DMA.

    https://tidrive.ext.ti.com/u/q2prWMhqa0q5amtN/df6adfdc-9a81-42bb-8917-568be50a1ad9?l      Access Code:v5Fk3i=Y

    Please let me know once you finish this. Thanks!

    Best regards,

    Pickle

  • https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/908/i2c_5F00_controller_5F00_DMA_5F00_rw_5F00_multibyte_5F00_fifo_5F00_interrupts_5F00_LP_5F00_MSPM0G3507_5F00_nortos_5F00_ticlang.7z

    Hi Florin,

    Please see the attached project for I2C+DMA example, the total current is about 40uA on my side, please refer to this demo with you project.

    Best regards,

    Pickle

  • Hello Pickle,

    Thank you for coming back to me with your demo project. I was unable to provide the requested code earlier. I just tested it and it indeed works as expected, but when putting the same lines into my application it didn't work anymore, meaning it was still at ~1.8mA consumption. I tried gradually adding parts of my application to your demo project to see what breaks it, and I was finally able to track down my issue.

    It turns out I also have configured another DMA channel for a UART that is only used for some test mode. So the UART peripheral itself was disabled and had no issue with current consumption that way until I switched the I2C to DMA. What happens is when the I2C triggers the DMA, the DMA is kept "awake" afterwards because of the other DMA channel connected to UART, even though the UART peripheral was disabled.

    So what I needed to do to fix my situation was to call DL_UART_disableDMATransmitEvent() on the UART peripheral to "disable" its DMA channel (while the UART is enabled, otherwise it won't work), and then it was enough to call DL_I2C_disableController(). Didn't even need DL_I2C_disableDMAEvent(). Result is I2C with DMA is working and I am back to my usual ~200uA consumption.

    So to sum up it looks like when you are triggering a DMA channel actually the DMA remains on even if the trigger for the channel you used is disabled, until all the other triggers for the other DMA channels are also disabled. Is it not actually a problem of the DMA (since I didn't need to call DL_I2C_disableDMAEvent()), but rather of the UART or UART connection to DMA? 

    Regardless, is this documented somewhere? Could some hint for this be added to the TRM/errata if not? Cause to me this is really not something I would expect and someone else would probably fall into this trap too.

    Thank you,

    Florin

  • Hi Florin,

    I got you, and I'll check more as you said, then I'll report this issue to our related team.

    Thanks for your deep research and suggestions!

    Best regards,

    Pickle