i.MXRT1xxx LPI2C single channel DMA: How to perform multiple send/receive sequence

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MXRT1xxx LPI2C single channel DMA: How to perform multiple send/receive sequence

1,812 Views
alonbl
Contributor III
Hello,
 
I am trying to perform a sequence I2C of send/receive requests using LPI2C DMA on iMX-RT117x, the issue at hand seems to be related to all MCUs that have LPI2C with single channel DMA.
 
Unlike previous generation MCUs, the RT1xxx LPI2C peripheral has a single DMA channel, I could not find an example of how to use it properly for multiple sequences of data receive.
 
Looking at the SDK code, the switch between TX to RX is performed using a specially crafted TCD that writes "TX disable" into the MDER register, it is commented explicitly in code:
 
            /* For shared rx/tx DMA requests, when there are commands, create a software TCD of
               enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
               and create another software TCD of transfering data and chain it onto the last TCD.
               Notice that in this situation assume tx/rx uses same channel */
It looks like the SDK is designed to perform a single send/receive transaction with auto stop injection, then stop, while our challenge at hand is to be able to perform a sequence of send/receive.
 
I noticed that once the TX in the MDER is disabled, the peripheral cannot be recovered for the TX side, a specially crafted TCD to revert the MDER setting is not pulled from memory and sequence stops.
Without disabling the TX in the MDER I do not see any data received.
 
Question#1: Why should the TX be disabled in MDER if the command within the FIFO is receive?
 
In previous generations one could open two DMA channels, one for send and one for receive and per the examples out there, once the receive command in FIFO the receive channel got the information while send continued after.
 
I would guess, this behavior could have been implemented using a single channel DMA as well, as once the receive command is in FIFO the peripheral could have internally temporary disable the DMA TX while resuming after the receive command was executed.
 
Please review the following sequence:
 
  1. Write commands to MTDR, sequence:
    1. START(slave, write)
    2. DATA(1)
    3. START(slave, read)
    4. RECEIVE(4)
  2. Write (RX enable, TX disable) into MDER
  3. Read 4 bytes from MRDR
  4. Write (TX enable, RX enable) into MDER
     
  5. Write commands to MTDR, sequence + trigger DMA interrupt to finalize:
    1. STOP
    2. Empty
 
In this sequence TCD#4 is not executed, it looks like the TX disable in MDER causes the device to stop pulling data from DMA.
 
If the TCD#2 is removed, then the TCD#3 is executed but not valid data is received.
 
If we modify TCD#3 [receive] to trigger DMA interrupt, and in the ISR modify MDER to trigger TX, then sequence is resumed and completed successfully, please refer to the following sequence:
 
  1. Write commands to MTDR, sequence:
    1. START(slave, write)
    2. DATA(1)
    3. START(slave, read)
    4. RECEIVE(4)
  2. Write (RX enable, TX disable) into MDER
  3. Read 4 bytes from MRDR + trigger DMA interrupt which writes TX enable into MDER
  4. Write commands to MTDR, sequence + trigger DMA interrupt to finalize:
    1. STOP
    2. Empty

I am sure that it is possible to perform multiple send/receive in the advanced RT1xxx series, similar to what was possible in the previous generation.
 
Questions:
  1. Is there any available documentation on how to perform multiple send/receive sequences using DMA and LPI2C in RT1xxx?
  2. Why should the TX in MDER must be disabled to receive data using DMA?
  3. If it is required to disable the TX in MDER, how can TX re-enable it without using the CPU?
 
Thank you for your help,
Labels (1)
0 Kudos
Reply
5 Replies

1,745 Views
Habib_MS
NXP Employee
NXP Employee

Hello @alonbl,
Sorry for taking a while to get back to you.  Answering your questions:

Q1: Is there any available documentation on how to perform multiple send/receive sequences using iDMA and LPI2C in RT1xxx?

Does not exist a specific documentation that talks about this. However, you can find more information in the chapter 69 called "Low Power Inter-Integrated Circuit (LPI2C)" in the RM.

Q2: Why should the TX in MDER must be disabled to receive data using DMA?

In order to support you better, can you provide me the SDK (version 2.16) code where the TX is disabled in the MDER register?

Q3: If it is required to disable the TX in MDER, how can TX re-enable it without using the CPU?

Since the MDER is a configuration register it can only be written via the CPU

BR,
Habib

0 Kudos
Reply

1,729 Views
alonbl
Contributor III

Hello @Habib_MS ,

 

Thank you for reviewing the question.

 

Q1: I have reviewed the RM in deep, had I found a solution in there or online, I would not have posted this thread

 

Q2: Please refer to the following block in the SDK code:

https://github.com/nxp-mcuxpresso/mcux-sdk/blob/main/drivers/lpi2c/fsl_lpi2c_edma.c#L386

