Rewrote MS/TP to minimize memory usage. Compiles, but untested.

This commit is contained in:
skarg
2007-09-05 23:13:15 +00:00
parent 794362580b
commit 17ceb11d3c
5 changed files with 1235 additions and 308 deletions
+101 -44
View File
@@ -35,10 +35,23 @@
/* This file has been customized for use with ATMEGA168 */
#include "hardware.h"
#include "timer.h"
/* baud rate */
static uint32_t RS485_Baud = 38400;
/* 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.
@@ -61,15 +74,13 @@ void RS485_Initialize(void)
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
/* Clear Power Reduction USART0 */
BIT_CLEAR(PRR,PRUSART0);
/* Use port PD2 for RTS - enable and disable of Transceiver Tx/Rx */
/* Set port bit as Output */
BIT_SET(DDRD,DDD2);
return;
}
void RS485_Cleanup(void)
{
}
/****************************************************************************
* DESCRIPTION: Returns the baud rate that we are currently running at
* RETURN: none
@@ -83,7 +94,7 @@ uint32_t RS485_Get_Baud_Rate(void)
/****************************************************************************
* DESCRIPTION: Sets the baud rate for the chip USART
* RETURN: none
* RETURN: true if valid baud rate
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
@@ -113,23 +124,50 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
return valid;
}
/* Transmits a Frame on the wire */
void RS485_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
uint16_t nbytes) /* number of bytes of data (up to 501) */
/****************************************************************************
* DESCRIPTION: Waits on the SilenceTimer for 40 bits.
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void RS485_Turnaround_Delay(void)
{
uint8_t turnaround_time;
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 */
};
}
/* delay after reception - per MS/TP spec */
if (mstp_port) {
/* 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 (mstp_port->SilenceTimer() < turnaround_time) {
/* do nothing - wait for timer to increment */
};
/****************************************************************************
* DESCRIPTION: Enable or disable the transmitter
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void RS485_Transmitter_Enable(bool enable)
{
if (enable) {
BIT_SET(PORTD,PD2);
} else {
BIT_CLEAR(PORTD,PD2);
}
}
/****************************************************************************
* DESCRIPTION: Send some data and wait until it is sent
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void RS485_Send_Data(
uint8_t * buffer, /* data to send */
uint8_t nbytes) /* number of bytes of data */
{
while (nbytes) {
while (!BIT_CHECK(UCSR0A,UDRE0)) {
/* do nothing - wait until Tx buffer is empty */
@@ -142,34 +180,53 @@ void RS485_Send_Frame(
/* do nothing - wait until the entire frame in the
Transmit Shift Register has been shifted out */
}
/* per MSTP spec */
if (mstp_port) {
mstp_port->SilenceTimerReset();
}
return;
}
/* called by timer, interrupt(?) or other thread */
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
/****************************************************************************
* DESCRIPTION: Return true if a framing or overrun error is present
* RETURN: true if error
* ALGORITHM: none
* NOTES: Clears any error flags.
*****************************************************************************/
bool RS485_ReceiveError(void)
{
if (mstp_port->ReceiveError == true) {
/* wait for state machine to clear this */
}
/* wait for state machine to read from the DataRegister */
else if (mstp_port->DataAvailable == false) {
/* check for error */
if (BIT_CHECK(UCSR0A,FE0)) {
mstp_port->ReceiveError = true;
}
bool uart_error = false;
uint8_t dummy_data;
if (BIT_CHECK(UCSR0A,DOR0)) {
mstp_port->ReceiveError = true;
}
/* check for data */
if (BIT_CHECK(UCSR0A,RXC0)) {
mstp_port->DataRegister = UDR0;
mstp_port->DataAvailable = true;
/* check for framing error */
if (BIT_CHECK(UCSR0A,FE0)) {
uart_error = true;
}
/* check for overrun error */
if (BIT_CHECK(UCSR0A,DOR0)) {
uart_error = true;
}
/* flush the receive buffer */
if (uart_error) {
while (BIT_CHECK(UCSR0A,RXC0)) {
dummy_data = UDR0;
}
}
return uart_error;
}
/****************************************************************************
* DESCRIPTION: Return true if data is available
* RETURN: true if data is available, with the data in the parameter set
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
bool RS485_DataAvailable(uint8_t *data)
{
bool uart_data = false;
/* check for data */
if (BIT_CHECK(UCSR0A,RXC0)) {
*data = UDR0;
uart_data = true;
}
return uart_data;
}