i.MX 6ULL SDMA behaviour for UART receiving

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

i.MX 6ULL SDMA behaviour for UART receiving

1,339 次查看
ckw089
Contributor II

Hi,

The project is using Linux 6.1.22 running on i.MX 6ULL on our controller board.

And we use UART for the communication between the controller board and measurement board.

And the UART is enabled to use the SDMA.

We are developing a custom kernel driver for the UART receiving.

In the custom kernel driver, we use dmaengine_tx_status() function to get the residue in order to know there is new data in the receive buffer.

But, found out that the residue is not continuous incrementing at the same buffer, the SDMA will advance to the next buffer.

Is it possible to stay at the same buffer until it filled up and then only for the SDMA to move to the next buffer ?

rgds,

kc wong

 

标签 (2)
0 项奖励
回复
5 回复数

1,252 次查看
ckw089
Contributor II

(a) How to know which SDMA firmware that I am using (ROM or RAM)?

I only know sdma_get_pc() is called to set the pc of SDMA script according to the peripheral type.

https://elixir.bootlin.com/linux/v6.1.22/source/drivers/dma/imx-sdma.c#L975

But, I do not know that script is in ROM or RAM.

(b) How do modify the SDMA firmware ?

(c) Our application is using HDLC frames also ...

From my observation, the buffer descriptor is closed even after it receives one byte. So, the buffer is definitely not full.

Then, it must be the aging timeout that causes it to close the current buffer descriptor.

So, in order to fully utilize the buffer, I guess I need to disable the aging timeout.

But, if I disable the aging timeout, there will be no interrupt to update the available bytes in the buffer.

The behaviour I need is to have the aging timeout to interrupt and update the available bytes in the buffer, but do not close the current buffer descriptor.

The current buffer descriptor should only be closed when it is full.

IMX SDMA is not like PrimeCell DMA Controller (PL080), PL080 has a destination address register that can be read anytime to know the available bytes in the buffer.

 

0 项奖励
回复

1,211 次查看
ceggers
Contributor V

(a) How to know which SDMA firmware that I am using (ROM or RAM)?

You should see one of these messages:

  1. imx-sdma 20ec000.sdma: external firmware not found, using ROM firmware
  2. imx-sdma 20ec000.sdma: loaded firmware x.xx

(b) How do modify the SDMA firmware ?

NXP offers no tools nor support for this. There are tutorials from Eli Billauer and Jonah Petri on the net. I personally have created my own toolset for SDMA development. In contrast to the former ones, my solution requires (almost) no modification of the Linux SDMA driver, as a link the whole SDMA firmware together in one firmware file instead of loading my own script separately.

If you want to avoid starting your own SDMA development, or you are interested on my toolchain, simply send me a privat message.

(c) Our application is using HDLC frames also

I think that it makes not much sense to use (S)DMA on the one hand, and to "poll" for the number of received bytes / 0x7e character on the other hand.

With the "default" SDMA firmware + UART, you will receive "partial" HDLC frames consisting of something between one and N bytes. Without the aging timeout, the SDMA would stop receiving only when the RX buffer has been completely filled up with data. But this wouldn't work with variable length messages like HDLC (as reception would never finish).

The problem with the "partial" frames is, that the RX buffers are not well filled and it's likely that you can run out of available buffers (because every buffer contains only a few bytes). This can only be avoided if ...

  1. The other systems sends the whole HDLC frame without intermediate gaps (so the aging IRQ only appears after a complete frame), OR
  2. You use a/my modified SDMA firmware, which closes the RX buffer only after the buffer is completely filled up or 0x7e has been received.

As you already mentioned, you cannot monitor the number received/available bytes as long as the SDMA transfer is ongoing. The SDMA "processor" keeps the remaining space in an internal CPU register.

1,174 次查看
ckw089
Contributor II

(a) So, I guess I am using the ROM firmware 3.5

[ 0.632457] imx-sdma 20ec000.dma-controller: firmware found.
[ 0.635596] imx-sdma 20ec000.dma-controller: loaded firmware 3.5

(b) Our project is basically migrating a 10-year old WinCE application which is originally running on SPEAr320S.