/* For shared rx/tx DMA requests, when there are commands, create a software TCD of
enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
and create another software TCD of transfering data and chain it onto the last TCD.
Notice that in this situation assume tx/rx uses same channel */
#if defined FSL_EDMA_DRIVER_EDMA4 && FSL_EDMA_DRIVER_EDMA4
EDMA_TcdResetExt(handle->rx->base, tcd);
EDMA_TcdSetTransferConfigExt(handle->rx->base, tcd, &transferConfig, NULL);
EDMA_TcdEnableInterruptsExt(handle->rx->base, tcd, (uint32_t)kEDMA_MajorInterruptEnable);
#else
EDMA_TcdReset(tcd);
EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
#endif

transferConfig.srcAddr = (uint32_t)&lpi2c_edma_RecSetting;
transferConfig.destAddr = (uint32_t) & (base->MDER);
transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
transferConfig.srcOffset = 0;
transferConfig.destOffset = (int16_t)sizeof(uint8_t);
transferConfig.minorLoopBytes = sizeof(uint8_t);
transferConfig.majorLoopCounts = 1;

edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_TCD_SIZE_MASK));
#if defined FSL_EDMA_DRIVER_EDMA4 && FSL_EDMA_DRIVER_EDMA4
EDMA_TcdResetExt(handle->rx->base, tcdSetRxClearTxDMA);
EDMA_TcdSetTransferConfigExt(handle->rx->base, tcdSetRxClearTxDMA, &transferConfig, tcd);
#else
EDMA_TcdReset(tcdSetRxClearTxDMA);
EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
#endif
linkTcd = tcdSetRxClearTxDMA;

 

Q3: Since the MDER is a configuration register it can only be written via the CPU

Understanding the platform better than I, maybe you can suggest creative way to solve this.

I thought about a trigger when DMA done via XBAR to trigger DMA to reset the `MDER` or have a chained DMA that is memory-to-memory, or perform TCD that triggers DMA start to move 1 into `MDER`.

 

Or in short, I would like to think that NXP LPI2C allows somehow to perform multiple I2C commands without CPU involvement in their advanced MCUs as it was supported by the previous generation.

 

Regards,
Alon

0 Kudos
Reply

1,699 Views
Habib_MS
NXP Employee
NXP Employee

Hello @alonbl,
Unfortunately, SDK (version 2.16) only provides the solution to disable Tx in the MDER register. Also, there is not existing documentation that specifically talks about this.

Creating a solution to increase performance must be by custom implementation, however I can suggest a solution. I understand that you are currently using the RT1170, you can use the cortex M4 to make this process or increase the core clock in order to execute instructions faster.

Also, you mentioned that the peripheral LPI2C only can use a single DMA channel, however, SDK(version 2.16) offers an alternative to use different TX and RX DMA channel using the next macro:

Habib_MS_0-1728924279280.png

BR
Habib.

0 Kudos
Reply

1,696 Views
alonbl
Contributor III

Hello @Habib_MS ,

Thank you for trying to assist, however, I would like to note that I am looking for someone that is deeply familiar with the architecture to assist me with this fundamental question of how to perform multiple I2C read/write transactions using DMA.

I am aware that there is no explicit documentation of how to establish this, or why the SDK implemented the way it is. Otherwise, I would have probably found it already and act upon it. This is why I seek help in NXP forum to reach out NXP professionals.

The issue is not performance (BTW: we use 1171 without cm4), the issue is how to use the hardware correctly, and what the engineer thought when they disabled the multi-channel DMA for the LPI2C, as in the Kinetis series it was supported, I would like to guess a solution exists and that it is not documented properly.

The architecture itself is a single DMA channel, it is not a software to decide how many DMA channels a peripheral has, you can also review that this is hard-coded using a simple `git grep` command:

devices/MIMXRT1176/MIMXRT1176_cm4_features.h:#define FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(x) (0)
devices/MIMXRT1176/MIMXRT1176_cm7_features.h:#define FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(x) (0)

As you can see there is no alternative to use multiple channels in this architecture, it is also clearly abstracted in the NXP config tool.

I am looking forward to deeply discuss this issue and find creative solutions, maybe disabling the MDER is incorrect and there is an alternative, I am unsure why it is done by the SDK. Can you please consult with your peers to understand exactly what the sequence is?

Regards,
Alon

0 Kudos
Reply

1,664 Views
Habib_MS
NXP Employee
NXP Employee

Hello again @alonbl,

Corroborating the information that you provided me, LPI2C in the RT1176 only has one DMA channel, also, unfortunately the SDK team does not provide related information regarding the propose of their changes.
In this app note explains how optimize the i.MX RT series in the chapter 4 called "How to improve performance", that could be helpful.

Also, it is important to take in consideration that each jump into functions takes time, and in order to optimize the performance you can use only registers and avoid using jumps into functions.
Sorry for the inconvenience this may cause.
BR
Habib.

0 Kudos
Reply