From 57781b40cb809a1d77aeda8f219be04ab3a9e241 Mon Sep 17 00:00:00 2001 From: skarg Date: Mon, 18 Oct 2010 20:42:26 +0000 Subject: [PATCH] Changed Tturnaround time in MS/TP modules to be a minimum of 2ms, or use a dummy transmit of 4 bytes while the transceiver is disabled. 1ms delay will always give smaller than 1ms of delay due to silence timer tick. --- bacnet-stack/ports/at91sam7s/rs485.c | 4 +- bacnet-stack/ports/atmega168/rs485.c | 62 +++++++++++------------ bacnet-stack/ports/atmega8/rs485.c | 25 ++++++--- bacnet-stack/ports/bdk-atxx4-mstp/rs485.c | 25 ++++++--- bacnet-stack/ports/linux/rs485.c | 2 +- bacnet-stack/ports/pic18f6720/rs485.c | 2 +- bacnet-stack/ports/rtos32/rs485.c | 5 +- bacnet-stack/ports/win32/rs485.c | 2 +- 8 files changed, 72 insertions(+), 55 deletions(-) diff --git a/bacnet-stack/ports/at91sam7s/rs485.c b/bacnet-stack/ports/at91sam7s/rs485.c index 4e4da882..98676a51 100644 --- a/bacnet-stack/ports/at91sam7s/rs485.c +++ b/bacnet-stack/ports/at91sam7s/rs485.c @@ -167,7 +167,7 @@ void RS485_Turnaround_Delay( /* delay after reception before trasmitting - per MS/TP spec */ /* wait a minimum 40 bit times since reception */ /* at least 1 ms for errors: rounding, clock tick */ - turnaround_time = 1 + ((Tturnaround * 1000UL) / RS485_Baud); + turnaround_time = 2 + ((Tturnaround * 1000UL) / RS485_Baud); while (Timer_Silence() < turnaround_time) { /* do nothing - wait for timer to increment */ }; @@ -241,7 +241,7 @@ bool RS485_ReceiveError( } /**************************************************************************** -* DESCRIPTION: Return true if data is available +* DESCRIPTION: Return true if data is available * RETURN: true if data is available, with the data in the parameter set * ALGORITHM: none * NOTES: none diff --git a/bacnet-stack/ports/atmega168/rs485.c b/bacnet-stack/ports/atmega168/rs485.c index 40bc9e2a..1386c7ab 100644 --- a/bacnet-stack/ports/atmega168/rs485.c +++ b/bacnet-stack/ports/atmega168/rs485.c @@ -44,18 +44,6 @@ static uint8_t LED3_Off_Timer; /* baud rate */ static uint32_t RS485_Baud = 9600; -/* The minimum time after the end of the stop bit of the final octet of a */ -/* received frame before a node may enable its EIA-485 driver: 40 bit times. */ -/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */ -/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */ -/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */ -/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */ -/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */ -/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */ -/* 40 bits is 4 octets including a start and stop bit with each octet */ -#define Tturnaround (40UL) -/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */ - /**************************************************************************** * DESCRIPTION: Initializes the RS485 hardware and variables, and starts in * receive mode. @@ -137,26 +125,6 @@ bool RS485_Set_Baud_Rate( return valid; } -/**************************************************************************** -* DESCRIPTION: Waits on the SilenceTimer for 40 bits. -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -void RS485_Turnaround_Delay( - void) -{ - uint16_t turnaround_time; - - /* delay after reception before trasmitting - per MS/TP spec */ - /* wait a minimum 40 bit times since reception */ - /* at least 1 ms for errors: rounding, clock tick */ - turnaround_time = 1 + ((Tturnaround * 1000UL) / RS485_Baud); - while (Timer_Silence() < turnaround_time) { - /* do nothing - wait for timer to increment */ - }; -} - /**************************************************************************** * DESCRIPTION: Enable or disable the transmitter * RETURN: none @@ -173,6 +141,35 @@ void RS485_Transmitter_Enable( } } +/**************************************************************************** +* DESCRIPTION: Waits on the SilenceTimer for 40 bits. +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Turnaround_Delay( + void) +{ + uint8_t nbytes = 4; + + RS485_Transmitter_Enable(false); + while (nbytes) { + while (!BIT_CHECK(UCSR0A, UDRE0)) { + /* do nothing - wait until Tx buffer is empty */ + } + /* Send the data byte */ + UDR0 = 0xff; + nbytes--; + } + /* was the frame sent? */ + while (!BIT_CHECK(UCSR0A, TXC0)) { + /* do nothing - wait until the entire frame in the + Transmit Shift Register has been shifted out */ + } + /* Clear the Transmit Complete flag by writing a one to it. */ + BIT_SET(UCSR0A, TXC0); +} + /**************************************************************************** * DESCRIPTION: Timers for delaying the LED indicators going off * RETURN: none @@ -253,7 +250,6 @@ void RS485_Send_Data( Timer_Silence_Reset(); } - /**************************************************************************** * DESCRIPTION: Return true if a framing or overrun error is present * RETURN: true if error diff --git a/bacnet-stack/ports/atmega8/rs485.c b/bacnet-stack/ports/atmega8/rs485.c index 40eada2e..e95b5de5 100644 --- a/bacnet-stack/ports/atmega8/rs485.c +++ b/bacnet-stack/ports/atmega8/rs485.c @@ -161,15 +161,24 @@ bool RS485_Set_Baud_Rate( void RS485_Turnaround_Delay( void) { - uint16_t turnaround_time; + uint8_t nbytes = 4; - /* delay after reception before trasmitting - per MS/TP spec */ - /* wait a minimum 40 bit times since reception */ - /* at least 1 ms for errors: rounding, clock tick */ - turnaround_time = 1 + ((Tturnaround * 1000UL) / RS485_Baud); - while (!timer_silence_elapsed(turnaround_time)) { - /* do nothing - wait for timer to increment */ - }; + RS485_Transmitter_Enable(false); + while (nbytes) { + while (!BIT_CHECK(UCSR0A, UDRE0)) { + /* do nothing - wait until Tx buffer is empty */ + } + /* Send the data byte */ + UDR0 = 0xff; + nbytes--; + } + /* was the frame sent? */ + while (!BIT_CHECK(UCSR0A, TXC0)) { + /* do nothing - wait until the entire frame in the + Transmit Shift Register has been shifted out */ + } + /* Clear the Transmit Complete flag by writing a one to it. */ + BIT_SET(UCSR0A, TXC0); } /**************************************************************************** diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/rs485.c b/bacnet-stack/ports/bdk-atxx4-mstp/rs485.c index 4a24b264..2aa574c7 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/rs485.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/rs485.c @@ -94,15 +94,26 @@ static void rs485_receiver_enable( void rs485_turnaround_delay( void) { - uint16_t turnaround_time; + uint8_t nbytes = 4; /* delay after reception before trasmitting - per MS/TP spec */ - /* wait a minimum 40 bit times since reception */ - /* at least 1 ms for errors: rounding, clock tick */ - turnaround_time = 1 + ((Tturnaround * 1000UL) / Baud_Rate); - while (!timer_elapsed_milliseconds_short(&Silence_Timer, turnaround_time)) { - /* do nothing - wait for timer to increment */ - }; + /* Transmit 4 dummy bytes with RS485 driver off. + This equals the 40 bit times (1 start, 8 data, 1 stop). */ + rs485_rts_enable(false); + while (nbytes) { + /* Send the data byte */ + UDR0 = 0xff; + while (!BIT_CHECK(UCSR0A, UDRE0)) { + /* do nothing - wait until Tx buffer is empty */ + } + nbytes--; + } + while (!BIT_CHECK(UCSR0A, TXC0)) { + /* do nothing - wait until the entire frame in the + Transmit Shift Register has been shifted out */ + } + /* Clear the Transmit Complete flag by writing a one to it. */ + BIT_SET(UCSR0A, TXC0); } ISR(USART0_RX_vect) diff --git a/bacnet-stack/ports/linux/rs485.c b/bacnet-stack/ports/linux/rs485.c index 70b76d56..f2173c7c 100644 --- a/bacnet-stack/ports/linux/rs485.c +++ b/bacnet-stack/ports/linux/rs485.c @@ -184,7 +184,7 @@ void RS485_Send_Frame( else if (baud == 19200) turnaround_time = 2; else - turnaround_time = 1; + turnaround_time = 2; while (mstp_port->SilenceTimer() < turnaround_time) { /* do nothing - wait for timer to increment */ sched_yield(); diff --git a/bacnet-stack/ports/pic18f6720/rs485.c b/bacnet-stack/ports/pic18f6720/rs485.c index b34ea97a..67e0d405 100644 --- a/bacnet-stack/ports/pic18f6720/rs485.c +++ b/bacnet-stack/ports/pic18f6720/rs485.c @@ -78,7 +78,7 @@ void RS485_Send_Frame( else if (RS485_Baud_Rate == 19200) turnaround_time = 2; else - turnaround_time = 1; + turnaround_time = 2; while (mstp_port->SilenceTimer < turnaround_time) { /* The line has not been silent long enough, so wait. */ diff --git a/bacnet-stack/ports/rtos32/rs485.c b/bacnet-stack/ports/rtos32/rs485.c index 7f0a035b..0d1da09b 100644 --- a/bacnet-stack/ports/rtos32/rs485.c +++ b/bacnet-stack/ports/rtos32/rs485.c @@ -172,6 +172,7 @@ void RS485_Send_Frame( { /* number of bytes of data (up to 501) */ bool status = true; /* return value */ + /* fixme: wait turnaround time */ RS485_TRANSMIT_ENABLE(RS485_Port); SendBlock(RS485_Port, (char *) buffer, nbytes); /* need to wait at least 9600 baud * 512 bytes = 54mS */ @@ -179,8 +180,8 @@ void RS485_Send_Frame( while (!(LineStatus(RS485_Port) & TX_SHIFT_EMPTY)) RTKScheduler(); RS485_RECEIVE_ENABLE(RS485_Port); - /* SilenceTimer is cleared by the Receive State Machine when - activity is detected and by the SendFrame procedure as each + /* SilenceTimer is cleared by the Receive State Machine when + activity is detected and by the SendFrame procedure as each octet is transmitted. */ mstp_port->SilenceTimer = 0; #if PRINT_ENABLED_RS485 diff --git a/bacnet-stack/ports/win32/rs485.c b/bacnet-stack/ports/win32/rs485.c index 86517631..b25c5078 100644 --- a/bacnet-stack/ports/win32/rs485.c +++ b/bacnet-stack/ports/win32/rs485.c @@ -383,7 +383,7 @@ void RS485_Send_Frame( else if (baud == 19200) turnaround_time = 2; else - turnaround_time = 1; + turnaround_time = 2; while (mstp_port->SilenceTimer() < turnaround_time) { /* do nothing - wait for timer to increment */ };