modified while adding pic18 support

This commit is contained in:
skarg
2005-04-20 17:09:26 +00:00
parent d6033b03a3
commit 4646df1188
13 changed files with 1183 additions and 204 deletions
+9 -9
View File
@@ -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);
+24 -42
View File
@@ -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
+45 -24
View File
@@ -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
Binary file not shown.
+250
View File
@@ -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 <p18F452.h>
#include <portb.h>
#include <timers.h>
/****************************************************************************
* 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 */
+126
View File
@@ -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 <string.h>
#include <stdint.h>
#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;
}
+33
View File
@@ -0,0 +1,33 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
*
* 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
+184
View File
@@ -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 <stdint.h>
#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
+55 -36
View File
@@ -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 <skarg@users.sourceforge.net>
*
* 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 <stddef.h>
#include <stdint.h>
@@ -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);
}
+372 -91
View File
@@ -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 <skarg@users.sourceforge.net>
*
* 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 <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#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();
}
+45
View File
@@ -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 <stdint.h>
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;
}
+34
View File
@@ -0,0 +1,34 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
*
* 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
+6 -2
View File
@@ -39,12 +39,16 @@
#include <stdint.h>
#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