The SPEAr320S has PrimeCell UART (PL011) and PrimeCell DMA Controller (PL080).

PL080 has a destination address register for application to know where the DMA will write next. That destination address register basically acts like a DMA write pointer.

Then, a circular buffer is setup to be accessible by both the application and the DMA for UART receiving.

So, the application just have to poll that register at 10ms interval. Application will know there is new data in the buffer if the DMA write pointer is not the same as the application read pointer.

(c) I am trying to duplicate the same scheme using i.MX 6ULL SDMA in Linux.

This seem to be impossible with current SDMA firmware as SDMA does not have the destination address register. And the SDMA is relying on aging timeout interrupt to update the residue as returned by dmaengine_tx_status() function.

So, I guess we want to change the SDMA firmware so that when aging timeout occurred, it does not close the current buffer descriptor. The current buffer descriptor is only closed when the buffer is full.

But, that will require Linux SDMA driver to be modified so that it does not  move to the next buffer in ISR when the current buffer descriptor is not closed.

Not sure if that can be done ?

 

0 项奖励
回复

1,123 次查看
ceggers1
Contributor IV

(a) So, I guess I am using the ROM firmware 3.5

You are using the RAM firmware 3.5 :-). It is likely that this firmware file is loaded from /lib/firmware/imx/sdma (or similar).

(b) PL080 has a destination address register for application to know where the DMA will write next. That destination address register basically acts like a DMA write pointer.

I also know this scheme from other controllers (e.g. STM32). But the SDMA doesn't expose this information as long as a transfer is running. A SDMA buffer descriptor is either in use by the SDMA or the CPU (but never both at the same time).

(c) I am trying to duplicate the same scheme using i.MX 6ULL SDMA in Linux.

Your idea sounds straight forward for me and I would do this similar on STM32. But on i.MX6, I have solved this differently for the following reasons.

  1. The SDMA is a processor on its own. It is difficult/inefficient to permanently "synchronize" its internal "state" (write pointer) with the ARM CPU.
  2. Polling the "write pointer" on the ARM CPU has several drawbacks:
    1. If no new data is available, it's a waste of CPU time
    2. If new data arrives, it can take up to 10 ms until it is processed (extra latency)
  3. The SDMA is quite flexible, so a superior solution can be used.

The actual problem with UART communication is, that transfers typically ...

  • consist of multiple/may UART "frames" (a UART "frame" means "5 to 9 bits")
  • the number of frames to receive is initially not known
    • some protocols "embed" the transfer length within the first byte(s)
    • other protocols use special characters as a frame delimiter (e.g. 0x7E for HDLC)

This is usually not a problem for transmitters, a they typically know the length of the whole frame before starting transmission (= setting up the DMA transfer). But for receivers it is often not possible to receive a frame sorely by DMA. I think that you current solution uses

  • the DMA for guaranteeing that no received bytes are lost (e.g. due to IRQ latency / busy CPU)
  • the CPU for determining when the UART frame has been fully received

For the reasons I mentioned above, I recommend to move the detection of the HDLC frame delimiters into the SDMA. In that case, that CPU has nothing to do (no polling) while the data is received by that UART. The SDMA will generate an IRQ only if ...

  1. A whole HDLC frame is in the RX buffer
  2. The RX buffer is completely full (for the case the length of a HDLC frame exceeds the SDMA buffer size). The SDMA will autonomously switch to the next buffer, so there is no particular limit for the overall length of HDLC frames.

Another advantage if this approach is, that you can get away with the existing i.MX UART driver. So you can probably avoid developing you own Linux driver.

1,290 次查看
ceggers
Contributor V

Hi,

which SDMA firmware do you use (ROM or RAM)? As far as I know, the the SDMA firmware closes the current buffer descriptor when ...

  • At least one byte has been received,
  • AND
    • the buffer is full, OR
    • an aging timeout has been occured

I use a slightly modified SDMA firmware for reception of HDLC frames (delimited by a 0x7E character). With my modified firmware, the buffer descriptor is closed when ...

  • At least one byte has been received,
  • AND
    • the buffer is full, OR
    • the character 0x7E has been received.

What type of data frames do you want to receive?

regards,
Christian