Hi,community
I configuration the imx6q WEIM bus and connected the ST16C554 to expand 4 uart port , then I used the serial port to resive data,it's possible to get the wrong data such I send the data is "0x55",but i got the data "0x00"(if I got the error data it's always 0x00),most time i can get the correct data "0x55".
My board is I.MX6Q,and the linux kernel is 3.14.52
Someone met the same problem? and could you give me some idear
thanks very much!!
Alee
Hi Alee
one can try to adjust ST16C554 - EIM interface timings using
the dts timing array "weim-cs-timing"
imx-weim.txt\bus\bindings\devicetree\Documentation - linux-imx - i.MX Linux kernel
ST16C554 datasheet and sect.22.9 EIM Memory Map/Register Definition i.MX6DQ Reference Manual
https://www.nxp.com/docs/en/reference-manual/IMX6DQRM.pdf
Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi, igor
thank you for your reply !
our hardware connect is
((~EIM_DA7) & EIM_CS0) to 554_CSA
((EIM_DA7) & EIM_CS0) to 554_CSB
((~EIM_DA7) & EIM_CS1 ) to 554_CSC
((EIM_DA7) & EIM_CS1 ) to 554_CSD
For details,see the picture "weim & ST16C554 HW connect"
and the software we set the weim timing is
/*CSxGCR1, CSxGCR2, CSxRCR1,
CSxRCR2, CSxWCR1, CSxWCR2.*///cs0
writel(0x00660081, base + 0 * 0x18 + 0 * 4);
writel(0x00000001, base + 0 * 0x18 + 1 * 4);
writel(0x1C022000, base + 0 * 0x18 + 2 * 4);
writel(0x0000C000, base + 0 * 0x18 + 3 * 4);
writel(0x0C04A38E, base + 0 * 0x18 + 4 * 4);
writel(0x00000000, base + 0 * 0x18 + 5 * 4);//cs1
writel(0x00660081, base + 1 * 0x18 + 0 * 4);
writel(0x00000001, base + 1 * 0x18 + 1 * 4);
writel(0x1C022000, base + 1 * 0x18 + 2 * 4);
writel(0x0000C000, base + 1 * 0x18 + 3 * 4);
writel(0x0C04A38E, base + 1 * 0x18 + 4 * 4);
writel(0x00000000, base + 1 * 0x18 + 5 * 4);// EIM_WCR
writel(0x00000001, base + 0x90);
gpr :
u32 gprvals[4] = {
05, /* CS0(128M) CS1(0M) CS2(0M) CS3(0M) */
033, /* CS0(64M) CS1(64M) CS2(0M) CS3(0M) */
0113, /* CS0(64M) CS1(32M) CS2(32M) CS3(0M) */
01111, /* CS0(32M) CS1(32M) CS2(32M) CS3(0M) */
};..............
regmap_update_bits(gpr, IOMUXC_GPR1, 0xfff, gprvals[1]);/* CS0(64M) CS1(64M) CS2(0M) CS3(0M) */
I used the I.Mx6 self ttymxc3 send 10000 Bytes(0xFF) and used the 554 serial port ttySEX3 to resive , then I got an error Byte(0x00),others data is correct(0xFF),then I used the command "cat /proc/tty/driver/serial " the result is :
root@imx6qsabresd:/# cat /proc/tty/driver/serial
serinfo:1.0 driver revision:
0: uart:16550A mmio:0x08000080 irq:321 tx:0 rx:0 CTS|DSR|CD|RI
1: uart:16550A mmio:0x08000000 irq:322 tx:0 rx:0 DSR|CD|RI
2: uart:16550A mmio:0x0C000080 irq:323 tx:0 rx:0 CTS|DSR|CD|RI
3: uart:16550A mmio:0x0C000000 irq:324 tx:0 rx:99985 oe:1 RTS|CTS|DTR|DSR|CD|RI
I found the "oe:1" always equal to resive error data ,such as if I resive 10 error Bytes(0x00),the results "oe:10",could you tell me what's mean of the "oe"? and have some idea to locate this problem?thanks
Best Wish!!
Alee
Hi Alee
you can check eim timings with oscilloscope and compare with ST16C554 datasheet
requirements. Just for test one can try to decrease EIM frequency.
Best regards
igor
Hi igor
thank you !
I setted the EIM frequency to 66MHz(old value is 133MHz),but can't address this problem,
on the other hand , when I used the ST16C554 to receive the serial data,sometime the 554 FIFO will overrun,
then i will got the data "0x00". I used the standard serial port driver "kernel/driver/tty/serial/8250/8250_core.c" my kernel is 3.14.52.
I want to know what's reason cause the FIFO overrun(looks like IRQ responds not immedaitely),and what should I do to deal with this issue
Best regards
Alee
the function "serial8250_rx_chars" detail
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
{
............................do {
if (likely(lsr & UART_LSR_DR))
ch = serial_in(up, UART_RX);
else............................
ch = 0;............................
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
if (lsr & UART_LSR_BI) {
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
port->icount.brk++;
if (uart_handle_break(port))
goto ignore_char;
} else if (lsr & UART_LSR_PE)
port->icount.parity++;
else if (lsr & UART_LSR_FE)
port->icount.frame++;
if (lsr & UART_LSR_OE) // UART_LSR_OE bit be setted
port->icount.overrun++;............................
if (uart_handle_sysrq_char(port, ch))
goto ignore_char;uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); // at this function will send 0x00 to user space
ignore_char:
lsr = serial_in(up, UART_LSR);
} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
...................
}