Cx3: switching the i2c mode (Dma/register transfer)

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
CoCo_4528381
Level 1
Level 1
First like given

Hello everyone!

For my project I need to connect the cx3 (through i2c) with two slaves: a camera and another sensor.
During the initialization of the slaves I'm using the i2c configured in transfer mode thanks to the API CyU3PMipicsiInitializeI2c(); I cannot do differently because I need to write single bytes in different registers and with DMA transfer I can only write multiple of 16 bytes.

My goal is to read the data from the second sensor through i2c configured in DMA mode once the UVC app starts (the dma channel is connected between i2c slave and endpoint). Here come the problems:

- Once the UVC app starts, from time to time I'm still sending i2c data in transfer mode towards the camera (for features such as the change of resolution) and reading control bytes from the cx3 mipi csi receiver slave (the one whose address is 0000111, according to the cx3 TRM, page 8 sec 1.5). Is it possible to separate the two modes of the i2c (transfer and DMA) or should I constantly change the settings with the CyU3PI2cSetConfig() API, ie turning on the Dma mode before reading from the sensor and then turning it off immediately after the reading?

- To trigger the i2c DMA reading from the second slave I'm using an interrupt line coming from the sensor and connected to a GPIO of the cx3. I've used two reference designs to create the firmware, these are cyfxgpioapp and cyfxusbi2cdmamode, which I've found in the serialif_exaples folder of the SDK. What I'm doing right now is to set the trigger on the gpio associated to the interrupt, activate a callback function associated to it and in here setting an event through the CyU3PEventSet() API.
          - At this point, should I create a thread that handles the DMA transfer? Is a thread in the cx3 always running in "time slices"? (if I understood correctly the cx3 is single core).
          - If I should use a thread, how could I estimate the allocated memory for CyU3PMemAlloc()?
          - Why isn't it possible to use a peripheral directly in the callback function? This is what I understood from the cyfxgpioapp (line 119 of cyfxgpioapp.c regarding the  debug print).

I thank you in advance for your answer!

Regards,

Costantino

0 Likes
1 Solution
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi Costantino,

When you use Manual channel you need not use override mode. Override mode is used when user defined DMA buffer in the firmware is used for DMA transfers instead of DMA buffers allocated during channel creation. APIs are used for write and read DMA transfers respectively.

You can also refer DMA Channel in Override Mode in FX3/CX3 - KBA229098

For manual mode operation you can refer to C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\firmware\dma_examples\cyfxbulklpmanual

In the above example both the producer and consumer are USB endpoints which is different in your case.

Even when you use Manual mode: Perform CyU3PI2cSendCommand() (1) after successfully performing commitbuffer call while writing on I2c and (2) when you want to perform a read on I2c - Once the read is successful and when the DMA buffer is full you would receive dmacallback with CONS event.

Regards,

Hemanth 

Hemanth

View solution in original post

0 Likes
11 Replies
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi Costantino,

1. Is there a specific reason for using DMA mode with the sensor?

2. Can you please share the channel configuration details? - are you creating MANUAL_IN and MANUAL_OUT?

3. After you get the event using CyU3PEventSet() what are the actions perfomed?

4. Why isn't it possible to use a peripheral directly in the callback function?

>> It is because the GpioIntr callback comes from the interrupt context and should not be delayed more.

5. yes cx3 is having single core.

Regards,

Hemanth

Hemanth
0 Likes

Hello Hemanth and thank you for your reply.

1. We want to read / write with i2c from two slaves. One is our camera sensor (we mainly use the i2c to initialize it in register mode) and the second one is an Inertial Measurement Unit (IMU). Considering that our camera works with very high frames, to avoid a huge usage of the cx3 cpu we decided to use an i2c DMA transfer to read data from the IMU (we read 16 bytes with a frequency of 1 kHz).

