IMX6 RS485 with 9th bit: how to change via termios

cancel
Showing results for 
Search instead for 
Did you mean: 

IMX6 RS485 with 9th bit: how to change via termios

1,172 Views
r_veens
Contributor II

Hi,

I have RS485 working and i need to add the functionality to change the 9th bit (TXB8 of UMCR).

I have implemented a boolean in the drivers/tty/serial/imx.c that is set by parodd or ~parodd termios option.

I was wondering what should be the correct location to set TXB8 of UMCR. Currently i have added the following to the  imx_start_tx function:

unsigned long umcr = 0;

umcr |= UMCR_MDEN;
if(sport->nine_bit_high)
{
umcr |= UMCR_TXB8_HIGH;
}
writel(umcr, sport->port.membase + UMCR);

Where nine_bit_high is set via termios.

This seems to work, under some conditions.

In userspace i am required to call the sleep() function after writing some bytes, before changing the 9th bit again:

       unsigned char buf[10] = {0};

buf[0] = 0x02; //board id
buf[1] = 0x07; //control
buf[2] = 0x0; //request id
buf[3] = 0x01; //request id
buf[4] = 0x0; //datalen
buf[5] = 0x0; //datalen
buf[6] = 0x01; //xor

set9bit(true);
write_uart(buf, 1); //Send address

sleep(1); // this is required or else a problem

set9bit(false);
write_uart(buf+1, 6);

When looking at the first byte being sent (buf[0], 0x02) on scope i see the following when i do not include the sleep:

pastedImage_2.png

When running once again:

pastedImage_3.png

So it seems to be some kind of race condition, the data is always different.

When i do enable the sleep(1) function i always get the following (correct) result:

pastedImage_4.png

I was hoping to find someone here who has knowledge of how to debug this or what the possible problem could be.

The work-around i have found currently with the sleep function is not preferred as it required changes in user-space.

We are in the process of upgrading the BSP from 3.10.17 to 4.9.11. In the old version this sleep was not required and we made the same changes to the code in imx_start_tx.

I have seen the thread https://community.nxp.com/thread/462526  where it is suggested there can be issues with transmitting but this did not offer me a solution.

Best regards,

Rick

0 Kudos
4 Replies

674 Views
r_veens
Contributor II

Hello everyone, 

I have since found the problem.

The problem is not related to setting the parod termios flag or the ninth bit.

It is related to the imx_flush_buffer function in drivers/tty/serial/imx.c that has been changed from the 3.10.17 to the 4.9.11 kernel. The following has been added:

/*
* According to the Reference Manual description of the UART SRST bit:
* "Reset the transmit and receive state machines,
* all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
* and UTS[6-3]". As we don't need to restore the old values from
* USR1, USR2, URXD, UTXD, only save/restore the other four registers
*/
ubir = readl(sport->port.membase + UBIR);
ubmr = readl(sport->port.membase + UBMR);
uts = readl(sport->port.membase + IMX21_UTS);

temp = readl(sport->port.membase + UCR2);
temp &= ~UCR2_SRST;
writel(temp, sport->port.membase + UCR2);

while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);

/* Restore the registers */
writel(ubir, sport->port.membase + UBIR);
writel(ubmr, sport->port.membase + UBMR);
writel(uts, sport->port.membase + IMX21_UTS);

It would seem that it performs a software reset in the flush, and that this does not adequately wait for the DMA to finish its work.

So instead of flushing the buffer, it actually prevents some data to be written.

In the cusomer's code a flush is issued right after a write.

  bytes_written = write(fd, buf+totalSent, len);

  tcflush(fd, TCIOFLUSH);

This flush causes the behavior mentioned in my previous post.

This has been introduced in commit 934084a9d2d95d0ce98ae8d1ec3bfe81c95c678c, and is still present in the current version:

linux-fslc/imx.c at 4.1-2.0.x-imx · Freescale/linux-fslc · GitHub 

I have tried to add some code that would wait for the DMA to complete any work.

However, it seems that i am not allowed to call a premptive function to wait for the work_queue to be empty.

Furthermore, looping for the sport->dma_is_txing to change does not fix the issue.

I also tried to restore some more of the registers mention in the comments, but this has not fixed the issue.

My current solution is to undo commit 934084a9d2d95d0ce98ae8d1ec3bfe81c95c678c.

Best regards,

Rick Veens

0 Kudos

674 Views
fabio_estevam
NXP Employee
NXP Employee

Hi Rick,

Thanks for reporting the issue and sorry for causing trouble.

Should we avoid clearing UCR2_SRST when the DMA is active?

Does this change help?

http://code.bulix.org/iyy7ew-405980 

Thanks

0 Kudos

674 Views
r_veens
Contributor II

I have decided to turn off DMA due to some other issue (removed imx_uart_dma_init in imx_startup), and this issue disappeared as well.

0 Kudos

674 Views
fabio_estevam
NXP Employee
NXP Employee

Hi Rick,

I remember that there have been some recent patches in mainline kernel related to the i.MX DMA/RS485.

If you have a chance, maybe you could try to run 4.18 with DMA enabled and see if this issue has been fixed.

Regards,

Fabio Estevam

0 Kudos