Ok,
Well, the baudrate is at 38400, the distribution is the Ubuntu from Robert
C Nelson ( 3.8.13 bone 30 ), the driver is the omap . I've modified a
little bit the driver to add RS485 support ( see the patch attached ) , the
only major modification that I've done is to add :
+ wait_for_xmitr(up);
+ if (up->rs485.flags & SER_RS485_ENABLED) {
+ if(up->rs485.delay_rts_after_send>0){
+ udelay(up->rs485.delay_rts_after_send);
+ }
+ /* Disable RS485 TX EN */
+ val = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;
+ gpio_set_value(up->rs485.gpio_pin, val);
+ }
in the function serial_omap_stop_tx .
It works most of the time, but for an unknown reason there is this weird
behavior .....
Any tips ? lead to follow ?
On Fri, Jan 3, 2014 at 11:38 PM, William Hermans <[email protected]> wrote:
> You're missing a bunch of information needed to help troubleshoot/ For
> starters how fast ? Which distro ? Which kernel driver are you using ? etc
> etc etc.
>
>
> On Fri, Jan 3, 2014 at 8:55 AM, Micka <[email protected]> wrote:
>
>> Hi,
>>
>> I would like to know if someone has experienced data sliced in two pieces
>> ?
>>
>> My case is simple, the UART in the beagleBone Black send the data in two
>> piece .....
>>
>> The problem is that the device answer with an error crc ....
>>
>> so why the uart is doing that ?
>>
>>
>> Micka,
>>
>> --
>> For more options, visit http://beagleboard.org/discuss
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "BeagleBoard" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected].
>> For more options, visit https://groups.google.com/groups/opt_out.
>>
>
> --
> For more options, visit http://beagleboard.org/discuss
> ---
> You received this message because you are subscribed to the Google Groups
> "BeagleBoard" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/groups/opt_out.
>
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 57d6b29..aa71c13 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -37,6 +37,8 @@
#include <linux/clk.h>
#include <linux/serial_core.h>
#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/gpio.h>
@@ -160,6 +162,7 @@ struct uart_omap_port {
u32 calc_latency;
struct work_struct qos_work;
struct pinctrl *pins;
+ struct serial_rs485 rs485;
};
#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port,
port)))
@@ -268,11 +271,11 @@ static void serial_omap_enable_ms(struct uart_port *port)
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
}
-
+static inline void wait_for_xmitr(struct uart_omap_port *up);
static void serial_omap_stop_tx(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
-
+ int val;
pm_runtime_get_sync(up->dev);
if (up->ier & UART_IER_THRI) {
up->ier &= ~UART_IER_THRI;
@@ -283,6 +286,15 @@ static void serial_omap_stop_tx(struct uart_port *port)
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
+ wait_for_xmitr(up);
+ if (up->rs485.flags & SER_RS485_ENABLED) {
+ if(up->rs485.delay_rts_after_send>0){
+ udelay(up->rs485.delay_rts_after_send);
+ }
+ /* Disable RS485 TX EN */
+ val = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;
+ gpio_set_value(up->rs485.gpio_pin, val);
+ }
}
static void serial_omap_stop_rx(struct uart_port *port)
@@ -345,12 +357,23 @@ static inline void serial_omap_enable_ier_thri(struct
uart_omap_port *up)
static void serial_omap_start_tx(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
+ int val;
+
+ if (up->rs485.flags & SER_RS485_ENABLED) {
+ /* Enable RS485 TX EN */
+ val = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 0 : 1;
+ gpio_set_value(up->rs485.gpio_pin, val);
+ if(up->rs485.delay_rts_before_send>0){
+ udelay(up->rs485.delay_rts_before_send);
+ }
+ }
pm_runtime_get_sync(up->dev);
serial_omap_enable_ier_thri(up);
serial_omap_set_noidle(up);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
+
}
static void serial_omap_throttle(struct uart_port *port)
@@ -702,6 +725,7 @@ static void serial_omap_shutdown(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
+ int val;
dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line);
@@ -722,6 +746,12 @@ static void serial_omap_shutdown(struct uart_port *port)
*/
serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
serial_omap_clear_fifos(up);
+
+ /* if in RS485 mode, make sure we disable the driver */
+ if (up->rs485.flags & SER_RS485_ENABLED) {
+ val = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;
+ gpio_set_value(up->rs485.gpio_pin, val);
+ }
/*
* Read data port to reset things, and then free the irq
@@ -1250,6 +1280,93 @@ static inline void serial_omap_add_console_port(struct
uart_omap_port *up)
#endif
+
+static int
+serial_omap_config_rs485(struct uart_port *port, struct serial_rs485
*rs485conf)
+{
+ int r = 0;
+ int val;
+ struct uart_omap_port *p = (struct uart_omap_port *)port;
+
+ spin_lock(&port->lock);
+
+ /* TODO - disable transmitter ? */
+
+ if (rs485conf->flags & SER_RS485_ENABLED) {
+ val = (p->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;
+ /* if using GPIO, request the resource and set it up */
+ if (rs485conf->flags & SER_RS485_USE_GPIO) {
+ /* get gpio resources if not already set */
+ if (!(p->rs485.flags & SER_RS485_USE_GPIO) ||
+ (p->rs485.gpio_pin != rs485conf->gpio_pin)) {
+
+ r = gpio_request(rs485conf->gpio_pin,
+ "RS485 TXE");
+ if (r) {
+ dev_warn(port->dev,
+ "Could not request GPIO %d :
%d\n",
+ rs485conf->gpio_pin, r);
+ r = -EFAULT;
+ goto exit_bail;
+
+ }
+
+ r = gpio_direction_output(rs485conf->gpio_pin,
val);
+ if (r) {
+ dev_warn(port->dev,
+ "Could not drive GPIO %d :
%d\n",
+ rs485conf->gpio_pin, r);
+ r = -EFAULT;
+ goto exit_bail;
+ }
+
+ /* free up old pin */
+//TODO: What if old pin is same as current?!!?!?
+ //if (p->rs485.flags & SER_RS485_USE_GPIO)
+ //gpio_free(p->rs485.gpio_pin);
+ }
+ } else { /* RTS pin requested */
+ dev_warn(port->dev, "Must use GPIO for RS485
Support\n");
+ goto exit_bail;
+ }
+ }
+ p->rs485 = *rs485conf;
+
+exit_bail:
+ spin_unlock(&port->lock);
+ return r;
+
+}
+
+static int
+serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+ struct serial_rs485 rs485conf;
+ switch (cmd) {
+ case TIOCSRS485:
+ printk("rs485\n");
+ if (copy_from_user(&rs485conf, (struct serial_rs485 *)arg,
+ sizeof(rs485conf)))
+ return -EFAULT;
+ serial_omap_config_rs485(port, &rs485conf);
+ break;
+
+ case TIOCGRS485:
+ printk("rs485\n");
+ if (copy_to_user((struct serial_rs485 *)arg,
+ &((struct uart_omap_port *)port)->rs485,
+ sizeof(rs485conf)))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+
static struct uart_ops serial_omap_pops = {
.tx_empty = serial_omap_tx_empty,
.set_mctrl = serial_omap_set_mctrl,
@@ -1271,6 +1388,7 @@ static struct uart_ops serial_omap_pops = {
.request_port = serial_omap_request_port,
.config_port = serial_omap_config_port,
.verify_port = serial_omap_verify_port,
+ .ioctl = serial_omap_ioctl,
#ifdef CONFIG_CONSOLE_POLL
.poll_put_char = serial_omap_poll_put_char,
.poll_get_char = serial_omap_poll_get_char,
diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 5e0d0ed..1830ceb 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -109,18 +109,16 @@ struct serial_icounter_struct {
*/
struct serial_rs485 {
- __u32 flags; /* RS485 feature flags */
-#define SER_RS485_ENABLED (1 << 0) /* If enabled */
-#define SER_RS485_RTS_ON_SEND (1 << 1) /* Logical level for
- RTS pin when
- sending */
-#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for
- RTS pin after sent*/
-#define SER_RS485_RX_DURING_TX (1 << 4)
- __u32 delay_rts_before_send; /* Delay before send (milliseconds) */
- __u32 delay_rts_after_send; /* Delay after send (milliseconds) */
- __u32 padding[5]; /* Memory is cheap, new structs
- are a royal PITA .. */
-};
-
+ __u32 flags; /* RS485 feature flags */
+ #define SER_RS485_ENABLED (1 << 0)
+ #define SER_RS485_RTS_ON_SEND (1 << 1)
+ #define SER_RS485_RTS_AFTER_SEND (1 << 2)
+ #define SER_RS485_RTS_BEFORE_SEND (1 << 3)
+ #define SER_RS485_USE_GPIO (1 << 5)
+ __u32 delay_rts_before_send; /* Microseconds */
+ __u32 delay_rts_after_send; /* Microseconds */
+ __u32 gpio_pin; /* GPIO Pin Index */
+ __u32 padding[4]; /* Memory is cheap, new structs
+ are a royal PITA .. */
+ };
#endif /* _UAPI_LINUX_SERIAL_H */