From 4646df1188d802daf98532d25f9b64f181d9f210 Mon Sep 17 00:00:00 2001 From: skarg Date: Wed, 20 Apr 2005 17:09:26 +0000 Subject: [PATCH] modified while adding pic18 support --- bacnet-stack/mstp.c | 18 +- bacnet-stack/mstp.h | 66 ++-- bacnet-stack/ports/pic18/bacnet.mcp | 69 +++-- bacnet-stack/ports/pic18/bacnet.mcw | Bin 25600 -> 25600 bytes bacnet-stack/ports/pic18/hardware.h | 250 +++++++++++++++ bacnet-stack/ports/pic18/init.c | 126 ++++++++ bacnet-stack/ports/pic18/init.h | 33 ++ bacnet-stack/ports/pic18/isr.c | 184 +++++++++++ bacnet-stack/ports/pic18/main.c | 91 +++--- bacnet-stack/ports/pic18/rs485.c | 463 ++++++++++++++++++++++------ bacnet-stack/ports/pic18/timer.c | 45 +++ bacnet-stack/ports/pic18/timer.h | 34 ++ bacnet-stack/rs485.h | 8 +- 13 files changed, 1183 insertions(+), 204 deletions(-) create mode 100644 bacnet-stack/ports/pic18/hardware.h create mode 100644 bacnet-stack/ports/pic18/init.c create mode 100644 bacnet-stack/ports/pic18/init.h create mode 100644 bacnet-stack/ports/pic18/isr.c create mode 100644 bacnet-stack/ports/pic18/timer.c create mode 100644 bacnet-stack/ports/pic18/timer.h diff --git a/bacnet-stack/mstp.c b/bacnet-stack/mstp.c index af85cac8..94956818 100644 --- a/bacnet-stack/mstp.c +++ b/bacnet-stack/mstp.c @@ -187,7 +187,7 @@ unsigned MSTP_Create_Frame( } void MSTP_Create_And_Send_Frame( - struct mstp_port_struct_t *mstp_port, // port to send from + volatile struct mstp_port_struct_t *mstp_port, // port to send from uint8_t frame_type, // type of frame to send - see defines uint8_t destination, // destination address uint8_t source, // source address @@ -210,7 +210,7 @@ void MSTP_Create_And_Send_Frame( } // Millisecond Timer - called every millisecond -void MSTP_Millisecond_Timer(struct mstp_port_struct_t *mstp_port) +void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t *mstp_port) { if (mstp_port->SilenceTimer < 255) mstp_port->SilenceTimer++; @@ -220,7 +220,7 @@ void MSTP_Millisecond_Timer(struct mstp_port_struct_t *mstp_port) return; } -void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port) +void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port) { switch (mstp_port->receive_state) { @@ -568,7 +568,7 @@ void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port) return; } -void MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port) +void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) { switch (mstp_port->master_state) @@ -1151,7 +1151,7 @@ void MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port) } void MSTP_Init( - struct mstp_port_struct_t *mstp_port, + volatile struct mstp_port_struct_t *mstp_port, uint8_t this_station_mac) { int i; //loop counter @@ -1200,7 +1200,7 @@ void MSTP_Init( // test stub functions void RS485_Send_Frame( - struct mstp_port_struct_t *mstp_port, // port specific data + 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) { @@ -1246,7 +1246,7 @@ static void Load_Input_Buffer(uint8_t *buffer,size_t len) } void RS485_Check_UART_Data( - struct mstp_port_struct_t *mstp_port) // port specific data + volatile struct mstp_port_struct_t *mstp_port) // port specific data { char *data; if (!Ringbuf_Empty(&Test_Buffer) && mstp_port && @@ -1263,7 +1263,7 @@ void RS485_Check_UART_Data( void testReceiveNodeFSM(Test* pTest) { - struct mstp_port_struct_t mstp_port; // port data + volatile struct mstp_port_struct_t mstp_port; // port data unsigned EventCount = 0; // local counter uint8_t my_mac = 0x05; // local MAC address uint8_t HeaderCRC = 0; // for local CRC calculation @@ -1652,7 +1652,7 @@ void testReceiveNodeFSM(Test* pTest) void testMasterNodeFSM(Test* pTest) { - struct mstp_port_struct_t mstp_port; // port data + volatile struct mstp_port_struct_t mstp_port; // port data uint8_t my_mac = 0x05; // local MAC address MSTP_Init(&mstp_port,my_mac); diff --git a/bacnet-stack/mstp.h b/bacnet-stack/mstp.h index 3bf96395..86d92350 100644 --- a/bacnet-stack/mstp.h +++ b/bacnet-stack/mstp.h @@ -93,76 +93,66 @@ typedef enum MSTP_MASTER_STATE_ANSWER_DATA_REQUEST } MSTP_MASTER_STATE; -// data for a given MS/TP port struct mstp_port_struct_t { MSTP_RECEIVE_STATE receive_state; // When a master node is powered up or reset, // it shall unconditionally enter the INITIALIZE state. MSTP_MASTER_STATE master_state; - - bool ReceiveError; // TRUE when error detected during Rx octet - - bool DataAvailable; // There is data in the buffer - - uint8_t DataRegister; // stores the latest data - + // A Boolean flag set to TRUE by the Receive State Machine + // if an error is detected during the reception of a frame. + // Set to FALSE by the main state machine. + unsigned ReceiveError:1; + // There is data in the buffer + unsigned DataAvailable:1; + unsigned FramingError:1; // TRUE if we got a framing error + unsigned ReceivedInvalidFrame:1; + // A Boolean flag set to TRUE by the Receive State Machine + // if a valid frame is received. + // Set to FALSE by the main state machine. + unsigned ReceivedValidFrame:1; + // A Boolean flag set to TRUE by the master machine if this node is the + // only known master node. + unsigned SoleMaster:1; + // After receiving a frame this value will be TRUE until Tturnaround + // has expired + unsigned Turn_Around_Waiting:1; + // stores the latest received data + uint8_t DataRegister; // Used to accumulate the CRC on the data field of a frame. uint16_t DataCRC; - // Used to store the data length of a received frame. unsigned DataLength; - // Used to store the destination address of a received frame. uint8_t DestinationAddress; - // Used to count the number of received octets or errors. // This is used in the detection of link activity. unsigned EventCount; - // Used to store the frame type of a received frame. uint8_t FrameType; - // The number of frames sent by this node during a single token hold. // When this counter reaches the value Nmax_info_frames, the node must // pass the token. unsigned FrameCount; - // Used to accumulate the CRC on the header of a frame. uint8_t HeaderCRC; - // Used as an index by the Receive State Machine, up to a maximum value of // InputBufferSize. unsigned Index; - - // An array of octets, used to store octets as they are received. // InputBuffer is indexed from 0 to InputBufferSize-1. // The maximum size of a frame is 501 octets. uint8_t InputBuffer[MAX_MPDU]; - // "Next Station," the MAC address of the node to which This Station passes // the token. If the Next_Station is unknown, Next_Station shall be equal to // This_Station. uint8_t Next_Station; - // "Poll Station," the MAC address of the node to which This Station last // sent a Poll For Master. This is used during token maintenance. uint8_t Poll_Station; - - // A Boolean flag set to TRUE by the Receive State Machine if an error is - // detected during the reception of a frame. Set to FALSE by the main - // state machine. - bool ReceivedInvalidFrame; - - // A Boolean flag set to TRUE by the Receive State Machine if a valid frame - // is received. Set to FALSE by the main state machine. - bool ReceivedValidFrame; - // A counter of transmission retries used for Token and Poll For Master // transmission. unsigned RetryCount; - // A timer with nominal 5 millisecond resolution used to measure and // generate silence on the medium between octets. It is incremented by a // timer process and is cleared by the Receive State Machine when activity @@ -177,10 +167,6 @@ struct mstp_port_struct_t // Machine when a Data Expecting Reply Answer activity is completed. unsigned ReplyPostponedTimer; - // A Boolean flag set to TRUE by the master machine if this node is the - // only known master node. - bool SoleMaster; - // Used to store the Source Address of a received frame. uint8_t SourceAddress; @@ -211,10 +197,6 @@ struct mstp_port_struct_t // less than or equal to 127. If Max_Master is not writable in a node, // its value shall be 127. unsigned Nmax_master; - - // After receiving a frame this value will be TRUE until Tturnaround - // has expired - bool Turn_Around_Waiting; }; #define DEFAULT_MAX_INFO_FRAMES 1 @@ -226,10 +208,10 @@ struct mstp_port_struct_t #define Tturnaround 40; void MSTP_Init( - struct mstp_port_struct_t *mstp_port, + volatile struct mstp_port_struct_t *mstp_port, uint8_t this_station_mac); -void MSTP_Millisecond_Timer(struct mstp_port_struct_t *mstp_port); -void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port); -void MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port); +void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t *mstp_port); +void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port); +void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port); #endif diff --git a/bacnet-stack/ports/pic18/bacnet.mcp b/bacnet-stack/ports/pic18/bacnet.mcp index 6c6e1d4a..e04a8f20 100644 --- a/bacnet-stack/ports/pic18/bacnet.mcp +++ b/bacnet-stack/ports/pic18/bacnet.mcp @@ -57,6 +57,11 @@ file_037=no file_038=no file_039=no file_040=no +file_041=no +file_042=no +file_043=no +file_044=no +file_045=no [FILE_INFO] file_000=rs485.c file_001=D:\bacnet-stack\whois.c @@ -75,30 +80,35 @@ file_013=D:\bacnet-stack\rp.c file_014=D:\bacnet-stack\abort.c file_015=D:\bacnet-stack\wp.c file_016=main.c -file_017=stdbool.h -file_018=stdint.h -file_019=D:\bacnet-stack\wp.h -file_020=D:\bacnet-stack\apdu.h -file_021=D:\bacnet-stack\bacdcode.h -file_022=D:\bacnet-stack\bacdef.h -file_023=D:\bacnet-stack\bacenum.h -file_024=D:\bacnet-stack\bacerror.h -file_025=D:\bacnet-stack\bigend.h -file_026=D:\bacnet-stack\bits.h -file_027=D:\bacnet-stack\bytes.h -file_028=D:\bacnet-stack\config.h -file_029=D:\bacnet-stack\crc.h -file_030=D:\bacnet-stack\device.h -file_031=D:\bacnet-stack\iam.h -file_032=D:\bacnet-stack\mstp.h -file_033=D:\bacnet-stack\npdu.h -file_034=D:\bacnet-stack\reject.h -file_035=D:\bacnet-stack\ringbuf.h -file_036=D:\bacnet-stack\rp.h -file_037=D:\bacnet-stack\rs485.h -file_038=D:\bacnet-stack\whois.h -file_039=D:\bacnet-stack\abort.h -file_040=18f252.lkr +file_017=init.c +file_018=isr.c +file_019=timer.c +file_020=stdbool.h +file_021=stdint.h +file_022=D:\bacnet-stack\wp.h +file_023=D:\bacnet-stack\apdu.h +file_024=D:\bacnet-stack\bacdcode.h +file_025=D:\bacnet-stack\bacdef.h +file_026=D:\bacnet-stack\bacenum.h +file_027=D:\bacnet-stack\bacerror.h +file_028=D:\bacnet-stack\bigend.h +file_029=D:\bacnet-stack\bits.h +file_030=D:\bacnet-stack\bytes.h +file_031=D:\bacnet-stack\config.h +file_032=D:\bacnet-stack\crc.h +file_033=D:\bacnet-stack\device.h +file_034=D:\bacnet-stack\iam.h +file_035=D:\bacnet-stack\mstp.h +file_036=D:\bacnet-stack\npdu.h +file_037=D:\bacnet-stack\reject.h +file_038=D:\bacnet-stack\ringbuf.h +file_039=D:\bacnet-stack\rp.h +file_040=D:\bacnet-stack\rs485.h +file_041=D:\bacnet-stack\whois.h +file_042=D:\bacnet-stack\abort.h +file_043=init.h +file_044=timer.h +file_045=18f252.lkr [SUITE_INFO] suite_guid={5B7D72DD-9861-47BD-9F60-2BE967BF8416} suite_state= @@ -107,6 +117,17 @@ TS{DD2213A8-6310-47B1-8376-9430CDFC013F}= TS{BFD27FBA-4A02-4C0E-A5E5-B812F3E7707C}=/m"$(BINDIR_)$(TARGETBASE).map" /o"$(TARGETBASE).cof" TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}= TS{ADE93A55-C7C7-4D4D-A4BA-59305F7D0391}= +TS{DD2213A8-6310-47B1-8376-9430CDFC013F}009= +TS{BFD27FBA-4A02-4C0E-A5E5-B812F3E7707C}009=/o"$(TARGETBASE).cof" +TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}009=-Ou- -Ot- -Ob- -Op- -Or- -Od- -Opa- +TS{ADE93A55-C7C7-4D4D-A4BA-59305F7D0391}009= +TS{DD2213A8-6310-47B1-8376-9430CDFC013F}016= +TS{BFD27FBA-4A02-4C0E-A5E5-B812F3E7707C}016=/o"$(TARGETBASE).cof" +TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}016=-Ou- -Ot- -Ob- -Op- -Or- -Od- -Opa- +TS{ADE93A55-C7C7-4D4D-A4BA-59305F7D0391}016= +[ACTIVE_FILE_SETTINGS] +TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}009_active=yes +TS{C2AF05E7-1416-4625-923D-E114DB6E2B96}016_active=yes [TOOL_LOC_STAMPS] tool_loc{96C98149-AA1B-4CF9-B967-FAE79CAB663C}=D:\mcc18\bin\mplink.exe tool_loc{E56A1C86-9D32-4DF6-8C34-FE0388B1B644}=D:\mcc18\bin\mcc18.exe diff --git a/bacnet-stack/ports/pic18/bacnet.mcw b/bacnet-stack/ports/pic18/bacnet.mcw index 620f20e3032119a51917b382b92c9571cd80b2c3..2c99b49dfa9fd6426820271b2d56ecb6370c5afe 100644 GIT binary patch delta 1892 zcmb7Fe@L8l7=OO^YnOSZcREjGn?E)ho;zKrlkHa5)UXoPBHb~JojV1gO}6vg3-Z!y z;lN7h*lS<~O&WpFEZ0l4V6ht+lZfySqv$VhxDXno>({xQ*XQ}Zck}4KzVO`p{P;XS zzt8*L$h;Vt7qiza_RVxUy?OOmi@0bzT~HYQ<=N|P-v}!a1q<|H+pA)~v2J@ya%{{l0#$z#=y_sKT8=-vyaFJ|7f&|zyjQv+N3g$0`8#Y3+S5p zB~UHs9oV=C#+5wdQ#d)>FQw|F4@X+r^vHsl&mOPerxb(OFZVFkJQ~qW1j;Is`;s#F z6s$a#GVws-K9GG9U0L6n%pCk)sWuCfApA^a7@j0giwk94Zmb`CW&=`>{4&Wb0)Me% z%dpeyQ+WIgN_5F;6EQ~_xghTbc{^sTx0bf6xia(Bppi8<9Zhc8wn2v@{X>D1#BnnH zP=yL`;)xlnqb8+{fuFaVJW-qy;PqHupwRn9u^GeRA#u-5dLl2N^%uk`)N{r9ek7^z z^DCs}K?|x5=m4yX7CyRC=BjJ_Xps>C-v(C z&C-}s60q~(BDRCVD41V)v!FP6x5cGAx%{!U88#Z>cf~9yo1+;r=U^-yI%09Xhyd;1 zcUd^-GMv_4x~&B5HmZR9t=%neSnmCEZ~#qAVVoJB@hc!6aqn8Cdbc;JET8x2MXn}Y zxHKV**IbIQ1T4n=f?*-5jG@9E7R^KLAC{3F<+Y=sdJs2wxrL`nbQiKwz7G>8QvWh- zh5Y8r*UUX9Q; VEb8;dT==?h9Ins9F)E9P#lL7_9uWWl delta 2215 zcmeHJQD|Fb6h42FW?5~z_9l&e=w>oI2(@GpyDe+0jUx|LOShq0qvRo3x><+Tu%%uN zKf6&UT(;rVyT>90Uj`EmT#+IZI+)vF4Eiwer4McKVc>*KyEe|Y@jEv+Yd1xF@X;R* z|2gMB=ltjV-}(Q0i`PW)nkY>=Hb#kPwNk09nwK0GMB~Iyx$8Th|3NsRjyD+v*9p;Q z{_Z+0jFXOFLr2XR4o1lx4ef@a8`J~p1w9LT4%7#-qJFx+5_dz`JC@Il(Xq_v>PpCHpAMN;oUUdG)p{N*~lYNkGNa552&+ zxu_6t7T#9fO#e-xS6Aj$A|HEG_>`YG-0XrvIHf&wbv7WqP^=%g|n>=qfo!Isq>yKiWODJ zvT97#_Zs8gpwG4|FS8C131Q>JM(GV zIEb0`#h_y!tJr5dC{3i%Mlh9%Q)BSC$~dr|0Y8l(eMK~sotPPKZSMqt45 ztxx)$Wt>d01^gqy%C%sw$7SM0ok~b3e4^T3DexsU?K`NJhYp)0bS$&&8St^LR&v{? z9gRR>#RwL3w~vDMX0`hmh0OPnVS$~|?Cmy$R}&8NeXlAUd6#*=u^_}#=2+8a$0olO zi%*Q9bXnamI3>_Hh%exymv96-yb1d8s}?zYH)NG`@pYdCp!e$*$(3;GQ=tU0p8adL zsSSJ8qqeMTKigS4-Q zpPnk{?8F;Cd07jGU zP6%bbQyA-?yAoob3aur07Cc{*vRxQIm3(q6mzP3P!k$l>Pu$zyC5?e(r&BH|#)sbB z+m6w3>Y^C!uwG}P4CUbde*^rb0kr?J0UrK-{VPBZ{sW@iDLnY2HvvlGvT>L4n1Q?> z)C^r11mJ01M;KaiJHGO)P2fKvMTgJ=S+kNH6=vbJ(@qaut?^kpUl#}G!rSqZc{zPi Jm{EUG{0U4toh|?X diff --git a/bacnet-stack/ports/pic18/hardware.h b/bacnet-stack/ports/pic18/hardware.h new file mode 100644 index 00000000..5e199106 --- /dev/null +++ b/bacnet-stack/ports/pic18/hardware.h @@ -0,0 +1,250 @@ +/************************************************************************** +* +* Copyright (C) 2003 Mark Norton and Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* Functional +* Description: Defines the hardware implementation for the Microchip +* microprocessor used in the Synergy lighting control project. +* +*********************************************************************/ +#ifndef HARDWARE_H +#define HARDWARE_H + +#include +#include +#include + +/**************************************************************************** + * Card IO * + ****************************************************************************/ +/* + TRIS masks are: + 0 = OUTPUT + 1 = INPUT + + The IO on this card is as follows: + RA0 - SDA - SEEPROM (input) + RA1 - SCL - SEEPROM (input) + RA2 - not used (input) + RA3 - not used (input) + RA4 - LK2a - jumper (input) + RA5 - LK2b - jumper (input) + + TRISA - 0011 1111 - 3Fh + + RB0 - INT - Zero Cross Interrupt (input) + RB1 - LED - I2C Bus Indication (output) + RB2 - LED - Labeled 'DATA' (output) + RB3 - not used (input) + RB4 - CTS input for RS-232 (not used unless LT1180A chip is there) + RB5 - RTS output for RS-232 (not used unless LT1180A chip is there) + RB6 - PGC - in circuit programming (input) + RB7 - PGD - in circuit programming (input) + + TRISB - 1101 1001 - D9h + + RC0 - QH of 74165 shift register (input) + RC1 - SHIFTREG_CKL of 74165 shift register (output) + RC2 - SHIFTREG_LOAD of 74165 shift register (output) + RC3 - SCL for I2C bus (input) + RC4 - SDA for I2C bus (input) + RC5 - RS-485 TXEN (or RS232) (output) + RC6 - RS-485 TXD (or RS232) (output) + RC7 - RS-485 RXD (or RS232) (input) + + TRISC - 1001 1001 - 99h + +*/ + +#define PORT_A_TRIS_MASK 0x3F +#define PORT_B_TRIS_MASK 0xD9 +#define PORT_C_TRIS_MASK 0x99 + +/* hardware mapping of functionality */ +#define DATA_LED_ON() PORTBbits.RB2=0 +#define DATA_LED_OFF() PORTBbits.RB2=1 + +#define ABUS_LED_ON() PORTBbits.RB1=0 +#define ABUS_LED_OFF() PORTBbits.RB1=1 + +#define RS485_TRANSMIT_DISABLE() PORTCbits.RC5=0 +#define RS485_TRANSMIT_ENABLE() PORTCbits.RC5=1 + +/* note: board is inverted logic */ +#define JUMPER_LK2_TOP_OFF() PORTAbits.RA4 +#define JUMPER_LK2_TOP_ON() (!PORTAbits.RA4) +#define JUMPER_LK2_BOTTOM_OFF() PORTAbits.RA5 +#define JUMPER_LK2_BOTTOM_ON() (!PORTAbits.RA5) + +#define ZERO_CROSS PORTBbits.RB0 + +#define I2C_CLK_LATCH LATCbits.LATC3 +#define I2C_DATA_LATCH LATCbits.LATC4 +#define I2C_CLK PORTCbits.RC3 +#define I2C_DATA PORTCbits.RC4 +#define I2C_CLK_HI_Z TRISCbits.TRISC3 +#define I2C_SDA_HI_Z TRISCbits.TRISC4 + +#define EEPROM_DATA_LATCH LATAbits.LATA0 +#define EEPROM_CLK_LATCH LATAbits.LATA1 +#define EEPROM_SDA PORTAbits.RA0 +#define EEPROM_CLK PORTAbits.RA1 +#define EEPROM_SDA_HI_Z TRISAbits.TRISA0 +#define EEPROM_CLK_HI_Z TRISAbits.TRISA1 + +#define SHIFTREG_LOAD PORTCbits.RC2 +#define SHIFTREG_CLK PORTCbits.RC1 +#define SHIFTREG_DATA PORTCbits.RC0 + +#define NO_ANALOGS 0x06 // None +#define ALL_ANALOG 0x00 // RA0 RA1 RA2 RA3 RA5 RE0 RE1 RE2 Ref=Vdd +#define ANALOG_RA3_REF 0x01 // RA0 RA1 RA2 RA5 RE0 RE1 RE2 Ref=RA3 +#define A_ANALOG 0x02 // RA0 RA1 RA2 RA3 RA5 Ref=Vdd +#define A_ANALOG_RA3_REF 0x03 // RA0 RA1 RA2 RA5 Ref=RA3 +#define RA0_RA1_RA3_ANALOG 0x04 // RA0 RA1 RA3 Ref=Vdd +#define RA0_RA1_ANALOG_RA3_REF 0x05 // RA0 RA1 Ref=RA3 + +#define ANALOG_RA3_RA2_REF 0x08 +#define ANALOG_NOT_RE1_RE2 0x09 +#define ANALOG_NOT_RE1_RE2_REF_RA3 0x0A +#define ANALOG_NOT_RE1_RE2_REF_RA3_RA2 0x0B +#define A_ANALOG_RA3_RA2_REF 0x0C +#define RA0_RA1_ANALOG_RA3_RA2_REF 0x0D +#define RA0_ANALOG 0x0E +#define RA0_ANALOG_RA3_RA2_REF 0x0F + +// Constants used for SETUP_ADC() are: +#define ADC_OFF 0 +#define ADC_START 4 +#define ADC_CLOCK_DIV_2 1 +#define ADC_CLOCK_DIV_4 0x101 +#define ADC_CLOCK_DIV_8 0x41 +#define ADC_CLOCK_DIV_16 0x141 +#define ADC_CLOCK_DIV_32 0x81 +#define ADC_CLOCK_DIV_64 0x181 +#define ADC_CLOCK_INTERNAL 0xc1 +#define ADC_DONE_MASK 0x04 + +#define SET_ADC_CHAN(x) ADCON0 = (ADC_CLOCK_DIV_32 | ((x) << 3)) + +#define T1_DISABLED 0 +#define T1_INTERNAL 0x85 +#define T1_EXTERNAL 0x87 +#define T1_EXTERNAL_SYNC 0x83 + +#define T1_CLK_OUT 8 + +#define T1_DIV_BY_1 0 +#define T1_DIV_BY_2 0x10 +#define T1_DIV_BY_4 0x20 +#define T1_DIV_BY_8 0x30 +#define SETUP_TIMER1(mode) T1CON = (mode) + +#define T2_DISABLED 0 +#define T2_DIV_BY_1 4 +#define T2_DIV_BY_4 5 +#define T2_DIV_BY_16 6 +#define SETUP_TIMER2(mode, period, postscale) \ +{ \ + T2CON = ((mode) | ((postscale)-1)<<3); \ + PR2 = (period); \ +} + +#define T3_DISABLED 0 +#define T3_INTERNAL 0x85 +#define T3_EXTERNAL 0x87 +#define T3_EXTERNAL_SYNC 0x83 + +#define T3_DIV_BY_1 0 +#define T3_DIV_BY_2 0x10 +#define T3_DIV_BY_4 0x20 +#define T3_DIV_BY_8 0x30 +#define SETUP_TIMER3(mode) T3CON = (mode) + +#define CCP_OFF 0 +#define CCP_CAPTURE_FE 4 +#define CCP_CAPTURE_RE 5 +#define CCP_CAPTURE_DIV_4 6 +#define CCP_CAPTURE_DIV_16 7 +#define CCP_COMPARE_SET_ON_MATCH 8 +#define CCP_COMPARE_CLR_ON_MATCH 9 +#define CCP_COMPARE_INT 0xA +#define CCP_COMPARE_RESET_TIMER 0xB +#define CCP_PWM 0xC +#define CCP_PWM_PLUS_1 0x1c +#define CCP_PWM_PLUS_2 0x2c +#define CCP_PWM_PLUS_3 0x3c +#define SETUP_CCP1(mode) CCP1CON = (mode) +#define SETUP_CCP2(mode) CCP2CON = (mode) + +#define WATCHDOG_TIMER() \ +{ \ + _asm \ + CLRWDT \ + _endasm \ +} + +#define GLOBAL_INT_ENABLE() INTCONbits.GIE = 1 +#define GLOBAL_INT_DISABLE() INTCONbits.GIE = 0 + +#define PERIPHERAL_INT_ENABLE() INTCONbits.PEIE = 1 +#define PERIPHERAL_INT_DISABLE() INTCONbits.PEIE = 0 + +#define TIMER0_INT_ENABLE() INTCONbits.TMR0IE = 1 +#define TIMER0_INT_DISABLE() INTCONbits.TMR0IE = 0 + +#define TIMER2_INT_ENABLE() PIE1bits.TMR2IE = 1 +#define TIMER2_INT_DISABLE() PIE1bits.TMR2IE = 0 + +#define CCP2_INT_ENABLE() PIE2bits.CCP2IE = 1 +#define CCP2_INT_DISABLE() PIE2bits.CCP2IE = 0 + +#define CCP1_INT_ENABLE() PIE1bits.CCP1IE = 1 +#define CCP1_INT_DISABLE() PIE1bits.CCP1IE = 0 + +#define ABUS_INT_ENABLE() PIE1bits.SSPIE = 1 +#define ABUS_INT_DISABLE() PIE1bits.SSPIE = 0 +#define ABUS_INT_FLAG_CLEAR() PIR1bits.SSPIF = 0 + +#define USART_RX_INT_DISABLE() PIE1bits.RCIE = 0 +#define USART_RX_INT_ENABLE() PIE1bits.RCIE = 1 + +#define USART_TX_INTERRUPT() PIE1bits.TXIE +#define USART_TX_INT_DISABLE() PIE1bits.TXIE = 0 +#define USART_TX_INT_ENABLE() PIE1bits.TXIE = 1 +#define USART_TX_ENABLE() TXSTAbits.TXEN = 1 +#define USART_TX_INT_FLAG_CLEAR() PIR1bits.TXIF = 0 +#define USART_TX_EMPTY() TXSTAbits.TRMT +#define USART_CONTINUOUS_RX_ENABLE() RCSTAbits.CREN = 1 +#define USART_CONTINUOUS_RX_DISABLE() RCSTAbits.CREN = 0 +#define USART_RX_COMPLETE() PIR1bits.RCIF +#define USART_RX_STATUS() RCSTAbits +#define USART_RX_STATUS() RCSTAbits +#define USART_TRANSMIT(x) TXREG = (x) +#define USART_RECEIVE() RCREG +#define USART_RX_FRAME_ERROR() rcstabits.FERR +// combine the sequence correctly +#define USART_RX_SETUP() PIE1bits.RCIE = 1; RCSTAbits.CREN = 1 +#define USART_TX_SETUP() PIE1bits.TXIE = 1; TXSTAbits.TXEN = 1 + + +#endif /* HARDWARE_H */ diff --git a/bacnet-stack/ports/pic18/init.c b/bacnet-stack/ports/pic18/init.c new file mode 100644 index 00000000..7fc5026f --- /dev/null +++ b/bacnet-stack/ports/pic18/init.c @@ -0,0 +1,126 @@ +/************************************************************************** +* +* Copyright (C) 2003 Mark Norton +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* Functional +* Description: Handles the init code for the Microchip microprocessor +* +*********************************************************************/ +#include +#include +#include "hardware.h" + +// define this to enable ICD - debugger +//#define USE_ICD +// ------------------------- Configuration Bits ---------------------------- +#pragma romdata CONFIG +#ifdef USE_ICD +_CONFIG_DECL ( + _CONFIG1H_DEFAULT & _OSCS_OFF_1H & _OSC_HS_1H, + _CONFIG2L_DEFAULT & _BOR_ON_2L & _BORV_27_2L & _PWRT_ON_2L, + _CONFIG2H_DEFAULT & _WDT_OFF_2H & _WDTPS_128_2H, + _CONFIG3H_DEFAULT & _CCP2MUX_OFF_3H, + _CONFIG4L_DEFAULT & _STVR_ON_4L & _LVP_OFF_4L & _DEBUG_ON_4L, + _CONFIG5L_DEFAULT & _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L , + _CONFIG5H_DEFAULT & _CPB_OFF_5H & _CPD_OFF_5H, + _CONFIG6L_DEFAULT & _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L , + _CONFIG6H_DEFAULT & _WPC_OFF_6H & _WPB_OFF_6H & _WPD_OFF_6H, + _CONFIG7L_DEFAULT & _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L, + _CONFIG7H_DEFAULT & _EBTRB_OFF_7H); +#else +_CONFIG_DECL ( + _CONFIG1H_DEFAULT & _OSCS_OFF_1H & _OSC_HS_1H, + _CONFIG2L_DEFAULT & _BOR_ON_2L & _BORV_27_2L & _PWRT_ON_2L, + _CONFIG2H_DEFAULT & _WDT_ON_2H & _WDTPS_128_2H, + _CONFIG3H_DEFAULT & _CCP2MUX_OFF_3H, + _CONFIG4L_DEFAULT & _STVR_ON_4L & _LVP_OFF_4L & _DEBUG_OFF_4L, + _CONFIG5L_DEFAULT & _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L , + _CONFIG5H_DEFAULT & _CPB_OFF_5H & _CPD_OFF_5H, + _CONFIG6L_DEFAULT & _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L , + _CONFIG6H_DEFAULT & _WPC_OFF_6H & _WPB_OFF_6H & _WPD_OFF_6H, + _CONFIG7L_DEFAULT & _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L, + _CONFIG7H_DEFAULT & _EBTRB_OFF_7H); + +#endif // USE_ICD +#pragma romdata + +/**************************************************************************** +* DESCRIPTION: Initializes the PIC, its timers, WDT, etc. +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void init_hardware(void) +{ + // If the processor gets a power on reset then we can do something. + // We should not get a reset unless there has been + // some kind of power line disturbance. + if (RCONbits.POR) + { + //do something special! + } + + GLOBAL_INT_DISABLE(); + + /* Setup PORT A */ + TRISA=PORT_A_TRIS_MASK; + + /* PORT A can have analog inputs or digital IO */ + ADCON1 = NO_ANALOGS; + + /* Setup PORT B */ + TRISB=PORT_B_TRIS_MASK; + + /* Setup PORT C */ + TRISC=PORT_C_TRIS_MASK; + + /* setup zero cross interrupt to trigger on a low to high edge */ + INTCON2bits.INTEDG0 = 1; + + // setup ABUS + //ABUS_LED_OFF(); + //SSPADD = ABUS_DEFAULT_ADDR; + //SSPCON1 = (ABUS_SLAVE_MASK | ABUS_CLK_ENABLE | ABUS_MODE_SETUP); + //ABUS_Clear_SSPBUF(); + + // setup timer2 to reset every 1ms + CloseTimer2(); + PR2 = 250; + OpenTimer2(T2_PS_1_4 & T2_POST_1_5 & 0x7F); + + // Setup our interrupt priorities ---------> all low priority + RCONbits.IPEN = 1; + IPR1 = 0; + IPR2 = 0; + INTCON2bits.TMR0IP = 0; + INTCON2bits.RBIP = 0; + INTCON3 = 0; + + /* Enable interrupts */ + TIMER2_INT_ENABLE(); + PERIPHERAL_INT_ENABLE(); + GLOBAL_INT_ENABLE(); + +// Turn on the Zero cross interrupt + INTCONbits.INT0F = 0; + INTCONbits.INT0E = 1; +} \ No newline at end of file diff --git a/bacnet-stack/ports/pic18/init.h b/bacnet-stack/ports/pic18/init.h new file mode 100644 index 00000000..b7d4dabb --- /dev/null +++ b/bacnet-stack/ports/pic18/init.h @@ -0,0 +1,33 @@ +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +#ifndef INIT_H +#define INIT_H + +void init_hardware(void); + + + +#endif diff --git a/bacnet-stack/ports/pic18/isr.c b/bacnet-stack/ports/pic18/isr.c new file mode 100644 index 00000000..1bc33fa9 --- /dev/null +++ b/bacnet-stack/ports/pic18/isr.c @@ -0,0 +1,184 @@ +/************************************************************************** +* +* Copyright (C) 2003 Mark Norton and Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* Functional +* Description: Defines the interrupt service routines (ISR) for the +* Microchip microprocessor used in the Synergy lighting +* control project. +* +*********************************************************************/ +#include +#include "hardware.h" +#include "timer.h" + +// interrupt service routines +extern void RS485_Receive_Interrupt(void); +extern void RS485_Transmit_Interrupt(void); + +/**************************************************************************** +* DESCRIPTION: High priority interrupt routine +* PARAMETERS: none +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +#pragma interruptlow InterruptHandlerLow save=PROD, section(".tmpdata") +void InterruptHandlerLow(void) +{ + // check for timer0 interrupt + if((INTCONbits.TMR0IF) && (INTCONbits.TMR0IE)) + { + // clear interrupt flag + INTCONbits.TMR0IF = 0; + // call interrupt handler + } + //check for timer1 interrupt + if ((PIR1bits.TMR1IF) && (PIE1bits.TMR1IE)) + { + PIR1bits.TMR1IF = 0; + // call interrupt handler + } + //check for timer2 interrupt + if ((PIR1bits.TMR2IF) && (PIE1bits.TMR2IE)) + { + PIR1bits.TMR2IF = 0; + Timer_Millisecond_Interrupt(); + } + //check for timer3 interrupt + if ((PIR2bits.TMR3IF) && (PIE2bits.TMR3IE)) + { + PIR2bits.TMR3IF = 0; + // call interrupt handler + } + //check for compare 1 int + if ((PIR1bits.CCP1IF) && (PIE1bits.CCP1IE)) + { + PIR1bits.CCP1IF = 0; + // call interrupt handler + } + //check for compare 2 int + if ((PIR2bits.CCP2IF) && (PIE2bits.CCP2IE)) + { + PIR2bits.CCP2IF = 0; + // call interrupt handler + } + //check for USART Rx int + if ((PIR2bits.EEIF) && (PIE2bits.EEIE)) + { + PIR2bits.EEIF = 0; //clear interrupt flag + EECON1bits.WREN = 0; // disable writes + // call interrupt handler + } + //check for USART Tx int + if ((PIR1bits.TXIF) && (PIE1bits.TXIE)) + { + // call interrupt handler + RS485_Transmit_Interrupt(); + } + //check for USART Rx int + if ((PIR1bits.RCIF) && (PIE1bits.RCIE)) + { + // call interrupt handler + RS485_Receive_Interrupt(); + } + //check for AD int + if ((PIR1bits.ADIF) && (PIE1bits.ADIE)) + { + // call interrupt handler + PIR1bits.ADIF = 0; + } + //check for I2C receive int (MSSP int) + if ((PIR1bits.SSPIF) && (PIE1bits.SSPIE)) + { + PIR1bits.SSPIF = 0; + // call interrupt handler + } + + return; +} + +/**************************************************************************** +* DESCRIPTION: High priority interrupt routine +* PARAMETERS: none +* RETURN: none +* ALGORITHM: none +* NOTES: don't call functions from this function because registers are +* not saved, and saving registers is slower. +*****************************************************************************/ +#pragma interrupt InterruptHandlerHigh +void InterruptHandlerHigh(void) +{ + //check for external int + if ((INTCONbits.INT0IF) && (INTCONbits.INT0IE)) + { + /* Test to ensure that we are not getting a false trigger on the + falling edge. Only trigger on Rising edge. */ + if (ZERO_CROSS) + { + // timer used to determine when power is gone (no zero crosses) +// Power_Timeout = 30; +// if (ABUS_Current_Status.Zerox_Fail) +// { +// ABUS_Flags.SendStatus = TRUE; +// ABUS_Current_Status.Zerox_Fail = FALSE; +// } + // if we get here it means power is good +// System_Flags.PowerFail = FALSE; + } + INTCONbits.INT0IF = 0; + } + return; +} + +/**************************************************************************** +* DESCRIPTION: High priority interrupt vector +* PARAMETERS: none +* RETURN: none +* ALGORITHM: none +* NOTES: ISRs not here because we would only have 0x10 bytes for code +*****************************************************************************/ +#pragma code InterruptVectorHigh = 0x08 +void InterruptVectorHigh(void) +{ + _asm + goto InterruptHandlerHigh //jump to interrupt routine + _endasm +} +#pragma code + +/**************************************************************************** +* DESCRIPTION: Low priority interrupt vector +* PARAMETERS: none +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +#pragma code InterruptVectorLow = 0x18 +void InterruptVectorLow(void) +{ + _asm + goto InterruptHandlerLow //jump to interrupt routine + _endasm +} +#pragma code + diff --git a/bacnet-stack/ports/pic18/main.c b/bacnet-stack/ports/pic18/main.c index 1b5a78d9..ddc1b73b 100644 --- a/bacnet-stack/ports/pic18/main.c +++ b/bacnet-stack/ports/pic18/main.c @@ -1,37 +1,27 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2004 Steve Karg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307 - USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ #include #include @@ -40,24 +30,53 @@ #include "crc.h" #include "rs485.h" #include "ringbuf.h" +#include "init.h" +#include "timer.h" +#include "hardware.h" -static struct mstp_port_struct_t MSTP_Port; // port data +volatile struct mstp_port_struct_t MSTP_Port; // port data static uint8_t MSTP_MAC_Address = 0x05; // local MAC address +/**************************************************************************** +* DESCRIPTION: Handles our calling our module level milisecond counters +* PARAMETERS: none +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +static void Check_Timer_Milliseconds(void) +{ + // We might have missed some so keep doing it until we have got them all + while (Milliseconds) + { + MSTP_Millisecond_Timer(&MSTP_Port); + Milliseconds--; + } +} + + int main(void) { - + init_hardware(); + RS485_Initialize(); MSTP_Init(&MSTP_Port,MSTP_MAC_Address); // loop forever for (;;) { + WATCHDOG_TIMER(); + // input + Check_Timer_Milliseconds(); + // note: also called by RS-485 Receive ISR RS485_Check_UART_Data(&MSTP_Port); MSTP_Receive_Frame_FSM(&MSTP_Port); + // process + // output + RS485_Process_Tx_Message(); MSTP_Master_Node_FSM(&MSTP_Port); } diff --git a/bacnet-stack/ports/pic18/rs485.c b/bacnet-stack/ports/pic18/rs485.c index 19e3e107..d30f721c 100644 --- a/bacnet-stack/ports/pic18/rs485.c +++ b/bacnet-stack/ports/pic18/rs485.c @@ -1,37 +1,27 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2004 Steve Karg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307 - USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ // The module handles sending data out the RS-485 port // and handles receiving data from the RS-485 port. @@ -39,76 +29,367 @@ #include #include #include - +#include "hardware.h" #include "mstp.h" -// Transmits a Frame on the wire +// public port info +extern volatile struct mstp_port_struct_t MSTP_Port; + +static uint32_t RS485_Baud_Rate = 9600; + +// UART transmission buffer and index +static volatile uint8_t RS485_Tx_Buffer[MAX_MPDU]; +static volatile uint8_t RS485_Tx_Index = 0; +static volatile uint8_t RS485_Tx_Length = 0; +static volatile char RS485_Tx_Postdrive_Delay = 0; +static struct +{ + unsigned TransmitStart:1; // TRUE if we are requested to transmit + unsigned TransmitComplete:1; // TRUE if we are finished transmitting frame +} RS485_Flags; + +// Duplicate of the RCSTA reg used due to the double buffering of the +// fifo. Reading the RCREG reg will cause the second RCSTA reg to be +// loaded if there is one. */ +struct _rcstabits +{ + unsigned char RX9D:1; + unsigned char OERR:1; + unsigned char FERR:1; + unsigned char ADDEN:1; + unsigned char CREN:1; + unsigned char SREN:1; + unsigned char RX9:1; + unsigned char SPEN:1; +}; + +volatile static enum +{ + RS485_STATE_IDLE = 0, + RS485_STATE_RX_DATA = 1, + RS485_STATE_RX_CHECKSUM = 2, + RS485_STATE_RX_PROCESS = 3, + RS485_STATE_TX_DATA = 4, + RS485_STATE_WAIT_FOR_ACK = 5, + RS485_STATE_WAIT_COMPLETE = 6, + RS485_STATE_TX_GLOBAL_ACK = 7, + RS485_STATE_TX_POSTDRIVE_DELAY = 8, + RS485_STATE_ERROR = 9, + RS485_STATE_RX_TEST = 10, + RS485_STATE_RX_TEST_EEPROM = 11, + RS485_STATE_RX_TEST_DELAY = 12, + RS485_STATE_TX_TEST_WAIT = 13, + RS485_STATE_TX_TEST = 14 +} RS485_State; + +/**************************************************************************** +* DESCRIPTION: Transmits a frame using the UART +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ void RS485_Send_Frame( - struct mstp_port_struct_t *mstp_port, // port specific data + 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) { - uint8_t HeaderCRC; // used for running CRC calculation + // do we check for tx buffer in-use? + // Or do we just stop the in-progress transmission? + // Drop any transmission in progress, but don't worry about + // cleaning up the hardware - the start routine will handle that - (void)buffer; // FIXME: temp until we implement this code - (void)nbytes; // FIXME: temp until we implement this code - - // in order to avoid line contention - //while (mstp_port->SilenceTimer < Tturnaround) - //{ - // wait, yield, or whatever - //} - - // Disable the receiver, and enable the transmit line driver. - - // Transmit the preamble octets X'55', X'FF'. - // As each octet is transmitted, set SilenceTimer to zero. - - HeaderCRC = 0xFF; - - // Transmit the Frame Type, Destination Address, Source Address, - // and Data Length octets. Accumulate each octet into HeaderCRC. - // As each octet is transmitted, set SilenceTimer to zero. - - // Transmit the ones-complement of HeaderCRC. Set SilenceTimer to zero. - - // If there are data octets, initialize DataCRC to X'FFFF'. - - // Transmit any data octets. Accumulate each octet into DataCRC. - // As each octet is transmitted, set SilenceTimer to zero. - - // Transmit the ones-complement of DataCRC, least significant octet first. - // As each octet is transmitted, set SilenceTimer to zero. - - // Wait until the final stop bit of the most significant CRC octet - // has been transmitted but not more than Tpostdrive. - - // Disable the transmit line driver. + // Disable the interrupt since it depends on the global transmit buffer. + USART_TX_INT_DISABLE(); + switch (RS485_State) + { + case RS485_STATE_TX_DATA: + case RS485_STATE_WAIT_FOR_ACK: + case RS485_STATE_WAIT_COMPLETE: + case RS485_STATE_TX_GLOBAL_ACK: + RS485_State = RS485_STATE_IDLE; + break; + } + + // load the frame + RS485_Tx_Length = 0; + while (buffer && nbytes) + { + RS485_Tx_Buffer[RS485_Tx_Length] = *buffer; + buffer++; + nbytes--; + RS485_Tx_Length++; + // check bounds - should this error be indicated somehow? + // perhaps not send the message? + if (RS485_Tx_Length >= MAX_MPDU) + break; + } + // signal the task to start sending when it is ready + RS485_Flags.TransmitStart = TRUE; return; } -// called by timer, interrupt(?) or other thread -void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port) +/**************************************************************************** +* DESCRIPTION: Processes the next RS485 byte for transmit +* RETURN: none +* ALGORITHM: none +* NOTES: Called by interrupt service routine (ISR) +*****************************************************************************/ +void RS485_Transmit_Interrupt(void) { - if (mstp_port->ReceiveError == true) + uint8_t data; // data byte to send + + switch (RS485_State) { - // wait for state machine to clear this - } - // wait for state machine to read from the DataRegister - else if (mstp_port->DataAvailable == false) - { - // check for data - - // if error, - // ReceiveError = TRUE; - // return; - - mstp_port->DataRegister = 0; // FIXME: Get this data from UART or buffer - - // if data is ready, - // DataAvailable = TRUE; - // return; + case RS485_STATE_TX_DATA: + RS485_Tx_Index++; + if (RS485_Tx_Index < RS485_Tx_Length) + { + data = RS485_Tx_Buffer[RS485_Tx_Index]; + USART_TRANSMIT(data); + MSTP_Port.SilenceTimer = 0; + } + else + { + // wait until the last bit is sent + while (!USART_TX_EMPTY()); + RS485_TRANSMIT_DISABLE(); + // wait 2 characters after sending (min=15 bit times) + RS485_Tx_Postdrive_Delay = 2; + RS485_State = RS485_STATE_TX_POSTDRIVE_DELAY; + USART_TRANSMIT(0); + } + break; + case RS485_STATE_TX_POSTDRIVE_DELAY: + // after the message is sent, we wait a certain + // number of character times to get a delay + if (RS485_Tx_Postdrive_Delay) + { + RS485_Tx_Postdrive_Delay--; + if (RS485_Tx_Postdrive_Delay == 0) + RS485_State = RS485_STATE_WAIT_COMPLETE; + USART_TRANSMIT(0); + } + else + RS485_State = RS485_STATE_WAIT_COMPLETE; + break; + case RS485_STATE_WAIT_COMPLETE: + // wait until the last delay bit is shifted + while (!USART_TX_EMPTY()); + USART_TX_INT_DISABLE(); + RS485_Flags.TransmitComplete = TRUE; + RS485_State = RS485_STATE_IDLE; + USART_RX_SETUP(); + break; + default: + break; } + + return; } +/**************************************************************************** +* DESCRIPTION: Processes the RS485 message to be sent +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Process_Tx_Message(void) +{ + if (RS485_Flags.TransmitComplete) + RS485_Flags.TransmitComplete = FALSE; + // start a new transmisstion if we are ready + if (RS485_Flags.TransmitStart && (RS485_State == RS485_STATE_IDLE)) + { + // Disable the receiver + USART_RX_INT_DISABLE(); + USART_CONTINUOUS_RX_DISABLE(); + // Enable the transmit line driver and interrupts + RS485_TRANSMIT_ENABLE(); + RS485_State = RS485_STATE_TX_DATA; + // Configure the ISR handler for an outgoing message + RS485_Tx_Index = 0; + // update the flags for beginning a send + RS485_Flags.TransmitComplete = FALSE; + RS485_Flags.TransmitStart = FALSE; + // send the first byte + USART_TRANSMIT(RS485_Tx_Buffer[0]); + USART_TX_SETUP(); + } + + return; +} + +/**************************************************************************** +* DESCRIPTION: Checks for data on the receive UART, and handles errors +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) +{ + struct _rcstabits rcstabits; // reading it more than once gets wrong data + + // check for data + if (USART_RX_COMPLETE()) + { + // Read the data and the Rx status reg + rcstabits = USART_RX_STATUS(); + mstp_port->DataRegister = USART_RECEIVE(); + + // Check for buffer overrun error + if (rcstabits.OERR) + { + // clear the error + USART_CONTINUOUS_RX_DISABLE(); + USART_CONTINUOUS_RX_ENABLE(); + // let the state machine know + mstp_port->ReceiveError = TRUE; + } + // Check for framing errors + else if (USART_RX_FRAME_ERROR()) + { + // let the state machine know + mstp_port->FramingError = TRUE; + mstp_port->ReceiveError = TRUE; + } + // We read a good byte + else + { + // state machine will clear this + mstp_port->DataAvailable = TRUE; + } + } + + return; +} + +/**************************************************************************** +* DESCRIPTION: Receives a data byte from the USART +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Receive_Interrupt(void) +{ + // get as many bytes as we can get + for (;;) + { + RS485_Check_UART_Data(&MSTP_Port); + if (MSTP_Port.ReceiveError || MSTP_Port.DataAvailable) + MSTP_Receive_Frame_FSM(&MSTP_Port); + else + break; + } + + return; +} + +/**************************************************************************** +* DESCRIPTION: Returns the baud rate that we are currently running at +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +uint32_t RS485_Get_Baud_Rate(void) +{ + return RS485_Baud_Rate; +} + +/**************************************************************************** +* DESCRIPTION: Sets the baud rate for the chip USART +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Set_Baud_Rate(uint32_t baud) +{ + if (baud < 19200) + RS485_Baud_Rate = 9600; + else if (baud < 38400) + RS485_Baud_Rate = 19200; + else if (baud < 57600) + RS485_Baud_Rate = 38400; + else if (baud < 57600) + RS485_Baud_Rate = 57600; + else if (baud < 115200) + RS485_Baud_Rate = 76800; + else + RS485_Baud_Rate = 115200; + +} + +void RS485_Initialize_Baud(void) +{ + // setup USART Baud Rate Generator + // see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book + /* Fosc=20MHz + BRGH=1 BRGH=0 + Rate SPBRG Rate SPBRG + ------- ----- ------- ----- + 9615 129 9469 32 + 19230 64 19530 15 + 37878 32 78130 3 + 56818 21 104200 2 + 113630 10 312500 0 + 250000 4 + 625000 1 + 1250000 0 + */ + switch (RS485_Baud_Rate) + { + case 19200: + SPBRG = 64; + TXSTAbits.BRGH=1; + break; + case 38400: + SPBRG = 32; + TXSTAbits.BRGH=1; + break; + case 57600: + SPBRG = 21; + TXSTAbits.BRGH=1; + break; + case 76800: + SPBRG = 3; + TXSTAbits.BRGH=0; + break; + case 115200: + SPBRG = 10; + TXSTAbits.BRGH=1; + break; + case 9600: + default: + SPBRG = 129; + TXSTAbits.BRGH=1; + break; + } + /* select async mode */ + TXSTAbits.SYNC=0; + /* serial port enable */ + RCSTAbits.SPEN=1; +} + +/**************************************************************************** +* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in +* receive mode. +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Initialize(void) +{ + RS485_Initialize_Baud(); + /* configure interrupts */ + USART_TX_INT_DISABLE(); + USART_RX_INT_ENABLE(); + // configure USART for receiving + // since the TX will handle setting up for transmit + USART_CONTINUOUS_RX_ENABLE(); + /* since we are using RS485, + we need to explicitly say + transmit enable or not */ + RS485_TRANSMIT_DISABLE(); +} + + diff --git a/bacnet-stack/ports/pic18/timer.c b/bacnet-stack/ports/pic18/timer.c new file mode 100644 index 00000000..c1b43347 --- /dev/null +++ b/bacnet-stack/ports/pic18/timer.c @@ -0,0 +1,45 @@ +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* +*********************************************************************/ +#include + +volatile uint8_t Milliseconds; // used for timing stuff - counts up to 0xFF. + +/**************************************************************************** +* DESCRIPTION: Timer is set to go off every 1ms. We increment the counter, +* and the main task will decrement the counter. +* PARAMETERS: none +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void Timer_Millisecond_Interrupt(void) +{ + // Global Milisecond timer + if (Milliseconds < 0xFF) + Milliseconds++; + + return; +} diff --git a/bacnet-stack/ports/pic18/timer.h b/bacnet-stack/ports/pic18/timer.h new file mode 100644 index 00000000..65628682 --- /dev/null +++ b/bacnet-stack/ports/pic18/timer.h @@ -0,0 +1,34 @@ +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +#ifndef TIMER_H +#define TIMER_H + +// used for timing stuff - counts up to 0xFF. +extern volatile uint8_t Milliseconds; + +void Timer_Millisecond_Interrupt(void); + +#endif diff --git a/bacnet-stack/rs485.h b/bacnet-stack/rs485.h index 89a6346b..aba982b9 100644 --- a/bacnet-stack/rs485.h +++ b/bacnet-stack/rs485.h @@ -39,12 +39,16 @@ #include #include "mstp.h" +void RS485_Initialize(void); + void RS485_Send_Frame( - struct mstp_port_struct_t *mstp_port, // port specific data + 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) void RS485_Check_UART_Data( - struct mstp_port_struct_t *mstp_port); // port specific data + volatile struct mstp_port_struct_t *mstp_port); // port specific data + +void RS485_Process_Tx_Message(void); #endif