2. Considering that the dma transfer needs to be triggered by an interrupt generated by the IMU, I decided to use the manual dma mode. The reference design sets the i2c Tx channel to CY_U3P_DMA_TYPE_MANUAL_OUT and the i2c Rx channel to CY_U3P_DMA_TYPE_MANUAL_IN. If the communication I want to establish is between i2c line and endpoint, should I use the same structure or should I stick with the type CY_U3P_DMA_TYPE_MANUAL? (In the dma header file I saw that the last type doesn't require the CPU on the consumer or producer sockets).

3. I have a thread with an infinite loop. Once I set an event with CyU3PEventSet() I can read it with CyU3PEventGet in the loop and at this point I'm planning to start the dma transfer (only if the CyU3PEventGet  API returns a success operation of course).

I hope I was clear with the explanation.

Regards,

Costantino

0 Likes
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi Costantino,

If the communication I want to establish is between i2c line and endpoint, should I use the same structure or should I stick with the type CY_U3P_DMA_TYPE_MANUAL?

>> You can use type manual. When you get Gpio interrupt callback, you can initiate the i2c read using CyU3PI2cSendCommand(). Once the buffer (of 16 bytes size) is full dma callback is received in the firmware where you can perform commit to the USB socket using CyU3PDmaChannelCommitBuffer().

Is it possible to separate the two modes of the i2c (transfer and DMA) or should I constantly change the settings with the CyU3PI2cSetConfig() API, ie turning on the Dma mode before reading from the sensor and then turning it off immediately after the reading?

>> Yes, you will have to constantly change the settings using CyU3PI2cSetConfig() - as the MIPI APIs provided by the SDK use I2c in Reg mode.

Regards,

Hemanth

Hemanth
0 Likes

Hello Hemanth and thank you for your reply.

On top of what I said I'd like to add that I used the CyU3PDmaChannelCommitBuffer in the callback function of the dma channel and I got the 0x42 error, meaning that the DMA channel is not started and I probably did something wrong with the configuration.

Could you point me a reference design for a dma channel configuration in dma manual mode? The one I used for the i2c dma was receiving data from the i2c and sending them towards the CPU and I imagine that the configuration changes if the consumer is an endpoint.

Also, I'm currently working with override mode with the dma buffer I'm using for the data transfer. I used this mode always because of the dmai2cmode example by setting the count value to 0 in the DmaChannelConfig. Could you clarify me what is the override mode exactly?

Thank you in advance for your reply,

Regards,

Costantino

0 Likes
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi Costantino,

When you use Manual channel you need not use override mode. Override mode is used when user defined DMA buffer in the firmware is used for DMA transfers instead of DMA buffers allocated during channel creation. APIs are used for write and read DMA transfers respectively.

You can also refer DMA Channel in Override Mode in FX3/CX3 - KBA229098

For manual mode operation you can refer to C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\firmware\dma_examples\cyfxbulklpmanual

In the above example both the producer and consumer are USB endpoints which is different in your case.

Even when you use Manual mode: Perform CyU3PI2cSendCommand() (1) after successfully performing commitbuffer call while writing on I2c and (2) when you want to perform a read on I2c - Once the read is successful and when the DMA buffer is full you would receive dmacallback with CONS event.

Regards,

Hemanth 

Hemanth
0 Likes

Hello Hemanth and thank you! Your reply were very useful for me to understand more about the DMA channel configuration.

I'm still confused about the last point you mentioned in the last answer, about the order of execution of the APIs. Here's how I'm doing:

  1. The external sensor generates an interrupt on a CX3 GPIO.
  2. The GPIO interrupt is associated to an ISR which sets an event.
  3. The UVC thread reads the event and calls a function that I created to read from I2c and Write on the Endpoint.

The function I created does the following:

  1. It turns on the DMA mode for the i2c line through the CyU3PI2cSetConfig API.
  2. It sends the preamble for the slave on the i2c line with the CyU3PI2cSendCommand API.
  3. It starts the DMA reading with CyU3PDmaChannelSetupRecvBuffer and I wait for completion with CyU3PDmaChannelWaitForCompletion (is the CyU3PDmaChannelWaitForRecvBuffer equivalent?).
  4. The API CyU3PDmaChannelSetupRecvBuffer works only when the DMA is in configured state, for this reason I cannot set an infinite transfer but, at this point, I can use the function CyU3PDmaChannelSetXfer by setting the value of count equal to the size of each channel buffer (am I making a mistake?).
  5. Once the CyU3PDmaChannelSetXfer API is correctly executed I can commit the buffer with CyU3PDmaChannelCommitBuffer, using the same count value I specified for the CyU3PDmaChannelSetXfer, if the commit is successful the channel should go back to the config state.
  6. It turns off the DMA mode of the i2c line with the CyU3PI2cSetConfig API.

Could you please give me a feedback on this APIs flow? I'm still getting some errors and I was wondering if the problem was related to the sequence of APIs.

Regards,

Costantino

0 Likes
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi Costantino,

You can try the below:

1. Configure two channels: Manual In (CPU - Cons, I2C - Prod), Manual Out (CPU - Prod, I2C - Cons)

2. When you receive the GPIO event in the thread, you can do below:

To write:

    a. Call CyU3PDmaChannelSetupSendBuffer()

    b. Call CyU3PI2cSendCommand()

    After this, you can either perform CyU3PDmaChannelWaitForCompletion() to wait for the data to go out of I2C lines OR you can register for CY_U3P_DMA_CB_SEND_CPLT event in dmaConfig.notification and wait for this event (Receiving this event in dma callback means that i2c write is complete)

To read:

    a. Call CyU3PI2cSendCommand()

    b. Call CyU3PDmaChannelSetupRecvBuffer()

    After this, you can either perform CyU3PDmaChannelWaitForCompletion() to wait for the data to be read from I2C bus OR you can register for CY_U3P_DMA_CB_RECV_CPLT event in dmaConfig.notification and wait for this event (Receiving this event in dma callback means that i2c write is complete)

Similarly you can have a manual OUT channel between CPU and USB endpoint and use CyU3PDmaChannelSetupSendBuffer() and wait for CY_U3P_DMA_CB_SEND_CPLT event.

Let me know if this is okay. The above method of operation is override mode (buf count during channel creation can be 0)

Regards,

Hemanth

Hemanth

Hello Hemanth and thanks for all of your replies, they were really useful for my project!
I initially used the last solution you gave me but in the end I realized that by using the API CyU3PI2cWaitForBlockXfer() instead of CyU3PDmaChannelSetupRecvBuffer() I can avoid the override mode and I can use a single manual channel in infinite transfer mode, thus avoiding the override mode.

Regards,

Costantino

0 Likes
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi Costantino,

Okay. So, you issue an I2c read and wait for it to complete using CyU3PI2cWaitForBlockXfer. Do you perform read for a DMA buffer amount of data (which should be 16 byte multiple)? - thereby getting a PROD event.

Regards,

Hemanth

Hemanth
0 Likes

Hello Hemanth,

Yes, I do perform a 16 bytes read at a time.

Regards,

Costantino

0 Likes
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Okay. In that case, doing a CyU3PDmaChannelCommitBuffer call would cause data getting committed to the endpoint (as endpoint is your consumer)

Regards,

Hemanth

Hemanth
0 Likes