diff --git a/bacnet-stack/ports/atmega168/dlmstp.c b/bacnet-stack/ports/atmega168/dlmstp.c index 433b9acc..31d6b43c 100644 --- a/bacnet-stack/ports/atmega168/dlmstp.c +++ b/bacnet-stack/ports/atmega168/dlmstp.c @@ -216,11 +216,6 @@ static uint8_t TransmitPacketDest; /* of a frame the node is transmitting: 20 bit times. */ #define Tframe_gap 20 -/* The maximum time after the end of the stop bit of the final */ -/* octet of a transmitted frame before a node must disable its */ -/* EIA-485 driver: 15 bit times. */ -#define Tpostdrive 15 - /* The maximum time a node may wait after reception of a frame that expects */ /* a reply before sending the first octet of a reply or Reply Postponed */ /* frame: 250 milliseconds. */ diff --git a/bacnet-stack/ports/atmega168/hardware.h b/bacnet-stack/ports/atmega168/hardware.h index c4411c57..50895531 100644 --- a/bacnet-stack/ports/atmega168/hardware.h +++ b/bacnet-stack/ports/atmega168/hardware.h @@ -25,16 +25,16 @@ #ifndef HARDWARE_H #define HARDWARE_H +/* The processor clock frequency */ +#define F_CPU (7372800) + #include #include +#include #include "avr035.h" #if !defined(__AVR_ATmega168__) #error Firmware is configured for ATmega168 only. #endif -/* The processor clock frequency */ -#define FREQ_CPU (7372800) - - #endif diff --git a/bacnet-stack/ports/atmega168/main.c b/bacnet-stack/ports/atmega168/main.c index 285faefa..de707913 100644 --- a/bacnet-stack/ports/atmega168/main.c +++ b/bacnet-stack/ports/atmega168/main.c @@ -36,10 +36,16 @@ /* For porting to IAR, see: http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/ +/* Notice: Fuse Bit Settings + + + + */ + + void init(void) { /* Initialize the Clock Prescaler for ATmega48/88/168 */ - /* The device is shipped with the CKDIV8 Fuse programmed */ /* The default CLKPSx bits are factory set to 0011 */ /* Enbable the Clock Prescaler */ CLKPR = _BV(CLKPCE); @@ -59,7 +65,7 @@ void init(void) /* Set the CLKPS3..0 bits to Prescaler of 1 */ CLKPR = 0; /* Initialize I/O ports */ - /* For Port DDRx (Data Direction) Input=1, Output=1 */ + /* For Port DDRx (Data Direction) Input=0, Output=1 */ /* For Port PORTx (Bit Value) TriState=0, High=1 */ DDRB = 0; PORTB = 0; @@ -79,15 +85,62 @@ void init(void) /* Configure Timer0 for millisecond timer */ Timer_Initialize(); + /* Set the LED ports OFF */ + BIT_SET(PORTD,PD4); + BIT_SET(PORTD,PD5); + /* Configure the LED ports as outputs */ + BIT_SET(DDRD,DDD4); + BIT_SET(DDRD,DDD5); + /* Enable global interrupts */ sei(); } +static uint8_t NPDU_Timer; + +static void NDPU_Timers(void) +{ + if (NPDU_Timer) { + NPDU_Timer--; + if (NPDU_Timer == 0) { + BIT_SET(PORTD,PD5); + } + } +} + +static void NPDU_LED_On(void) +{ + BIT_CLEAR(PORTD,PD5); + NPDU_Timer = 20; +} + void task_milliseconds(void) { while (Timer_Milliseconds) { Timer_Milliseconds--; /* add other millisecond timer tasks here */ + RS485_LED_Timers(); + NDPU_Timers(); + } +} + +static uint8_t Address_Switch; + +void input_switch_read(void) +{ + uint8_t value; + static uint8_t old_value = 0; + + value = BITMASK_CHECK(PINC,0x0F) | (BITMASK_CHECK(PINB,0x07)<<4); + if (value != old_value) { + old_value = value; + } else { + if (old_value != Address_Switch) { + Address_Switch = old_value; +#if defined(BACDL_MSTP) + dlmstp_set_mac_address(Address_Switch); +#endif + } } } @@ -111,7 +164,6 @@ int main(void) init(); #if defined(BACDL_MSTP) RS485_Set_Baud_Rate(38400); - dlmstp_set_mac_address(86); dlmstp_set_max_master(127); dlmstp_set_max_info_frames(1); #endif @@ -121,6 +173,7 @@ int main(void) iam_send(&Handler_Transmit_Buffer[0]); #endif for (;;) { + input_switch_read(); task_milliseconds(); /* other tasks */ /* BACnet handling */ @@ -129,6 +182,7 @@ int main(void) #if !defined(TEST_MSTP) npdu_handler(&src, &PDUBuffer[0], pdu_len); #endif + NPDU_LED_On(); } } diff --git a/bacnet-stack/ports/atmega168/rs485.c b/bacnet-stack/ports/atmega168/rs485.c index 4f822f62..d13adb99 100644 --- a/bacnet-stack/ports/atmega168/rs485.c +++ b/bacnet-stack/ports/atmega168/rs485.c @@ -37,6 +37,10 @@ #include "hardware.h" #include "timer.h" +/* Timers for turning off the TX,RX LED indications */ +static uint8_t LED1_Off_Timer; +static uint8_t LED3_Off_Timer; + /* baud rate */ static uint32_t RS485_Baud = 38400; @@ -52,6 +56,13 @@ static uint32_t RS485_Baud = 38400; #define Tturnaround (40UL) /* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */ +/* The maximum time after the end of the stop bit of the final */ +/* octet of a transmitted frame before a node must disable its */ +/* EIA-485 driver: 15 bit times. */ +/* NOTE: AVR lib delay_us limit is 768us; limit is 7bits/9600bps=729us */ +#define Tpostdrive1 (7UL) +#define Tpostdrive2 (7UL) + /**************************************************************************** * DESCRIPTION: Initializes the RS485 hardware and variables, and starts in * receive mode. @@ -75,8 +86,14 @@ void RS485_Initialize(void) /* 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 */ + /* Set port bit as Output - initially receiving */ + BIT_CLEAR(PORTD,PD2); BIT_SET(DDRD,DDD2); + /* Configure Transmit and Receive LEDs - initially off */ + BIT_SET(PORTD,PD6); + BIT_SET(PORTD,PD7); + BIT_SET(DDRD,DDD6); + BIT_SET(DDRD,DDD7); return; } @@ -113,7 +130,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud) /* 2x speed mode */ BIT_SET(UCSR0A,U2X0); /* configure baud rate */ - UBRR0 = (FREQ_CPU / (8UL * RS485_Baud)) - 1; + UBRR0 = (F_CPU / (8UL * RS485_Baud)) - 1; /* FIXME: store the baud rate */ break; default: @@ -153,11 +170,63 @@ void RS485_Transmitter_Enable(bool enable) { if (enable) { BIT_SET(PORTD,PD2); - } else { + } else { + #if Tpostdrive1 + _delay_us(Tpostdrive1/RS485_Baud); + #endif + #if Tpostdrive2 + _delay_us(Tpostdrive2/RS485_Baud); + #endif BIT_CLEAR(PORTD,PD2); } } +/**************************************************************************** +* DESCRIPTION: Timers for delaying the LED indicators going off +* RETURN: none +* ALGORITHM: none +* NOTES: expected to be called once a millisecond +*****************************************************************************/ +void RS485_LED_Timers(void) +{ + if (LED1_Off_Timer) { + LED1_Off_Timer--; + if (LED1_Off_Timer == 0) { + BIT_SET(PORTD,PD6); + } + } + if (LED3_Off_Timer) { + LED3_Off_Timer--; + if (LED3_Off_Timer == 0) { + BIT_SET(PORTD,PD7); + } + } +} + +/**************************************************************************** +* DESCRIPTION: Turn on the LED, and set the off timer to turn it off +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +static void RS485_LED1_On(void) +{ + BIT_CLEAR(PORTD,PD6); + LED1_Off_Timer = 20; +} + +/**************************************************************************** +* DESCRIPTION: Turn on the LED, and set the off timer to turn it off +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +static void RS485_LED3_On(void) +{ + BIT_CLEAR(PORTD,PD7); + LED3_Off_Timer = 20; +} + /**************************************************************************** * DESCRIPTION: Send some data and wait until it is sent * RETURN: none @@ -168,6 +237,7 @@ void RS485_Send_Data( uint8_t * buffer, /* data to send */ uint16_t nbytes) /* number of bytes of data */ { + RS485_LED3_On(); while (nbytes) { while (!BIT_CHECK(UCSR0A,UDRE0)) { /* do nothing - wait until Tx buffer is empty */ @@ -176,10 +246,15 @@ void RS485_Send_Data( buffer++; nbytes--; } + while (!BIT_CHECK(UCSR0A,UDRE0)) { + /* do nothing - wait until Tx buffer is empty */ + } + /* is the frame sent? */ while (!BIT_CHECK(UCSR0A,TXC0)) { /* do nothing - wait until the entire frame in the Transmit Shift Register has been shifted out */ } + BIT_CLEAR(UCSR0A,TXC0); /* per MSTP spec, sort of */ Timer_Silence_Reset(); } @@ -204,11 +279,12 @@ bool RS485_ReceiveError(void) if (BIT_CHECK(UCSR0A,DOR0)) { ReceiveError = true; } - /* flush the receive buffer */ if (ReceiveError) { - while (BIT_CHECK(UCSR0A,RXC0)) { + RS485_LED1_On(); + /* flush the receive buffer */ + do { dummy_data = UDR0; - } + } while (BIT_CHECK(UCSR0A,RXC0)); } return ReceiveError; @@ -222,15 +298,16 @@ bool RS485_ReceiveError(void) *****************************************************************************/ bool RS485_DataAvailable(uint8_t *data) { - bool uart_data = false; + bool DataAvailable = false; /* check for data */ if (BIT_CHECK(UCSR0A,RXC0)) { *data = UDR0; - uart_data = true; + DataAvailable = true; + RS485_LED1_On(); } - return uart_data; + return DataAvailable; } #ifdef TEST_RS485 diff --git a/bacnet-stack/ports/atmega168/rs485.h b/bacnet-stack/ports/atmega168/rs485.h index 7ab21eae..f14320c8 100644 --- a/bacnet-stack/ports/atmega168/rs485.h +++ b/bacnet-stack/ports/atmega168/rs485.h @@ -57,6 +57,8 @@ extern "C" { uint32_t RS485_Get_Baud_Rate(void); bool RS485_Set_Baud_Rate(uint32_t baud); + void RS485_LED_Timers(void); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/ports/atmega168/timer.c b/bacnet-stack/ports/atmega168/timer.c index f7b27877..18553b38 100644 --- a/bacnet-stack/ports/atmega168/timer.c +++ b/bacnet-stack/ports/atmega168/timer.c @@ -30,7 +30,7 @@ /* Prescaling: 1, 8, 64, 256, 1024 */ #define TIMER_PRESCALER 64 /* Count: Timer0 counts up to 0xFF and then signals overflow */ -#define TIMER_TICKS (FREQ_CPU/TIMER_PRESCALER/1000) +#define TIMER_TICKS (F_CPU/TIMER_PRESCALER/1000) #if (TIMER_TICKS > 0xFF) #error Timer Prescaler value is too small #endif