Sei sulla pagina 1di 158

Implementation of digital I/O module for communication using CANopen protocol

A thesis submitted to Newcastle University for the degree of MSc in Automation and control In the Faculty of Science, Agriculture and Engineering

2010

Mosab Yaseen Mohammed Elamin


SCHOOL OF ELECTRICAL, ELECTRONIC AND COMPUTER ENGINEERING

NEWCASTLE UNIVERSITY SCHOOL OF ELECTRICAL, ELECTRONIC AND COMPUTER ENGINEERING

I, Mosab Yaseen Mohammed Elamin , confirm that this report and the work presented in it are my own achievement. I have read and understand the penalties associated with plagiarism.

Signed: ....................................................... Date: ...........................................................

ii

Abstract
Many industrial automation technologies were developed due to the great benefits of adopting automation in industry, one of these techniques is remote digital Input/Output (I/O) modules which is widely used with considerable success in automation applications. These modules communicate with controllers in different types of communication protocols; CANopen is a field bus protocol which proved to be reliable for more than fifteen years in automation communication. This project describes in details the steps of implementing digital I/O module with CANopen in both hardware and software terms, the module has been tested and verified.

iii

Contents
Acronyms .................................................................................................................................................... vii List of figures ............................................................................................................................................. viii List of tables ................................................................................................................................................. ix Chapter 1 ...................................................................................................................................................... 1 Introduction .................................................................................................................................................. 1 1.1 Automation methods ......................................................................................................................... 1 1.2 Benefits of DCS: .................................................................................................................................. 2 1.3 Smart solutions: ...................................................................................................................................... 3 1.3.1 Intelligent instrumentation ............................................................................................................. 4 Advantages: ............................................................................................ Error! Bookmark not defined. Disadvantages: ....................................................................................... Error! Bookmark not defined. Recent trends: ........................................................................................ Error! Bookmark not defined. 1. 3.2 Remote or field I/O: .......................................................................... Error! Bookmark not defined. Advantages: ............................................................................................ Error! Bookmark not defined. Disadvantages: ....................................................................................... Error! Bookmark not defined. Recent trends: ...................................................................................................................................... 5 1.4 Communication protocols ...................................................................................................................... 6 1.4.1 Open System Interconnection (OSI) model: ................................................................................... 6 1.4.2 Standard Vs proprietary .................................................................................................................. 8 1.4.2.1 Proprietary protocols ............................................................................................................... 8 1.4.2.2 Standard protocols: .................................................................................................................. 8 1.4.3 Ethernet VS Field bus protocols ...................................................................................................... 8 1.4.3.1 Ethernet .................................................................................................................................... 8 1.4.3.2 Field bus protocols ................................................................................................................... 9 Chapter 2 ................................................................................................................................................ 11 CAN protocol: ......................................................................................................................................... 11 2.1 Historical background: ................................................................................................................. 11 Chapter 3 ................................................................................................................................................ 12 CANopen: ............................................................................................................................................... 12 3.1 Protocol structure: ........................................................................................................................ 12 3.2 CANopen properties: .................................................................................................................... 13 Chapter 4....................................................................................................................................................16 Hardware implementation.........................................................................................................................16 4.1 Implementation description..........................................................................................................16 iv

4.2 Overview of the microcontrlloer....................................................................................................16 4.2.2 ECAN module features........................................................................................................17 4.2.3 Module overview.................................................................................................................18 4.2.4 I/O ports.............................................................................................................................18 4.2.5 Data recieving ....................................................................................................................19 4.2.6 Data transmission...............................................................................................................20 4.2.7 Interrupt services.........................................................................................................,.....21 4.2.8 Data rate programming......................................................................................................22 4.3 MCP2551 CAN transciever.............................................................................................................23 4.4 Voltage regulator ..........................................................................................................................24 4.5 Printed Circiut Board.....................................................................................................................25 Chapter 5 ................................................................................................................................................28 Software..................................................................................................................................................28 5.1 Initialization..........................................................................................................................29 5.1.1 Node initilization..................................................................................................29 5.1.1.1 Oscillator initilization...........................................................................29 5.1.1.2 Node ID................................................................................................29 5.1.1.3 Heart beat cycle setting.......................................................................30 5.1.1.4 Port initialization.................................................................................30 5.2 CANopen initilization..........................................................................................................31 5.3 Infinite loop processing......................................................................................................33 5.3.1 Processing functions...........................................................................................34 5.3.2 PDO message recieving......................................................................................34 5.3.3 NMT message group..........................................................................................35 5.3.4 SDO messsage group..........................................................................................35 5.3.5 Object dictionary................................................................................................35 5.3.5.1 Object dictionary entry......................................................................35 5.3.5.2 Reading and writing functions of the dictionary................................37 5.3.6 Message transmission........................................................................................38 v

5.3.7 DemoProcessEvents function.............................................................................38 5.3.7.1 Input port processing.........................................................................38 5.3.7.2 Output port processing......................................................................39 Chapter 6...............................................................................................................................................40 Tests......................................................................................................................................................40 6.1 Input port test....................................................................................................................40 6.2 State request test..............................................................................................................40 6.3 Output port test................................................................................................................40 6.4 Reading from and writing to object dictionary.................................................................40 6.4 Node state change command...........................................................................................40 Conclusion..........................................................................................................................................41 References:.........................................................................................................................................42

vi

Acronyms

CAN CIA CPU CSMA/CD

Controller Area Network Control In Automation Central Processing Unit Carrier Sense Multiple Access /Collision Detection

DCS IEEE

Distributed Control System Institute of Electrical and Electronics Engineers

I/O ISO MAC NCS NMT OPC

Input/Output International Standardization Organization Medium Access Control Network Control System Network Management System Object Linking and Embedding; (OLE) for Process Control

OSI PC PCB PDO PLC SDO

Open System Interconnection Personal Computer Printed Circuit Board Process Data Object Programmable Logic Controller Service Data Object

vii

List of figures
Figure 1: Typical DCS system [7]................................................................................................... 2

Figure 2: OSI model ........................................................................................................................ 6 Figure 3: Communication services required for DCS systems ....................................................... 7 Figure 4:CAN definition according to OSI model ........................................................................ 11 Figure 5: CANopen protocol mapped to the OSI model ............................................................... 12 Figure 6: state transitions for a CANopen node............................................................................14 Figure 7: pic18f2585 pin diagram.................................................................................................16 Figure 8: Module circuit layout.....................................................................................................24 Figure 9: Top layer tracks..............................................................................................................25 Figure 10: Bottom layer tracks......................................................................................................25 Figure 11: Top and bottom layers..................................................................................................26 Figure 12: Code flow chart............................................................................................................27 Figure 13: Initialization.................................................................................................................29 Figure 14: Infinite loop processing flow chart..............................................................................34

viii

List of tables
Table 1: Field bus protocols...........................................................................................................9 Table 2: Fieldbus protocols and key factors................................................................................10 Table 3: CANopen characteristics................................................................................................13 Table 4: CANopen node states....................................................................................................14 Table 5: PIC18F2585 key features..............................................................................................17 Table 6: Comparison between CAN and ECAN modules..........................................................18 Table 7: Registers associated to receive buffers.........................................................................19 Table 8: Registers associated to transmit buffers.......................................................................20 Table 9: Interrupt registers.........................................................................................................21 Table 10: Bit timing controlling registers...................................................................................23 Table 11: MCP 2551 features.....................................................................................................24 Table 12: Dip switch and baud rates...........................................................................................30 Table 13: Messages groups values..............................................................................................32 Table 14: Messages numbers in message groups.....................................................;;.................32 Table 15: Node states and corresponding value in heartbeat messages......................................33 Table 16: node state change command values............................................................................35 Table 17: object dictionary structure and variable meaning.......................................................36 Table 18: object dictionary.........................................................................................................36 Table 19: transmit functions for message groups.......................................................................38 Table 20: PDO messages............................................................................................................41 Table 21: SDO messages...........................................................................................................42 Table 22: node state change command values...........................................................................43

ix

Chapter 1

Introduction
Automation is changing a process or a product to make it work in the best possible manner without a significant human contribution. [1] There exists the potential for much benefit and thus applying automation methods has become important in all industries, some of the reasons are [1, 2]: Replacing human man power in dangerous and hazardous fields. Reducing costs in exchange for better product quality, less defective units, faster operations, and better utilization of raw materials. The automation system provides information about processes, which allows defining weak points and initiating possible improvements.

1.1 Automation methods


Three methods exist in automation: Control boards for a specific unit. Programmable Logic Controller (PLC) for a small scale process Distributed Control System (DCS) for a relatively large scale process [3]

Control boards: Early models of automation included the control board, which has a number of switches, lights, analogue meters and other devices that inform an operator of a units status [3]. PLC: Current models include PLCs, involving a processing unit controller. Under the command of a set of operation conditions, PLC is operated to govern a sequence of processes [4]. It is often times used to control relatively small systems. DCS: DCS: is a group of microprocessor based nodes connected in a network (such as controllers, remote I/O modules, smart measurement devices or smart sensors). DCS works with a central controlling unit and software packages, including archiving and analysis tools connected through a communication network [5]. DCS (sometimes referred to as Network Control System (NCS)) was initially used with industrial processes and factories. However, recently it has been utilized in numerous fields including the likes of building automation, automotive systems, medical instruments ,airplanes, amongst others[6], fig(1) [7] shows a typical DCS system, within which PLC and control boards (machine controller) are labelled.

Figure 1: Typical DCS system [7]

1.2 Benefits of DCS:


Enables efficient and easy analysis of the system based on data collected from monitoring devices, this analysis allows improvements to be made to the process. Increases the speed of failure detection in any device in the system allowing quick failure detection and correction and in some cases without the need of human interaction. Allows flexible operation by communicating and controlling all nodes in an acceptable time frame.
2

Different control devices from different vendors can exchange data using Object Linking and Embedding (OLE) for Process Control(OPC) server as shown in figure(1), the OPC , is a set of standards used to enable plant real-time data communication between control devices from different manufacturers[8]. It will be possible to connect industrial plants to the internet as shown in figure(1) which can change the way of plant operation ,however this approach still needs great research efforts.

Additionally [2]: Since DCS uses a single data bus that connects all nodes, it reduces cost by decreasing the number and/or length of connection cables. It allows data buses to run long distances, thus increasing the coverage area. Expanding DCS systems is easy as new nodes can easily be attached using extension cable with appropriate communicating ports.

1.3 Smart solutions:


Controlling units often connect sensors and actuators through I/O cards used for both analogue and digital signals. These cards are mounted in the same rack within the cabinet of the controlling units processor .Many wires connect the I/O cards with the instrument; nevertheless, there can be some difficulties with this approach [9]: If there are numerous instruments involved, then the number of wires can become intolerable for the controller cabinet and difficult for the engineer involved. For large number of instruments high rates controller processors are required to avoid operation time delays due to processing time. If the distance between the controller and instrument is elongated, then there is an excess cost due to long cabling. By being utilized for longer distances, the signal may be more vulnerable to noise signals that can jam the data of interest. Moreover, cable losses may result in erroneous receipt. It may be extremely difficult to install the processor in a field of harsh conditions (high temperature, moisture, noise, or high level of gas emission). Nodes can also be scattered far apart from each other requiring a standalone processor for each set of neighbouring nodes.

For these reasons a new approach was developed to create moderate processing capabilities in instrumentation. These new approaches enable a direct connection to data buses in two different techniques:

1.3.1 Intelligent instrumentation.


By adding a processor with a small sized memory in addition to built in communication ports to instruments, dealing with superfluous wires can be avoided as only two communication wires can connect all instruments in a multi drop fashion to the controller.
1.3.1.1 Advantages:

This technique overcomes the problem of noise picked up by connection wires as well as power losses in long wires [10]. This unit performs initial processing including data conversion to engineering units, self testing, initiating alarms according to set limits, or short term archiving. The unit aids controllers by reducing processing loads [11]. The property of initiating alarms is advantageous on event based maintenance where instruments can send alarms for improper operation. These alarms allow maintenance staff to maintain devices before they completely fail, and this saves money and time compared with cyclic maintenance. The possibility of remote configuration of instruments through data buses.

1.3.1.2 Disadvantages:

Intelligent instruments are more expensive than traditional ones. With respect to different vendor instruments, interoperability should be considered. Many studies[12,13,14] support the wireless technology to be adopted in industrial automation , by using sensors and actuators which communicate wirelessly with controllers , in [13] the technology of Wireless Sensors Networks (WSN) is described. Standardization efforts are made by number of organization to define and implement WSN however the real implementation still need time to spread, due to some design challenges. Advantages of WSN technology [12, 13]: Reducing cabling costs Flexible instruments distribution. Some applications which require device mobility can be monitored and controlled wirelessly [15]. Main challenges [12, 13]: Noise signals. Propagation losses. Multipathing ( losses due to reflected waves from several paths). Time delay, should be kept below certain limits. Signal interference from other sources.

1.3.2.3 Recent trends:

1.3.2 Remote or field I/O: Remote or field I/O (also known as smart I/O) is an input, output module installed remotely with a low level of intelligence. Examples of intelligence include processing memory, communication ports , and other physical ports to be connected to instruments.
1.3.2.1 Advantages:

This overcomes the problem of noise picked-up by connection wires as well as power losses in longer wires. And this unit makes initial processing such as data conversion to engineering units; this serves controllers by reducing processing load. Economically much better than the smart instrumentation approach.

1.3.2.2 Disadvantages:

Remote configuration for instruments is not possible. More wires are required between instruments and Remote I/O.

Recent trends:

In [12] the Wireless Interface for Sensors and Actuators (WISA) technology is described, it is adopting I/O modules which communicate with sensors and actuators wirelessly, having nearly the same advantages and challenges described in 2.1.3 WSN technology.

1.4 Communication protocols


1.4.1 Open System Interconnection (OSI) model: The Open System Interconnection Reference Model is a general description of the communication process by diving it to groups of services and putting these groups in a layer form, fig (2) shows the OSI model. This model was made by the standard International Standarization Organization (ISO) to enable connectivity and interoperability between different vendors communication devices [16].

Figure 2: OSI model

Brief definition for each layer Application layer: in this layer services of interacting with users are defined, including application addressing, file transfer and others. Presentation layer: in this layer the required data conversion, processing and encoding services are defined. Session layer: in this layer services are defined to link programs in the sending and receiving devices along the network, it is not a physical link but it is a logical one. Transport layer: the services here guarantee reliable transfer of a message no matter what size is it, over potentially unreliable networks. Network layer: the services here define the communication path through a wide network connection.
6

Data link layer: in this layer services responsible for four vital processes are defined, they are: Error detection and erroneous messages. correction: services detect and correct

Flow control: these services manage the communication load between the transmitter and receiver, for example if the receiver cant cope with the transmission rate, these services will slow down the transmitter and buffer the communication load. Link management: these services deal with the sequence of rules required for establishing connections between devices; there are certain rules of communication: request from the transmitter and acknowledgment from the receiver and some settings for request time out and other parameters defined by these services. Medium Access Control (MAC):Since all network nodes shares the same bus or media , and at any time only one node should be transmitting and the rest are either receiving or waiting , for a node to access the bus (i.e. to get control on the bus and start sending) there are set of rules to decide which node should take hold of the bus first, the services in this sub layer decide that.

Physical layer: it is the physical interface between a node and the communication media, in here the transmitted signal physical properties are decided such as voltage levels, power rates as well as physical port properties. Communication services required in DCS are mainly in the application ,data link, and physical layers fig(3) shows an illustration of the required layers in industrial applications; and more detailed description can be found in [2,16].

Figure 3: Communication services required for DCS systems

1.4.2 Standard Vs proprietary


A communication protocol is a set of rules governing transmission and receiving of data along with defining physical properties of communication signals [17], many communication protocols has been developed.

1.4.2.1 Proprietary protocols In old DCS systems each company had special communication rules which are called proprietary or private protocol ,vendors were providing a whole system for a factory or a manufacturing line, i.e. all communication devices must be from only one vendor this has some advantageous and disadvantageous [3] The main advantage is that the system will be especially tailored to the factory so system consistency and operability will be guaranteed. Disadvantages: Any system has some weak points, which do not exist in other systems, if designers have the possibility to combine different systems, the overall results may be much better. The customer will be restricted to one vendor in maintenance, spare parts and system extensions, economically and practically this situation may cause difficulties.

1.4.2.2 Standard protocols:

Standard protocols published or approved by standard organizations and applied by large group of vendors became more common, designers can select devices from different vendors and connect them in one network, obviously a more flexible solution and also economically effective because this standardization generates more competition between vendors allowing lower prices for customers [6].

1.4.3 Ethernet VS Field bus protocols:


1.4.3.1 Ethernet

There are large numbers of communication standards, some recent studies in DCS system suggested that in the future Ethernet (IEEE 802.3: Carrier Sense Multible Access (CSMA/CD)) will dominate in industrial automation communication [18, 19] This point of view is based on recent trends of adopting Commercial Off-The-Shelf (COTS) technologies in DCS systems including Personal Computers (PCs) and Ethernet networks due to its great achievements in data communication i.e. personal computers networks[18] Advantages of Ethernet: Large capacity of data transmission. Very high transmission rates. Compatibility with data networks , this can be very useful, by using appropriate software, field information can be archived in the instruments or controllers, this information can be send through automation network to the management ,financial, and marketing departments or even through internet.
8

However Ethernet is not always the best solution in automation applications, because originally data communication is different from control communication , Ethernet has high data rates but there are problems with its transmission time determinism , depending on network size and bus load, transmission time delays are small yet random, these delays have no effects on data networks, but in automation, small delays in feedback control messages for example may result in unstable system. [6] There are many efforts to improve Ethernet timing properties and to design new versions called Real Time Ethernet RTE; now more than twenty approaches are available. More over in some applications with short messages a field bus protocol Controller Area Network (CAN) was found according to [6] to have better achievements. This kind of messages is dominant in the lower level in control systems, the communication between sensors, actuators and controllers, as well as embedded controllers industry like automotive, medical instruments, aircraft industries and more. In addition ,some field bus protocols currently have adopted Ethernet facilities such as Foundation Field bus High Speed Ethernet FF HS1, Modbus TCP, and some others in the way [12], moreover available in the market gateways between field bus and Ethernet, these gateways offer transparent transmission of field bus protocols from point to point over Ethernet. One disadvantage of using gateways is that, gateway circuits need time to process the data flow, this will increase time delays.
1.4.3.2 Field bus protocols

Field bus protocols are a group of protocols for industrial automation, the term bus was originated from the fact that all devices in the field (e.g. factory, manufacturing line, etc.) are connected serially through cables, in early automation systems each manufacturer or vendor had a special protocol, thats why large number of protocols are classified as fieldbuses these days .Table (1) shows the most common field bus protocols , more information can be found in[20]. Table 1: Field bus protocols
Field bus Name Profibus DP/PA Interbus DeviceNet Arcnet AS-I Foundation Field bus H1 Foundation Field bus HSE Seriplex WorldFIP LONWorks SDS ControlNet CANOpen Modbus Plus Modbus RTU/ASCII Technology Developer Siemens Phoenix Contact Interbus Club Allen-Bradley Datapoint AS-I Consortium Fieldbus Foundation Fieldbus Foundation APC WorldFIP Echelon Honeywell Allen-Bradley CAN in Automation Modicon Modicon Year Introduced DP: 1994 PA: 1995 1984 1994 1977 1993 1995

2000
1990 1988 1991 1994 1996 1995

------1999

Comparisons: It is not easy to compare between field bus protocols and decide which one is the best ; this comparison depends on two issues ,technical specifications and economical feasibility. First of all application type defines which protocols are applicable , some protocols are widely used in large processing systems, but not used in smaller scale applications. Key factors of technical specifications are: Maximum number of nodes in a network segment. Maximum distance. Data rate. Maximum delay time and some other factors. Interestingly some studies [21], suggested an approach to compare protocols and the final result is a quantitative figure, using a technique called entropy ideal point, this procedure doesnt only consider technical specifications but also some economical aspects such as System cost. Installation cost. Maintenance cost. However some important economical factors are not included which relates to the current status of the customer such as Training cost. Replacement cost if required, and other factors. Still it is a wonderful approach; table (2) shows some field bus protocols with key properties [20]. Table 2: Field bus protocols and key factors
Fieldbus Name Profibus DP/PA Interbus DeviceNet Arcnet AS-I Foundation Fieldbus H1 Foundation Fieldbus HSE Seriplex WorldFIP LONWorks SDS ControlNet CANOpen Modbus Plus Modbus RTU/ASCII Max Devices Nodes 126 512 64 255 32 slaves 240/segment 65,000 segments IP addressing essentially unlimited 500+ devices 64 without repeaters 256 with repeaters 32,000 per domain 64 nodes, 126 addresses 99 127 32 per segment, 64 max 250 per segment Max Distance DP:100-1,200m/segment PA: 1,900m/segment 400m/segment 500m 400/2000 feet 100-300m 1900m 100-2000m >500 feet 2 km 40 km 2000m 500m 250-1000m 25-1000m 500m per segment 350m

10

Chapter 2

CAN protocol:
2.1 Historical background:
CAN is an international serial communication protocol, standardized in ISO 11898-1 and classified as a field bus, it was originally designed in BOSCH automotive company in 1980 to achieve in-vehicles communication control, in instead of large number of wires, but after that it found its way to other applications in industry [2]. CAN protocol only specifies the data link layer and physical layer as shown in fig (4).

Figure 4:CAN definition according to OSI model There are collection of protocols related to CAN, they are CAN Application layer CAL, CANopen, DeviceNet, and J1939[22] CAN Application layer CAL. CANopen an application layer over CAN bus applied in many automation fields, one of the best Protocols used in embedded networks in many kinds of machineries especially in Europe. DeviceNet is a communication protocol based over CAN bus and was developed by Allen-Bradley Company and mainly used in process automation applications. J1939 protocol: is an application profile based on CAN originally was developed for in-trucks communication, after wards had been applied for other fields.

2.2 CAN bus properties:


Deterministic i.e. the maximum delay time of transmission is fixed. The highest priority node always gets hold of the bus first, thus critical nodes are not affected by time delays. Easy to setup. Relatively cheap. Reliable, very effective in error detection and correction. Was succeeded in dealing with harsh fields conditions in automobiles for long time. Easy to upgrade[23]

2.3 CAN bus filtering:


CAN bus is a message oriented protocol, , there is no sender id or receiver id in a CAN message , all nodes detects every message on the bus , each node determines whether to accept and process a message or not based on the message identifier , each message has an identifier ,which is a particular value , to do this each node need to perform a message filtering, there are two types of filtering:
11

FULL CAN where message identifiers which the node should receive and process are statically defined and stored in the node registers , this procedure is fast in processing and requires smaller programs. Basic CAN the node manipulates identifiers by software ,requiring larger code , and some processing time but is more flexible than Full CAN method , more details about CAN protocol can be found in[2]

Chapter 3

CANopen:
3.1 Protocol structure:
CANopen is a field bus protocol based on CAN bus as shown in fig (5).

Figure 5: CANopen protocol mapped to the OSI model The reasons why CANopen and CAN dont have specification for four layers i.e. presentation, session, network, and transport are [2]: Presentation layer: this layer responsible for encoding data, in CAN there is a defined set of data types so no need for data encoding or addressing.

12

Session layer: CAN adopts real time communication, thus no need for this layer which is responsible for creating logical links between receiver and transmitter for each communication transaction. Network layer: Network layer is responsible for internetworking communication, since in CAN bus the network can not be such big and complex this layer is not needed. Transport layer: again because the nature of real time communication and high reliability in CAN networks no need for this layer which deals with semi-unreliable networks.

3.2 CANopen properties:


Table (3) shows some characteristics of CANopen [20]. Table 3: CANopen characteristics CAN In automation Technology developer 1995 Year introduced 17 chip vendors,300 product vendors, open Openness Drop line Network topology Twisted pair optimal signal & power Physical media 127 nodes Maximum devices (nodes) 25-1000m depending on data rate Maximum Distance Master/slave, peer-to-peer, multicast, multimaster Communication methods 10,20,50,125,250,500& 800Kbps,1 Mbps Transmission properties 8 byte, variable Data transfer size CANopen properties are flexible, different choices of data rates and distances are available, even for the limitation of 8 byte message in CAN, CANopen can send longer messages by breaking a message down to 8 data blocks and recombine them again in the receiver, nodes number is really competitive. One of the most powerful characteristics of CANopen that it is an open software, this results in more flexibility for designers , on the other hand the cost for installing is reduced . More field bus protocols can be found in [6] to be compared with CANopen. Control In Automation (CIA) organization, publishes device profiles for CANopen in different industrial fields, there are many profiles for specific applications such as I/O modules, train machines, building room control and more. Profiles help designers to access devices functionalities using CAN bus [2], there are many published device profiles and other new fields are in progress [22].

3.3 CANopen services:


3.3.1 Object dictionary: CANopen specification defines a data base in each node from which all node information can be accessed through the network this data base is called object dictionary, each entry in the dictionary is addressed by an index and sub-index. 3.3.2 Communication objects: There are four types of communication objects ( messages with specific identifiers and formats) in CANopen network SDO Service data objects These objects are used to read from or write in the object dictionary.

13

PDO Process data objects These objects are used to transfer the process information e.g. the states of the outputs inputs of the device. NMT Network management objects These objects are used by the network master node to change the state of a slave node, the node states defined in the standard are shown in table 4, and figure 6 shows the commands used to change the states, these commands are sent through NMT objects. Table 4: CANopen node states Communication capabilities SDO communication is possible to read and write from the object dictionary, heart beat messages are sent, no PDO messaging is possible Operational Stop All messages are available Only heart beat messages are available

State Preoperational

Figure 6: state transitions for a CANopen node[27]


14

Node guard or heartbeat objects These are two ways to make a CANopen node send a periodic signal in the bus , this signal serves two purposes: o This signal is a sign that the node is up and working. o And it contains the current state of the node thus the network master will get a current view of the status of all nodes on the network.

15

Chapter 4

Hardware Implementation
4.1 implementation description:
The module implemented in this project has the following features: 4 inputs and 4 output. Node id programmable through dip switch. Programmable baud rate through dip switch. Asynchronous message sending in case of port change. Immediate port change in case of receiving operation request. Full can implementation. Standard identifiers communication. Power supply 24V DC. Reading and writing to/from the object dictionary. The mode of operation can be controlled ( stop , preoperational, operational, reset command). Send a heart beat in 2000 ms periods.

4.2 Overview of the microcontroller


The microcontroller used in this implementation is PIC18F2585 which is part of the PIC18F2585/2680/4585/4680 family , these devices combine high processing capabilities and low prices, along with some enhanced functions in memory and communication ports which help improving the over all performance, table 5 shows the main features of PIC18F2585, and figure 7 shows the PIC18F2585 pin diagram [24] .

16

Table 5: PIC18F2585 key features Manufacturer Data EEPROM (bytes) RAM Bytes Flash memory KB CPU Speed (Million Instructions Per Second ) Embedded communication controller Temperature Range (C) Operating Voltage Range (V) Pin Count Microchip 1024 3,328 48 10

ECAN -40 to 150 2 to 5.5 28

Figure 7 pic18f2585 pin diagram[24]

4.2.2 ECAN Module Features:

ECAN is an enhanced CAN module developed by Microchip , with ECAN there are more resources available in terms of buffers and filters. ECAN is fully compatible with legacy CAN modules table 6 shows a comparison between CAN and ECAN modules :

17

Table 6: comparison between CAN and ECAN modules CAN Number of filters Message buffers 6 2 recieve + 3 transmit buffers ECAN 16 2 recieve + 3 transmit buffers+6 programmable buffers(can be programmed to be either receive or transmit) Processing time Code size ECAN module can be operated in one of these three modes: Legacy mode (mode 0) in this mode the module will operate as an ordinary CAN module . Much less Larger

Enhanced Legacy (mode 1) operates with the enhancements enabled. FIFO mode (mode2) in this mode 2 or more buffers can be used to form a FIFO First In

First Out buffer in which no one to one filter to buffer link is available , suitable for applications requiring large data bursts handling. ECAN (mode 1) module is recommended for CANOPEN networks which normally require large number of message handling [25].

4.2.3 Module Overview The module consists of protocol engine , memory buffers and special function registers that control the data flow.

4.2.4 I/O ports This microcontroller has three I/O ports PORTA PORTB and PORTC, each port has three registers controlling the port operation: PORT register which reads the level of port pins. TRIS register used to define each bit of the port as an input or output, if a bit in this register is set to 0 the corresponding bit in the port will operate as an output and if set to 1 the corresponding pin will be an input. LAT it is an output latch used as a second alternative for reading or writing the port value. Each pin in the port is protected from Vs and Vg by diodes.

18

4.2.5 Data receiving: The microcontroller when connected to a network bus will load every message into a temporary buffer called the MAB Message Assembly Buffer, the message id will be

compared with the filters, if the massage ID matches one filter then the data will be loaded to one of the receive buffer for further processing, for each receive buffer there is a control register RXBnCON in which the information of which filter enabled the reception of the message is stored , the processor will be informed by an interrupt flag in PIR3 register see

(section 4.6 interrupt services ) table 7 shows the registers associated with a receive buffer.

Table 7: registers associated to receive buffers No. 1 Register name RXBnCon (n=0 or 1) Description Receive buffer control register Function bits 0-4 shows which filter enabled the message reception 2 RXBnSIDL used If standard identifiers are implemented in the network (n=0 or 1) 3 RXBnSIDH used If standard identifiers are implemented in the network (n=0 or 1) 4 RXBnEIDL used If extended identifiers are implemented in the network(n=0 or 1) 5 RXBnEIDH used If extended identifiers are implemented in the network(n=0 or 1) 6 RXBnDLC Recieve buffer data length count The data length in the message received is stored here Recieve buffer extended Identifier High byte The High byte of the standard identifier is stored here Recieve buffer extended Identifier Low byte The low byte of the extended identifier is stored here Recieve buffer Standard Identifier High byte The High byte of the standard identifier is stored here Recieve buffer Standard Identifier Low byte The low byte of the standard identifier is stored here

19

RXBnDm (n=0 or 1) (m=0 to 7)

Recieve buffer data

Eight registers in which the eight data bytes of the message can be stored

4.2.6 Data transmission In case of transmission the data to be send is loaded to one of the transmit buffers , the processor is informed by setting bit 3 of the transmit buffer control register , after the transmission is successfully finished bits 2 and 3 in the PIR3 register see

(section 4.6 interrupt services ) will inform the processor that the transmit buffer is ready to be reloaded, table 8 shows registers associated to transmit buffers.

Table 8: registers associated to transmit buffers No. 1 Register name TXBnCON (n=0 or 1) Description Transmit buffer n control register Functions Bit7 is a transmit buffer flag set when the transmission starts and is not cleared till the transmission finish Bit 3 Transmit request status bit informing the processor that the data in the buffer is ready to be sent, cleared if the transmission was successful 2 TXBnSIDH (n=0 or 1) Transmit buffer n standard identifier high byte 3 TXBnSIDL (n=0 or 1) Transmit buffer n standard identifier low byte The High byte of the standard identifier is stored here The low byte of the standard identifier is stored here

20

TXBnEIDH (n=0 or 1) Transmit buffer n extended identifier high byte

The High byte of the extended identifier is stored here The low byte of the extended identifier is stored here Eight registers in which the eight data byte of the message can be stored

TXBnEIDL (n=0 or 1)

Transmit buffer n extended identifier low byte

TXBnDm (n=0 or 1)(m=0 to 7)

Transmitt data buffer

TXBnDLC (n=0 or 1)

Transmit buffer data length count

The data length in the message to be transmitted is stored here

TXERRCNT

Transmit error count register

contains a value of the rate of transmission errors , if it overflows then the module will enter bus off state

4.2.7 Interrupt services: In case of receiving or transmitting a message interrupt scheme should be available PIR3 peripheral interrupt register 3 is responsible for raising the interrupt flag in case of a message received or transmitted interrupts: table 9 shows registers which deal with message communication

21

Table 9: interrupt registers No. 1 Register name PIR3 Description Peripheral interrupt request register 3 Function Bit 3 and bit2 are set to inform the processor that the transmission is completed and the number of the buffer is ready to be reloaded Bit1 and bit 0 are set to inform the processor that a message have been received and by the number of the buffer 2 PIE3 Peripheral interrupt enable register 3 IPR3 Peripheral interrupt priority register Used to enable or disable interrupts Used to set the priority of buffers

4.2.8 Data rate programming This module can be programmed to operate in one of the eight baud rates defined in the standard , all time parameters are defined in terms of a time quantity called Time quanta TQ, The value of TQ is derived from the oscillator frequency and a programmable value called baud rate pre scalar BRP (0-63) by equation 1 TQ = (2 * (BRP + 1))/oscillator frequency...................1 Each of the four bit time segments defined in CAN specification is defined in multiples of TQ thus the bit time is calculated by equation 2

Bit Time= TQ * (Synchronization segment + Propagation segment +Phase segment1 + Phase segment2).......................2

Finally the baud rate is calculated by equation 3 Baud rate = 1/Bit Time......................3
22

Table 10 shows the three registers controlling these values.

Table 10: Bit timing controlling registers No. 1 Register name BRGCON1 Description Baud rate control register 1 Function Bit7-6 define the value of synchronization segment Bit5-0 define the value of BRP 2 BRGCON2 Baud rate control register 2 Bit 5-3 define the value of phase segment1 Bit2-0 define the value of propagation segment 3 BRGCON3 Baud rate control register 3 Bit 2-0 define the value of phase segment2

4.3 MCP2551 transceiver


MCP2551 is a CAN transceiver, to raise the voltage level of the signals sent and to protect the microcontroller from overvoltage in the bus, key features are displayed in table 11 [26]

23

Table 11: MCP 2551 features

Manufacturer Speed Standard

Microchip 1 Mb/s operation ISO-11898 standard physical layer

Voltage supply Protection

Max. 7 volts Protection against damage due to short-circuit conditions (positive or negative battery voltage)

Protection against high-voltage transients High noise immunity due to differential bus implementation Temperature ranges -40C to +85C

4.4 Voltage regulator


78l05 regulator is used to transform the 24 V DC supply to 5 volts.

24

4.5 Printed circuit board:


For designing the PCB two software packages were used Multisim to draw the layout of the circuit as shown in figure 8.
J11 Key = Space U3 78L05 C3 LINE VREG 330nF COMMON 2%
VOLTAGE

J8 C4 0.01F 2% R1 1k R2 R14 390

LED
R11 10.0k

R15 390

J1

HDR1X6 J9
28 27 26 25 24 23 22 21 20 19 18 17 16 15

HDR1X2 J6

1k
1 2 3 4 5 6 7 8 9 10 11 12 13 14

U1 R12 1k R13 1k J5

J3 R3 1k R4 HDR1X4 1k R5 1k R6 1k R7 1k R8 HDR1X5 1k R9 1k R10 1k C1 15pF 2% C2 15pF 2%

HDR1X2

J10 U2
1 2 3 4 8 7 6 5

pic18f2585

HDR1X2 J2

J7

MCP2551

DSUB9F J4 X1 20MHz

HDR1X5

Figure 8: Module circuit layout

Ultiboard to specify the Physical dimensions of the components. The copper tracks on the two sides of the board. The vias (a via is a connection between the two sides of the board).

Figure 9 shows the top layer tracks, figure 10 shows the bottom layer tracks, and figure 11 shows the two layers.

25

Figure 9 Top layer tracks

Figure 10 Bottom layer tracks

26

Figure 11 Top and bottom layers

27

Chapter 5.

Software
Microchip developed a CANOPEN stack [27] that includes most of the functions defined by the standard, these functions need to be tailored for the application required, and most of these functions were used in this project to program the microcontroller. The program developed in this project handles both CAN and CANOPEN functions along with continuously monitoring the input ports for any change, a description of the code in general is introduced first , details for each service are mentioned afterwards. Figure 12 shows a flow chart of the code.
Power on

Initialization

Continuous monitoring

NO

Change detected? Yes Processing

Figure 12: Code flow chart


ed?

28

5.1 Initialization:
Module initialization consists of two parts as shown in figure 13.

Initialaization

Node initialization

CANOPEN initialization

Figure 13: initialization 5.1.1 Node initialization: In this stage the oscillator and timer setting, node ID and baud rate are determined dip switches are used for this purpose, and the ports are initialized according to requirements. 5.1.1.1 Oscillator initialization: Since there are several options for the oscillator source in PIC18F2585 either internal or external and different frequencies can be selected , in this mode the source of oscillator and frequency value are selected. The mode selected here is HS High speed external oscillator for this the register config1H was set to 0b00000010 and the frequency 20 MHZ. 5.1.1.2 Node ID: For node id 3 bits from port A were used to be connected to the 4 way dip switch (only

three ways are used and one reserved) , in initializing these pins must be configured as in puts thus register TRISA see( section 4.1.4 ) is set to TRISA=0xFF; ( the rest of the pins are set as inputs but are not used , still they are connected to a header for future use). As per the standard it is not allowed for a node to have an ID of 0, thus a conditional statement has been put in the code to avoid this

if(node0 == 0) node = 1; else node = node0; mCO_SetNodeID (node) // Set the Node ID
29

Similarly for baud rate two pins of PORTB are connected to a two way dip switch ,thus PORTB is set to operate as an input port TRISB= 0xFF , the dip switch enable the operation in one of four rates(1 Mbit, 500Kbit, 250Kbit,125Kbit per second) , in fact CANbus standard defines eight rates , the remaining four are (800Kbit,50 Kbit,20Kbit, 10Kbit per second) but because of the tester used in our case here for testing this module see( section ) only the above mentioned rates are available. For each dip switch selection the registers BRGCON1 BRGCON2 and BRGCON3 are set to yield one value as shown in table 12. Table 12: dip switch and baud rates Dip switch value 0 Registers values BRGCON1 = 0x00 BRGCON2 = 0x92 BRGCON3 = 0x82 Baud rate 1Mbit

BRGCON1 =0x01 BRGCON2 = 0x92 BRGCON3 = 0x82

500kbits

BRGCON1 = 0x03; BRGCON2 = 0x92 BRGCON3 = 0x82

250kbits

BRGCON1 = 0x07 BRGCON2 = 0x92 BRGCON3 = 0x82

125kbits

5.1.1.3 Heart beat cycle setting The heartbeat rate set in this stage , defining the cycle in milliseconds , by this function mNMTE_SetHeartBeat (cycle), whereas cycle is in milliseconds. 5.1.1.4 Port initialization: In this implementation PORTC pins 0-3 are used as inputs and PORTC pins 4-7 are used as outputs , thus TRISC=0x0F. There are two variables defined to store ports values:
30

uLocalRcvBuffer to store the data received by messages to deal with output port PORTC 4-7. uLocalXmtBuffer to store the state of the input port PORTC 0-3 to be send to CAN bus. change is used to detect any changes in the input port. These variables are set to zero in this initialization stage.. Since the standard defines message identifiers to include the node id:

PDO transmit id and PDO receive id are defined in this stage by the following PDO transmit cob id is 384+node id which is the equivalent of 0x180+ node id. PDO receive cob id is 512+node id (0x200+node id). PIC18F microcontrollers are designed to handle identifiers in a reverse order, the id of 0b10001110 is handled with filters in this order 0b01110001 , so any id must be stored in microchip format. This is what the function mTOOLS_CO2MCHP (CO_COB) do, converts the MCHP COB

format to the CANopen format.

5.2 CANOPEN initialization


In this stage the CANOPEN services are enabled by these functions _CO_COMM_NMT_Open (); _CO_COMM_SDO1_Open (); _CO_COMM_NMTE_ Open (); _CO_COMM_PDO1_Open (); Starts network management Starts the default SDO Starts the heartbeat Start the pdo1

In this function there are another two functions: The first one is mTOOLS_CO2MCHP which is responsible for setting end point and transforming it from CANopen format to Microchip format The second function is mCANOpenMessage this function uses a variable called handler , each end point has its own handler , addressing endpoints with handlers improves the data flow and speeds up the message processing, messages are classified to three major groups: Network control message group SDO message group PDO message group the cob id for the

31

Each group is assigned a value as shown in table 13 Table 13: messages groups values Message group Network control SDO PDO Name value

COMM_MSGGRP_NETCTL 0x00 COMM_MSGGRP_SDO COMM_MSGGRP_PDO 0x40 0x80

Each group includes number of messages as shown in table 14. Table 14: messages numbers in message groups Message COMM_NETCTL_NMT COMM_NETCTL_NMTE COMM_SDO_1 COMM_PDO_1 Message value 1 4 0 0 Message group COMM_MSGGRP_NETCTL COMM_MSGGRP_NETCTL COMM_MSGGRP_SDO COMM_MSGGRP_PDO

Thus each message is uniquely addressed by the group number and subgroup number e.g. PDO1 is addressed by 0x80 and 0 and so on. mCANOpenMessage function has two inputs and one return value: mCANOpenMessage (MsgTyp, COBID, hRet) MsgTyp= message type which is the group number in binary digitally (ored) with subgroup number e.g. PDO1 message type = 0x80 | 0 = 0x80 and so on. COBID is stored in a buffer _uCANRxIDRes[n], after wards this buffer is copied to filter register RXFnSIDH (n= 0 to 15 in ECAN mode1) hRet is a handle which indicates that the COBID was copied to one filter register. Then the function mCANOpenComm is called to put CANCON CANCON register to zero,

CAN control is a special register in PIC18F2585 which is used to set the status of

the CAN controller in one of the following modes Configuration mode Listen only mode Loopback mode Disable mode Normal mode
32

CANCON=0 will put the controller to normal mode. According to the standard a CANOPEN node should send a message informing the network that the node has initialized, this message is called boot up message, and the COB ID for this message is the same of heart beat with one data byte containing zero value. This message is sent using the function of_CO_COMM_NMTE_TXEvent.

mCANSendMessage function is used to inform the processor that a message is ready to be sent. Then the node will enter preoperational mode as described by the standard , where the heart beat message will be send every N milliseconds (N is decided by the programmer) with the COB ID of 0x700 + Node ID with one data byte , this byte shows the state of the node as shown in table15. Table 15: node states and corresponding value in heartbeat messages Data byte value 0x7F State Preoperational Communication capabilities SDO communication is possible to read and write from the object dictionary, heart beat messages are sent, no PDO messaging is possible 0x05 0x04 Operational Stop All messages are available Only heart beat messages are available

5.3 Infinite loop processing:


Figure 14 shows the data flow chart after initialization, which is implemented by an infinite loop while (1), as long as the node is powered this loop should be followed.

33

Continuous monitoring

NO

Change detected? Yes Processing

Figure 14: infinite loop processing flow chart 5.3.1 Processing functions: _CO_COMMRXEventManager this function ed? deals with all received messages In this function bit1 of register PIR3 is continuously monitored if it raises then this function forwards a handle of the associated buffer , this handle is checked to determine which group this message belongs to , then the relevant receiving function is called, 5.3.2 PDO message receiving. For PDO group then the function _CO_COMM_PDO1_RXEvent is called , this function will store the data field and data length in buffers for further processing. After that the function mCANReadMessage is called to reset bit7 (RXFULL) of the buffer to indicate that the message was successfully received. 5.3.3 NMT message group For a state change command which belongs to NMT group the function

_CO_COMM_NMT_RXEvent is called, This function will check first that the data length is 2 Then it reads data byte zero , according to the value the node state

will change as shown in table 16.

34

Table 16 : node state change command values Data bytre0 value 0x01 0x02 The state Start node , operational mode Stop node Functionality available All messaging is available No communication except the heart beat 0x80 Preoperational mode SDO messaging and heartbeat only 0x82 Reset communication The node will restart as if it was powered off and powered on again

5.3.4. SDO message group For SDO messages then the function _CO_COMM_SDO1_RXEvent is called to determine whether the message is an upload or download and respond accordingly.

5.3.5 Object dictionary 5.3.5.1 Object dictionary entry The implementation of the object dictionary is achieved through using structures , each entry in the dictionary is represented by a structure that contains all necessary information.

typedef struct _DICTIONARY_OBJECT_TEMPLATE { unsigned int index; unsigned char subindex; unsigned char ctl; unsigned int len; rom unsigned char * pROM; }DICT_OBJECT_TEMPLATE; Table 17 shows the function of each variable in the structure, and table 18 shows the object dictionary implemented by this code.

35

Table 17: object dictionary structure and variable meaning Variable Ctrl Function a variable that defines whether the entry is writable or readable both

Len * pROM

the length in bytes of the object a pointer to the object

Table 18: object dictionary

Index

Subindex

Object

R/W

Meaning

0x1000

Device type

Contains a code that represent the type , reading this value will return 0x111111

0x1017

NMTE_HeartBeatAccessEvent

This entry allows reading the heart beat message cycle

0x1018

Device serial number

Reading this object will return device serial number 0x87654321

0x1200

SDO1_CS_COBIDAccessEvent R

Reading this entry will return the Client to Server COB ID 0x600+node ID

0x1200

SDO1_SC_COBIDAccessEvent R

Reading this entry will return the Server to client COB ID 0x580+node ID

0x1400

RPDO1_COBIDAccessEvent

Reading this entry will return the Recieve PDO OB ID 0x200+node ID

36

0x1600

RPDO1Map

Reading this entry will return the index and subindex of the object that store the data sent by RPDO 0x62000

0x1800

TPDO1_COBIDAccessEvent

Reading this entry will return the Transmit PDO COB ID 0x180+node ID

0x1800

TPDO1_TypeAccessEvent

Reading this entry will return the Transmit PDO type 255

0x1A00

TPDO1Map

Reading this entry will return the index and subindex of the object that store the data sent by TPDO 0x60000

0x6000

uLocalXmtBuffer

Reading this entry will return the state of the input ports PORTC bits 0-3

0x6200

uLocalRcvBuffer

R/W

This entry allows reading and writing to the output ports PORTC bits 4-7

5.3.5.2 Reading and writing functions of the dictionary There are two functions to access the dictionary: _CO_DictObjectRead this function is used to read from the dictionary which in turn manipulate two functions CO_MEMIO_CopyRomToRam used if a data stored in ROM need to be read . CO_MEMIO_CopySram used for reading from RAM.

37

_CO_DictObjectWrite this function is used to write in the dictionary ,in this function only CO_MEMIO_CopySram is used, because it is not possible to modify ROM contents in the run time.

5.3.6 Message transmission _CO_COMMTXRdyEventManager() , this function is where all transmission requests are

dispatched , this function is continuingly checking these flags, each group has a variable called transmit flag as shown below COMM_NETCTL_TF COMM_SDO_TF COMM_SDO_TF Network control Transmit Flag SDO transmit flag PDO transmit flag

Whenever a message is ready to be sent the corresponding flag is raised , once one flag is raised the associated transmit function is called, table 19 show the transmit function of each group Table 19 transmit functions for message groups Message group NMTCTL PDO SDO Transmit function _COMM_NMTE_TXEvent _CO_COMM_PDO1_TXEvent. _CO_COMM_SDO1_TXEvent

All these functions operate in the same way, they all set COBID , data length and put the required data into the data filed of the message.

5.3.7 DemoProcessEvents function: This function is the application defined and it has two parts: Part 1 dealing with the input port. Part 2 dealing with the output port. 5.3.7.1 Input port processing The function keeps reading the input port (PORTC 0-3) storing the port value in a variable called uLocalXmtBuffer and comparing this variable with the last state stored in the variable uIOinDigiInOld , once a change is detected that means at least on pin was changed , then the transmit flag of PDO1 is raised, there is a pointer linking the variable uLocalXmtBuffer with

38

the transmit buffer thus when the transmit flag is raised the contents of uLocalXmtBuffer will be sent , the stored state is updated to have the latest values , and the comparison starts again.

5.3.7.2 Output port processing There is a pointer linking the variable uLocalRcvBuffer with the receive buffer, thus when a PDO message is received the data field will be copied to this variable. In addition LATC which is the value of the output port is assigned to uLocalRcvBuffer (since PORTC0-3 are programmed as inputs only PORTC4-7 will change with LATC) Thus any value sent in byte 0 of a PDO message will be forwarded to LATC4-7, also it is possible to change the output port status through writing in the object dictionary.

39

Chapter 6

Tests
The monitor software used is CANbus demo board [28] which include two CAN nodes each is equipped by USB board that can communicate with a PC and display CAN messages in the associated interface, the masks of these nodes are all set to one to enable receiving every CAN message in the bus , the interface allow to form and send CAN messages as well.

6.1 Input port test According to the implementation if one input changed state then an asynchronous PDO message will be sent with the current state of the switches. The COB ID should be 0x180+node ID; the first byte in the data field will reflect the state of the inputs as shown in table () , if an input is connected then the corresponding bit should be one , otherwise should be zero, the test was successfully completed.

6.2 Output port test A message is sent to trigger a signal through output port. The COBID should be 0x200+node ID , byte0 of the data bytes should have the state requested on the output port , for every bit set to one in bits4-7 in byte0 the corresponding port should forward five volt signal , making the connected LED lit . The test was successfully done as shown in table() Another way is to lit the LEDs by writing in correspondent object in the object dictionary , this was done as well as shown in table ()

40

Table 20 PDO messages

Message identifier

Data length

D0

D1

D2

D3

D4-D7

Transmit PDO Input port change Receive PDO Output signal command

0x180 + node ID

Bits 0-3 the 4 ports status

00

00

00

00

0x200 + node ID

Bits 4-7 the value for each port 0x01 firs port 0x02 second 0x04 third 0x08 forth And combinations e.g. value 0xC means port3 and 4

00

00

00

00

6.3 Reading from object dictionary test: Reading any entry in the object dictionary, this was successfully done as shown in table 21

41

Table 21 SDO messages

Message identifier

Data length

D0

D1

D2

D3

D4-D7

Read from the dictionary Read response

0x600+ node ID 0x580+ node ID

0x40

Index low

Index high Index high

Sub index Sub index

zeros

0x43 for four bytes object 0x47 for three bytes objects 0x4B for two bytes object 0x4F for one byte object

Index low

The object D7 most significant

D4 least significant

Write to the dictionary

0x600+ node ID

0x2F (for one byte only)

Index low

Index high

Sub index

D4 the data to be written

Write response 0x580+ node ID

0x60

Index low

Index high

Sub index

zeros

6.4 State request test The state of the inputs should be read on request, by reading the value of the input port from the object dictionary the test was successfully completed .

42

6.5 node state change commands: These commands were successfully tested as shown in table 22. Start remote node Stop remote node Enter preoperational mode Node reset Table 22 node state change command values Message Data Data bytre0 value 0x01 02 0x01 Data byte1 value Node ID Start node , operational mode All messages are available The heart beat data byte 0 is 0x05 0x01 02 0x02 Node ID Stop node No communication except the heart beat 0x01 02 0x80 Node ID Preoperational mode SDO messaging and heartbeat only The heart beat data byte 0 is 0x04 The heart beat data byte 0 is 0x7F 0x01 02 0x82 Node ID Reset communication The node will restart as if it was powered off and powered on again The boot up message will be sent again data byte 0 is 0 The state Function Response

identifier length

43

Conclusion
The field of Industrial automation is developing rapidly , new technologies have appeared to reduce costs and to increase efficiency in industry ,recent trends in automation are to use intelligent and wireless instruments , some researchers are even working to make communication with DCS systems through internet a safe and feasible solution ,in this field Remote I/O modules with CANopen have competitive characteristics. In this project the implementation for digital I/O module has been described in details in terms of hardware and software, and finally the module has been successfully tested.

44

References:
[1] Friedmann, Paul G. (2006). Automation and Control Systems Economics. (2nd Edition) [Online]. Available: http://www.knovel.com Farsi, Mohammed Barbosa Manuel, CANopen implementation, application to industrial networks, Research Studies Press Ltd, 2000, pp 1 Whitt, Michael.(2004). Successful Instrumentation and Control Systems Design. [Online]. Available: http://www.knovel.com [4] Bolton, W. (2006). Programmable Logic Controllers. (4th Edition). [Online]. Available: http://www.knovel.com [5] McMillan, G.K.; Considine, D.M.(1999). Process/Industrial Instruments and Controls ... . Handbook. (5th Edition) [Online]. Available: http://www.knovel.com. [6] . . [7] Feng-Li Lian; Moyne, J.R.; Tilbury, D.M.; Performance evaluation of control networks: Ethernet, ControlNet, and DeviceNet, in Control Systems Magazine, IEEE Volume 21, Issue 1, , pp:66 83, Feb. 2001 Process Control Security Requirements Forum (PCSRF)working group, Generic composite industrial control system network architecture-DCS,NIST National Institute of Standards and Technology U.S,[ONLINE] Available: http://www.isd.mel.nist.gov/projects/processcontrol/members/documents/diagram_ DCS.gif Adnan Salihbegovi ,Zoran Cico, Vlatko Marinkovi, Elvedin Karavdi, software engineering approach in the design and development of the industrial automation systems, proceedings of the 2008 international workshop on Software Engineering in east and south Europe, 2008, in technical presentations, pp:15-22. Daniel, R.A., Ethernet-a natural evolution for remote I/O, in: WESCON/96, 1996, pp 610 616 Palls-Areny, Ramon; Webster, John G.(2001). Sensors and Signal Conditioning., (2nd Edition) [Online]. Available: http://www.knovel.com D. W. Clarke, Intelligent instrumentation, Transactions of the Institute of Measurement and Control, vol. 22: pp. 3 27, Mar 2000;
Jimmy Kjellsson, Anne Elisabeth Vallestad, Richard Steigmann, and Dacfey Dzung,Integration of a wireless I/O Interface for PROFIBUS and PROFINET for

[2]

[3]

[8]

[9] , [10] . [11] ... [12]

Factory Automation, Industrial Electronics, IEEE Transactions on Volume 56, Issue 10,pp:4279 - 4287 ,Oct. 2009.

45

[13]

Gungor, V.C.; Hancke, G.P,Industrial Wireless Sensor Networks: Challenges, Design Principles, and Technical Approaches,Industrial Electronics, IEEE Transactions on Volume 56, Issue 10, Page(s):4258 4265, Oct. 2009. Gnad, A.; Kratzig, M.; Rauchhaupt, L.; Trikaliotis, S,Relevant influences in wireless automation, WFCS 2008. IEEE International Workshop on Page(s):341 348, 21-23 May 2008. Ando, B.; Savalli, N, instrumentationnotes - CANBUS Networked Sensors Use in Orientation Tools for the Visually Impaired Wired versus Wireless Technology, Instrumentation & Measurement Magazine, IEEE ,Volume 11, Issue 1, pp:49 52, Feb. 2008. Halsall, Fred: Title Data communications, computer networks, and open systems, .. (4th Edition),1996,pp 15-18. American Society of Heating, Refrigerating and Air-Conditioning Engineers.(2009). ASHRAE Handbook - Fundamentals. [Online]. Available: http://www.knovel.com. Jasperneite, J.; Imtiaz, J.; Schumacher, M.; Weber, K.; A Proposal for a Generic RealTime Ethernet System, Industrial Informatics, IEEE Transactions on Volume 5, Issue 2 pp: 75 85, May 2009. Bob Yeager, President Emerson Power & Water Solutions,Distributed Control . . Technology: From A Decade of Progress to an Era of New Possibilities, presented at 2008 POWID Conference PO44, [ONLINE] Available: . . . . . . . . http://www.isa.org/filestore/Division_TechPapers/GlassCeramics/POW08-P044Final.pdf Strothman, Jim.(2006).Handbook of Measurement Equations and Tables. (2nd Edition).[Online]. Available: http://www.knovel.com

[14]

[15]

[16] . [17] [18] . , [19] . . . [20]

[21]

Wei-ming Tong; Hong-wei Gao; A Fieldbus Comprehensive Evaluation and Selection Method Based on Entropy-Ideal Point, ISDA '08. Eighth International Conference on , Volume 2, pp: 564 568, 26-28 Nov. 2008. Cia Control in automation,CAN history [Online]. Available: http://www.can-cia.org/index.php?id=161 , http://www.can-cia.org/index.php?id=48 & http://www.can-cia.org/index.php?id=49 Ando, B.; Baglio, S.; La Malfa, S.; Marletta, V.; Savalli, N.; A distributed sensor network approach for orientation tasks, Intrumentation and Measurement Technology Conference, IEEE, pp: 1215, 5-7 May 2009. Microchip technology Inc. PIC18F2585/2680/4585/4680 Data Sheet, 2007.
46

[22]

[23]

[24]

[25] [26] [27]

Caio Gbel , Comparing CAN and ECAN Modules , Microchip technology Inc. ,2004. Microchip technology Inc. MCP2551 high-speed CAN transceiver Data Sheet, 2003. Ross M. Fosler , A CANopen Stack for PIC18 ECAN Microcontrollers , Microchip technology Inc. ,2004. Microchip technology Inc. MCP2515CAN Bus Monitor Demo Board Users Guide, 2008.

[28]

47

Appendix
All C code programs used in this implementation is shown in this appendix, however all header files are available online:
(http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en020605).

Obviously no change was applied for them, because of their big size they are not shown here.

1- Main.c
/***************************************************************************** * * Microchip CANopen Stack (Main Entry) * ***************************************************************************** * FileName: main.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * * Software License Agreement * * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * * This is the main entry into the demonstration. In this file some startup * and running conditions are demonstrated. * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... * *****************************************************************************/

48

#include #include #include #include

"CO_MAIN.H" "Timer.H" "DemoObj.h" "p18f2585.h"

#pragma config LVP = OFF // disable Low voltage programming #pragma config DEBUG = OFF //disable debug mode unsigned char test3[0x20]; unsigned long msgID; unsigned char hMsg; unsigned char node; unsigned char node0; unsigned char baud;
/********************************************************************* * Function: void main(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: Main entry into the application. * * Note: The following is simply a demonstration of * initialization and running the CANopen stack. ********************************************************************/

void main(void) { // Perform any application specific initialization TimerInit(); // Init my timer

TRISA=0xFF; // Set PORTA as input TRISB=0xFF; // Set PORTB as input ADCON1 = 0x0F; // Setting PORTA bits0-3 to operate as digital ports node0=0; node=0; baud=0; node0= ~PORTA & 0x07 ; // reading portA 0-3 if(node0 == 0) node = 1; else node = node0; baud=~PORTB & 0x03; // reading portB 0-1 mCO_SetNodeID(node); // Set the Node ID mCO_SetBaud(baud); // Set the baudrate mNMTE_SetHeartBeat(4000); // Set the initial heartbeat mNMTE_SetGuardTime(0000); // Set the initial guard time mNMTE_SetLifeFactor(0x00); // Set the initial life time DemoInit(); // Initialize my demo

49

mCO_InitAll(); while(1) { // Process CANopen events mCO_ProcessAllEvents();

// Initialize CANopen to run, bootup will be sent

// Process application specific functions DemoProcessEvents(); // 1ms timer events if (TimerIsOverflowEvent()) { // Process timer related events mCO_ProcessAllTimeEvents(); } } }

2. Timer.c
/***************************************************************************** * Timer ***************************************************************************** * FileName: Timer.c * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.10.02 or higher * Linker: MPLINK 03.20.01 or higher * Company: Microchip Technology Incorporated * Software License Agreement * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * This is a simple timer function used within the DeviceNet Stack for * demonstration. * Author Date Comment * Ross Fosler 04/28/03 ...

*****************************************************************************/

50

#include "P18F2585.H" #pragma romdata CONFIG1H = 0x300001 const rom unsigned char config1H = 0b00000010; #pragma romdata CONFIG2L = 0x300002 const rom unsigned char config2L = 0b00000000; #pragma romdata CONFIG3H = 0x300005 const rom unsigned char config3H = 0b10000000; #define #define #define #if #define #elif #define #elif #define #elif #define #elif #define #elif #define #elif #define #elif #define #else #define #define #endif TIMER_PERIOD_MS TIMER_FOSC TIMER_PRESCALE TIMER_PRESCALE == 0 TIMER_PRESCALE_VALUE TIMER_PRESCALE == 1 TIMER_PRESCALE_VALUE TIMER_PRESCALE == 2 TIMER_PRESCALE_VALUE TIMER_PRESCALE == 3 TIMER_PRESCALE_VALUE TIMER_PRESCALE == 4 TIMER_PRESCALE_VALUE TIMER_PRESCALE == 5 TIMER_PRESCALE_VALUE TIMER_PRESCALE == 6 TIMER_PRESCALE_VALUE TIMER_PRESCALE == 7 TIMER_PRESCALE_VALUE TIMER_PRESCALE_VALUE TIMER_PRESCALE 8 8 25000000L 7 2 4 8 16 32 64 128 256 1 //register CONFIG1H //HS mode external oscillator //register CONF2G1H //enabling PWRT //register CONFIG3H // enabling MCLR pin // Period in milliseconds // Frequency of the processor clock // The desired prescale

/********************************************************************* * Function: void TimerInit(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: None * * Overview: Initializes Timer0 for use. * * Note: None ********************************************************************/

void TimerInit(void) { T0CON = 0x40 | TIMER_PRESCALE;

51

TMR0L = 255L - ((TIMER_PERIOD_MS * TIMER_FOSC) / 1000L / 4 / TIMER_PRESCALE_VALUE); T0CONbits.TMR0ON = 1; INTCONbits.TMR0IF = 0; }

/********************************************************************* * Function: unsigned char TimerIsOverflowEvent(void) * * PreCondition: none * * Input: none * * Output: unsigned char status * * Side Effects: None * * Overview: Checks for an overflow event, returns TRUE if * an overflow occured. * * Note: This function should be checked at least twice * per overflow period. ********************************************************************/

unsigned char TimerIsOverflowEvent(void) { static unsigned char temp; if (INTCONbits.TMR0IF) { temp = 256L - ((TIMER_PERIOD_MS * TIMER_FOSC) / 1000L / 4 / TIMER_PRESCALE_VALUE); TMR0L += temp; INTCONbits.TMR0IF = 0; return(1); } return(0); }

52

3. CO_CANDRV.C
/***************************************************************************** * * Microchip CANopen Stack (ECAN Driver For CANopen) * ***************************************************************************** * FileName: CO_CANDRV.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * * Software License Agreement * * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * * * * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... * *****************************************************************************/

#include #include #include #include #include

"CO_DEFS.DEF" "CO_TYPES.H" "CO_CANDRV.H" "p18f2585.h" "p18cxxx.h"

// Global definitions // Driver services

53

// Definition of a Microchip CAN filter typedef union __FILTER { unsigned long dword; struct __BYTES { unsigned char SIDH; unsigned char SIDL; unsigned char EIDH; unsigned char EIDL; }bytes; }_FILTER;

// Parameter area unsigned char _uCAN_Handle; unsigned char _uCAN_Param1; unsigned char _uCAN_Param2; unsigned char _uCAN_Param3; unsigned char _uCAN_Param4; unsigned char _uCAN_ret;

// Statically passed parameters

// Driver related static data unsigned char _uCAN_Bitrate; unsigned char _uCANRxHndls[CAN_MAX_RCV_ENDP]; _FILTER _uCANRxIDRes[CAN_MAX_RCV_ENDP]; unsigned char _uCANTxHndls[3]; unsigned char _uCANReq; unsigned char _uCANOldMode;

// Stored bitrate // Filter handles // Filters // Transmit handles

// Queued driver request

/* ******** CAN Control Services ******* */

/********************************************************************* * Function: void _CANEventManager(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This function processes any queued requests in * the CAN driver. * * Note: ********************************************************************/

54

void _CANEventManager(void) { if (_uCANReq) { switch (_uCANReq) { // Filter has been modified, re-sync case 1: // Check for config mode if (CANSTATbits.OPMODE2) { if (_uCANRxHndls[0]) {*(_FILTER *)(&RXF0SIDH) = _uCANRxIDRes[0]; RXFCON0bits.RXF0EN = 1;} else RXFCON0bits.RXF0EN = 0; #if CAN_MAX_RCV_ENDP > 1 if (_uCANRxHndls[1]) {*(_FILTER *)(&RXF1SIDH) = _uCANRxIDRes[1]; RXFCON0bits.RXF1EN = 1;} else RXFCON0bits.RXF1EN = 0; #endif #if CAN_MAX_RCV_ENDP > 2 if (_uCANRxHndls[2]) {*(_FILTER *)(&RXF2SIDH) = _uCANRxIDRes[2]; RXFCON0bits.RXF2EN = 1;} else RXFCON0bits.RXF2EN = 0; #endif #if CAN_MAX_RCV_ENDP > 3 if (_uCANRxHndls[3]) {*(_FILTER *)(&RXF3SIDH) = _uCANRxIDRes[3]; RXFCON0bits.RXF3EN = 1;} else RXFCON0bits.RXF3EN = 0; #endif #if CAN_MAX_RCV_ENDP > 4 if (_uCANRxHndls[4]) {*(_FILTER *)(&RXF4SIDH) = _uCANRxIDRes[4]; RXFCON0bits.RXF4EN = 1;} else RXFCON0bits.RXF4EN = 0; #endif #if CAN_MAX_RCV_ENDP > 5 if (_uCANRxHndls[5]) {*(_FILTER *)(&RXF5SIDH) = _uCANRxIDRes[5]; RXFCON0bits.RXF5EN = 1;} else RXFCON0bits.RXF5EN = 0; #endif #if CAN_MAX_RCV_ENDP > 6 if (_uCANRxHndls[6]) {*(_FILTER *)(&RXF6SIDH) = _uCANRxIDRes[6]; RXFCON0bits.RXF6EN = 1;} else RXFCON0bits.RXF6EN = 0; #endif #if CAN_MAX_RCV_ENDP > 7 if (_uCANRxHndls[7]) {*(_FILTER *)(&RXF7SIDH) = _uCANRxIDRes[7]; RXFCON0bits.RXF7EN = 1;} else RXFCON0bits.RXF7EN = 0; #endif #if CAN_MAX_RCV_ENDP > 8

55

if (_uCANRxHndls[8]) {*(_FILTER *)(&RXF8SIDH) = _uCANRxIDRes[8]; RXFCON1bits.RXF8EN = 1;} else RXFCON1bits.RXF8EN = 0; #endif #if CAN_MAX_RCV_ENDP > 9 if (_uCANRxHndls[9]) {*(_FILTER *)(&RXF9SIDH) = _uCANRxIDRes[9]; RXFCON1bits.RXF9EN = 1;} else RXFCON1bits.RXF9EN = 0; #endif #if CAN_MAX_RCV_ENDP > 10 if (_uCANRxHndls[10]) {*(_FILTER *)(&RXF10SIDH) = _uCANRxIDRes[10]; RXFCON1bits.RXF10EN = 1;} else RXFCON1bits.RXF10EN = 0; #endif #if CAN_MAX_RCV_ENDP > 11 if (_uCANRxHndls[11]) {*(_FILTER *)(&RXF11SIDH) = _uCANRxIDRes[11]; RXFCON1bits.RXF11EN = 1;} else RXFCON1bits.RXF11EN = 0; #endif #if CAN_MAX_RCV_ENDP > 12 if (_uCANRxHndls[12]) {*(_FILTER *)(&RXF12SIDH) = _uCANRxIDRes[12]; RXFCON1bits.RXF12EN = 1;} else RXFCON1bits.RXF12EN = 0; #endif #if CAN_MAX_RCV_ENDP > 13 if (_uCANRxHndls[13]) {*(_FILTER *)(&RXF13SIDH) = _uCANRxIDRes[13]; RXFCON1bits.RXF13EN = 1;} else RXFCON1bits.RXF13EN = 0; #endif #if CAN_MAX_RCV_ENDP > 14 if (_uCANRxHndls[14]) {*(_FILTER *)(&RXF14SIDH) = _uCANRxIDRes[14]; RXFCON1bits.RXF14EN = 1;} else RXFCON1bits.RXF14EN = 0; #endif #if CAN_MAX_RCV_ENDP > 15 if (_uCANRxHndls[15]) {*(_FILTER *)(&RXF15SIDH) = _uCANRxIDRes[15]; RXFCON1bits.RXF15EN = 1;} else RXFCON1bits.RXF15EN = 0; #endif // Cancel the request _uCANReq = 0; // Request normal operation CANCON = _uCANOldMode;; } // Request config mode else CANCON = 0x80; break;

56

case 2: // Check for config mode if (CANCONbits.REQOP2) { // Set the bitrate _CANSetBitRate(); // Cancel the request _uCANReq = 0; // Request normal operation CANCON = _uCANOldMode;; } // Request config mode else CANCON = 0x80; break; } } }

/********************************************************************* * Function: void _CANReset(void) * * PreCondition: none * * Input: unsigned char _uCAN_Bitrate * * Output: none * * Side Effects: none * * Overview: All aspects of the CAN driver are reset. * * Note: This function does not automatically enable the * device on the network. ********************************************************************/

void _CANReset(void) { // Empty an queued requests _uCANReq = 0; // Force the CAN peripherial into Config mode CANCON = 0x40; CANCON = 0x80; // Set the bitrate _CANSetBitRate(); // Make all programmable buffers receive buffers BSEL0 = 0x00;

57

// Setup the receive buffers RXB0CON = 0; RXB1CON = 0; B0CON = 0; B1CON = 0; B2CON = 0; B3CON = 0; B4CON = 0; B5CON = 0;

// Place the module in enhanced legacy mode ECANCON = 0x50; // Disable all filters RXFCON0 = 0; RXFCON1 = 0; // No data byte filtering SDFLC = 0; // Setup filter/buffer association, two filters per buffer RXFBCON0 = 0x00; RXFBCON1 = 0x11; RXFBCON2 = 0x22; RXFBCON3 = 0x33; RXFBCON4 = 0x44; RXFBCON5 = 0x55; RXFBCON6 = 0x66; RXFBCON7 = 0x77; // Setup filter/mask association to Mask 0 MSEL0 = MSEL1 = MSEL2 = MSEL3 = 0; // Set Mask 0 to not mask any filter bit RXM0SIDH = 0xFF; RXM0SIDL = 0xE3; RXM0EIDH = 0xFF; RXM0EIDL = 0xFF; // Set I/O control CIOCON = 0x20; // Set interrupts TXBIE = 0x1C; BIE0 = 0xFF; // Reset all handles _uCANRxHndls[0] = 0; #if CAN_MAX_RCV_ENDP > 1 _uCANRxHndls[1] = 0; #endif

58

#if CAN_MAX_RCV_ENDP > 2 _uCANRxHndls[2] = 0; #endif #if CAN_MAX_RCV_ENDP > 3 _uCANRxHndls[3] = 0; #endif #if CAN_MAX_RCV_ENDP > 4 _uCANRxHndls[4] = 0; #endif #if CAN_MAX_RCV_ENDP > 5 _uCANRxHndls[5] = 0; #endif #if CAN_MAX_RCV_ENDP > 6 _uCANRxHndls[6] = 0; #endif #if CAN_MAX_RCV_ENDP > 7 _uCANRxHndls[7] = 0; #endif #if CAN_MAX_RCV_ENDP > 8 _uCANRxHndls[8] = 0; #endif #if CAN_MAX_RCV_ENDP > 9 _uCANRxHndls[9] = 0; #endif #if CAN_MAX_RCV_ENDP > 10 _uCANRxHndls[10] = 0; #endif #if CAN_MAX_RCV_ENDP > 11 _uCANRxHndls[11] = 0; #endif #if CAN_MAX_RCV_ENDP > 12 _uCANRxHndls[12] = 0; #endif #if CAN_MAX_RCV_ENDP > 13 _uCANRxHndls[13] = 0; #endif #if CAN_MAX_RCV_ENDP > 14 _uCANRxHndls[14] = 0; #endif #if CAN_MAX_RCV_ENDP > 15 _uCANRxHndls[15] = 0; #endif }

59

/********************************************************************* * Function: void _CANSetBitRate(void) * * PreCondition: This function should only be called when the * device is not active on the CAN bus. * Input: unsigned char _uCAN_Bitrate * Output: none * Side Effects: none * Overview: The predefined BRG values are set. * Note: This message is intended to be called from within * the event manager. It is also called on reset. * An invalid bitrate will default to _BITRATE0 ********************************************************************/

void _CANSetBitRate(void) { switch(_uCAN_Bitrate) { case 0x00: BRGCON1 = CAN_BITRATE0_BRGCON1; BRGCON2 = CAN_BITRATE0_BRGCON2; BRGCON3 = CAN_BITRATE0_BRGCON3; break; #if CAN_BITRATE2 case 0x01: BRGCON1 = CAN_BITRATE2_BRGCON1; BRGCON2 = CAN_BITRATE2_BRGCON2; BRGCON3 = CAN_BITRATE2_BRGCON3; break; #endif #if CAN_BITRATE4 case 0x02: BRGCON1 = CAN_BITRATE4_BRGCON1; BRGCON2 = CAN_BITRATE4_BRGCON2; BRGCON3 = CAN_BITRATE4_BRGCON3; break; #endif #if CAN_BITRATE5 case 0x03: BRGCON1 = CAN_BITRATE5_BRGCON1; BRGCON2 = CAN_BITRATE5_BRGCON2; BRGCON3 = CAN_BITRATE5_BRGCON3; break; #endif default: BRGCON1 = CAN_BITRATE0_BRGCON1; BRGCON2 = CAN_BITRATE0_BRGCON2; BRGCON3 = CAN_BITRATE0_BRGCON3; break; } }

/* 1Mbit */

/* 500kbits */

/* 250kbits */

/* 125kbits */

60

/* ******** Message Write Services ******* */


/********************************************************************* * Function: void _CANIsPutReady(void) * * PreCondition: A message must have been placed on the bus * for this function to ever report anything. * * Input: unsigned char _uCAN_Handle * * Output: unsigned char _uCAN_ret * * Side Effects: none * * Overview: This function scans for an available output * buffer. If successful the handle passed is the * same as the handle returned. Else a NULL is * returned on a failure. * * Note: Buffer access on successive transmit related calls * is assumed. I.E. the handle is not required for * associated write functions. ********************************************************************/

void _CANIsPutReady(void) { // Check to see if buffer 0 is available if (!TXB0CONbits.TXREQ) {ECANCON = 0x43; _uCAN_ret = _uCANTxHndls[0] = _uCAN_Handle;} // Else check to see if buffer 1 is available else if (!TXB1CONbits.TXREQ) {ECANCON = 0x44; _uCAN_ret = _uCANTxHndls[1] = _uCAN_Handle;} // Else check to see if buffer 2 is available else if (!TXB2CONbits.TXREQ) {ECANCON = 0x45; _uCAN_ret = _uCANTxHndls[2] = _uCAN_Handle;} // Else no more buffers available else {_uCAN_ret = 0;} }

61

/********************************************************************* * Function: void _CANIsPutFin(void) * * PreCondition: A message must have been placed on the bus * for this function to ever report anything. * * Input: none * * Output: unsigned char _uCAN_ret * * Side Effects: none * * Overview: This function scans the output buffers for any * int flags indicating data has been sent. The * handle to the message is returned to the user. * * Note: This function should only be called one time for * a tx indication. Calling a second time after * receiving an indication may not return the same * handle. ********************************************************************/

void _CANIsPutFin(void) { // Check to see if buffer 0 has sent a message if (TXB0CONbits.TXBIF) {ECANCON = 0x43; TXB0CONbits.TXBIF = 0; _uCAN_ret = _uCANTxHndls[0];} // Else check to see if buffer 1 has sent a message else if (TXB1CONbits.TXBIF) {ECANCON = 0x44; TXB0CONbits.TXBIF = 0; _uCAN_ret = _uCANTxHndls[1];} // Else check to see if buffer 2 has sent a message else if (TXB2CONbits.TXBIF) {ECANCON = 0x45; TXB0CONbits.TXBIF = 0; _uCAN_ret = _uCANTxHndls[2];} // Else no message was sent else {_uCAN_ret = 0;} }

62

/* ******** Message Read Services ******* */


/********************************************************************* * Function: void _CANOpenMessage(void) * * PreCondition: _CANEventManager() must be called frequently for * proper operation. * * Input: (unsigned long) _uCAN_Param1 * * Output: unsigned char _uCAN_ret * * Side Effects: none * * Overview: This function scans the available mailbox space * for an open slot. If found the COBID is added to * the list of received messages. * * Note: The COBID is added but not activated until the * bus is ready. In future CAN modules this queuing * functionality may be removed depending on * hardware support. ********************************************************************/

void _CANOpenMessage(void) { unsigned char i; // Scan for an open filter for (i = 0; i < CAN_MAX_RCV_ENDP; i++) { if (_uCANRxHndls[i] == 0) { // Save the handle to the object _uCAN_ret = _uCANRxHndls[i] = _uCAN_Handle; // Store the ID in a buffer _uCANRxIDRes[i].dword = *(unsigned long *)(&_uCAN_Param1); // Set the filter change request flag _uCANReq = 1; return; } } _uCAN_ret = 0; }

63

/********************************************************************* * Function: void _CANCloseMessage(void) * * PreCondition: Must be a valid handle. * _CANEventManager() must be called frequently for * proper operation. * * Input: (unsigned long) _uCAN_Param1 * * Output: none * * Side Effects: none * * Overview: This function scans the mailbox space for the * handle. If found the COBID is removed from the * receive list. * * Note: The COBID is only queued to be removed from the * list. In future CAN modules this queuing * functionality may be removed depending on * hardware support. ********************************************************************/

void _CANCloseMessage(void) { unsigned char i; // Scan for an open filter for (i = 0; i < CAN_MAX_RCV_ENDP; i++) { if (_uCANRxHndls[i] == _uCAN_Handle) { // Remove the handle _uCANRxHndls[i] = 0; // Set the filter change request flag _uCANReq = 1; // Indicate a successful close of the message receive endpoint _uCAN_ret = 1; return; } } _uCAN_ret = 0; }

64

/********************************************************************* * Function: void _CANIsGetReady(void) * * PreCondition: none * * Input: none * * Output: unsigned char _uCAN_ret * * Side Effects: none * * Overview: This function scans for a receive event. If found * it returns the handle associated to the receive * buffer. Otherwise it returns NULL. * * Note: Buffer access on successive receive related calls * is assumed. I.E. the handle is not required for * associated read functions. ********************************************************************/

void _CANIsGetReady(void) { // Check for a receive interrupt if (PIR3bits.RXB1IF) { // Default receive buffer ECANCON = 0x50; // Check for an interrupt and set the appropriate buffer if (RXB0CONbits.RXFUL) {} #if CAN_MAX_RCV_ENDP > 2 else if (RXB1CONbits.RXFUL) {ECANCON = 0x51;} #endif #if CAN_MAX_RCV_ENDP > 4 else if (B0CONbits.RXFUL) {ECANCON = 0x52;} #endif #if CAN_MAX_RCV_ENDP > 6 else if (B1CONbits.RXFUL) {ECANCON = 0x53;} #endif #if CAN_MAX_RCV_ENDP > 8 else if (B2CONbits.RXFUL) {ECANCON = 0x54;} #endif #if CAN_MAX_RCV_ENDP > 10 else if (B3CONbits.RXFUL) {ECANCON = 0x55;} #endif #if CAN_MAX_RCV_ENDP > 12 else if (B4CONbits.RXFUL) {ECANCON = 0x56;} #endif #if CAN_MAX_RCV_ENDP > 14 else if (B5CONbits.RXFUL) {ECANCON = 0x57;} #endif else {_uCAN_ret = 0; PIR3bits.RXB1IF = 0; return;} // Remove the interrupt, it will set again if more are pending //PIR3bits.RXB1IF = 0;

65

// Decode which filter passed the event and return the handle // associated to the filter _uCAN_ret = *((RXB0CON & 0x0F) + _uCANRxHndls); } else _uCAN_ret = 0; }

4. CO_COMM.c
/***************************************************************************** * * Microchip CANopen Stack (Communications Management) * ***************************************************************************** * FileName: CO_COMM.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * Software License Agreement * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * * This is the primary communications management. Within this file all events * are received and dispached to the appropriate handling functions. * * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ...*/

66

#include #include #include #include

"CO_DEFS.DEF" "CO_TYPES.H" "CO_CANDRV.H" "CO_COMM.H"

// Global definitions // Data types // Driver services // Object // Networm Management // SYNC Object support // SDO1, the default SDO // Error protocols: heartbeat, node-guard // EMCY Object support // Time Stamp Object Support // PDOs

#include "CO_NMT.H" #include "CO_SYNC.H" #include "CO_SDO1.H" #include "CO_NMTE.H" //#include "CO_EMCY.H" //#include "CO_TIME.H" #include "CO_PDO.H" #include "p18f2585.h"

void CO_PDO1LSTimerEvent(void); void CO_PDO1TXFinEvent(void); #if CO_NUM_OF_PDO > 1 void CO_PDO2LSTimerEvent(void); void CO_PDO2TXFinEvent(void); #endif #if CO_NUM_OF_PDO > 2 void CO_PDO3LSTimerEvent(void); void CO_PDO3TXFinEvent(void); #endif #if CO_NUM_OF_PDO > 3 void CO_PDO4LSTimerEvent(void); void CO_PDO4TXFinEvent(void); #endif

// The node ID for this device, 1 - 127 is valid. UNSIGNED8 _uCO_nodeID; // State flags, UNSIGNED8 _uCO_state; // Baudrate UNSIGNED8 _uCO_baud; // Flags used to verify certain connections are enabled UNSIGNED8 _net_en; UNSIGNED8 _sdo_en; UNSIGNED8 _rpdo_en; UNSIGNED8 _tpdo_en; // Transmit queue flags, if a flag is set then an object is ready to send a message UNSIGNED8 _tx_net_que; UNSIGNED8 _tx_sdo_que; UNSIGNED8 _tx_pdo_que;

67

// Receive flag UNSIGNED8 _rx_net_flg; UNSIGNED8 _rx_sdo_flg; UNSIGNED8 _rx_pdo_flg;

/********************************************************************* * Function: void _CO_COMMResetEventManager(void) * * PreCondition: All driver and CANopen initialization must be * complete before calling this function. * * Input: none * * Output: none * * Side Effects: none * * Overview: This function resets communications. * * Note: ********************************************************************/ void _CO_COMMResetEventManager(void) { // Kill any existing states _uCO_state.byte = 0; // Disable all COMM objects _net_en.byte = 0; _sdo_en.byte = 0; _rpdo_en.byte = 0; _tpdo_en.byte = 0; _tx_net_que.byte = 0; _tx_sdo_que.byte = 0; _tx_pdo_que.byte = 0; _rx_net_flg.byte = 0; _rx_sdo_flg.byte = 0; _rx_pdo_flg.byte = 0; // Issue a reset to the driver then open communications mCANReset(_uCO_baud.byte); // Issue a driver reset // Call all object reset handlers. All objects go online except PDOs. PDOs go // online when the appropriate parameter is enabled. _CO_COMM_NMT_Open(); // Start network management // _CO_COMM_SYNC_Open(); // Start SYNC support _CO_COMM_SDO1_Open(); // Start the default SDO // _CO_COMM_EMCY_Open(); // Reset the Emergency Object // _CO_COMM_TIME_Open(); // Reset the Time Stamp Object _CO_COMM_NMTE_Open(); // Start the error protocol, heartbeat or node-guard _CO_COMM_PDO1_Open(); // Start the pdo1

68

// Process driver events for the first time _CANEventManager(); // Request to open communications mCANOpenComm(); // Send boot-up message NMTE_BOOT_SERVICE = 1; mCANIsPutReady(0); _CO_COMM_NMTE_TXEvent(); mCANSendMessage(); // Finished, so enter into preop state COMM_STATE_PREOP = 1; }

/********************************************************************* * Function: void _CO_COMMRXEventManager(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This function dispatches any receive events. * * Note: ********************************************************************/ void _CO_COMMRXEventManager(void) { // Call the driver for any received messages, if there are any then // determine which object the message is for mCANIsGetReady(); // If at least in a pre-operational state and // if the handle is valid then decode and generate the appropriate event if (COMM_STATE_PREOP) if (mCANFetchRetHandle()) { // Test the group of the message switch(mCANFetchRetHandle() & COMM_MSGGRP_MASK) { case COMM_MSGGRP_NETCTL: // Network management switch(mCANFetchRetHandle() & COMM_MSG_MASK) { case COMM_NETCTL_NMT: if (COMM_NETCTL_NMT_EN) _CO_COMM_NMT_RXEvent(); break;

69

// case COMM_NETCTL_SYNC: // if (COMM_NETCTL_SYNC_EN) {if (!COMM_STATE_STOP) _CO_COMM_SYNC_RXEvent();} // break; // case COMM_NETCTL_TMSTP: // if (COMM_NETCTL_TMSTP_EN) {if (!COMM_STATE_STOP) _CO_COMM_TIME_RXEvent();} // break; case COMM_NETCTL_NMTE: if (COMM_NETCTL_NMTE_EN) _CO_COMM_NMTE_RXEvent(); break; default: // Driver error: driver passed a message that has no endpoint /*call func*/ break; } break;

case COMM_MSGGRP_SDO: // SDOs if (!COMM_STATE_STOP) { switch(mCANFetchRetHandle() & COMM_MSG_MASK) { case COMM_SDO_1: //SDO1 if (COMM_SDO_1_EN) _CO_COMM_SDO1_RXEvent(); break; // case COMM_SDO_2: //SDO1 // if (COMM_SDO_2_EN) _CO_COMM_SDO2_RXEvent(); // break; // case COMM_SDO_3: //SDO1 // if (COMM_SDO_3_EN) _CO_COMM_SDO3_RXEvent(); // break; // case COMM_SDO_4: //SDO1 // if (COMM_SDO_4_EN) _CO_COMM_SDO4_RXEvent(); // break; default: // Driver error: driver passed a message that has no endpoint /*call func*/ break; } } break;

70

case COMM_MSGGRP_PDO: // PDOs if (!COMM_STATE_STOP) if (COMM_STATE_OPER) { switch(mCANFetchRetHandle() & COMM_MSG_MASK) { case COMM_PDO_1: //PDO1 if (COMM_RPDO_1_EN) {if (!COMM_PDO_1_RF){COMM_PDO_1_RF = 1; _CO_COMM_PDO1_RXEvent();}} break; #if CO_NUM_OF_PDO > 1 case COMM_PDO_2: //PDO2 if (COMM_RPDO_2_EN) {if (!COMM_PDO_2_RF){COMM_PDO_2_RF = 1; _CO_COMM_PDO2_RXEvent();}} break; #endif #if CO_NUM_OF_PDO > 2 case COMM_PDO_3: //PDO3 if (COMM_RPDO_3_EN) {if (!COMM_PDO_3_RF){COMM_PDO_3_RF = 1; _CO_COMM_PDO3_RXEvent();}} break; #endif #if CO_NUM_OF_PDO > 3 case COMM_PDO_4: //PDO4 if (COMM_RPDO_4_EN) {if (!COMM_PDO_4_RF){COMM_PDO_4_RF = 1; _CO_COMM_PDO4_RXEvent();}} break; #endif // case COMM_PDO_5: //PDO4 // if (COMM_PDO_5_EN) {if (!COMM_PDO_5_RF){COMM_PDO_5_RF = 1; _CO_COMM_PDO5_RXEvent();}} // break; // case COMM_PDO_6: //PDO4 // if (COMM_PDO_6_EN) {if (!COMM_PDO_6_RF){COMM_PDO_6_RF = 1; _CO_COMM_PDO6_RXEvent();}} // break; // case COMM_PDO_7: //PDO4 // if (COMM_PDO_7_EN) {if (!COMM_PDO_7_RF){COMM_PDO_7_RF = 1; _CO_COMM_PDO7_RXEvent();}} // break; // case COMM_PDO_8: //PDO4 // if (COMM_PDO_8_EN) {if (!COMM_PDO_8_RF){COMM_PDO_8_RF = 1; _CO_COMM_PDO8_RXEvent();}} // break; default: // Driver error: driver passed a message that has no endpoint /*call func*/ break; } } break;

71

default: // Driver error: driver passed a message that has no endpoint /*call func*/ break; } // Release the driver's receive buffer mCANReadMessage(); } }

/********************************************************************* * Function: void _CO_COMMTXRdyEventManager(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This function dispatches any transmit events. * * Note: ********************************************************************/ void _CO_COMMTXRdyEventManager(void) { // Call the driver to check buffer availability, an arbitrairy // handle is used to get status mCANIsPutReady(1) // If at least in a pre-operational state and // If the buffer is available then generate the tx event if (COMM_STATE_PREOP) if (mCANFetchRetStat()) { if (COMM_NETCTL_TF) { if (COMM_NETCTL_NMTE_TF) { if (COMM_NETCTL_NMTE_EN) {mCANIsPutReady(COMM_MSGGRP_NETCTL | COMM_NETCTL_NMTE); _CO_COMM_NMTE_TXEvent(); mCANSendMessage();} COMM_NETCTL_NMTE_TF = 0; }

72

else // if (COMM_NETCTL_EMCY_TF) // { // if (COMM_NETCTL_EMCY_EN) // { // if (!COMM_STATE_STOP) {mCANIsPutReady(COMM_MSGGRP_NETCTL | COMM_NETCTL_EMCY); _CO_COMM_EMCY_TXEvent(); mCANSendMessage();} // } // // COMM_NETCTL_EMCY_TF = 0; // } // else //Error, a message was queued in an object that does not exist {COMM_NETCTL_TF = 0;} } else if (COMM_SDO_TF) { if (!COMM_STATE_STOP) { if (COMM_SDO_1_TF) { if (COMM_SDO_1_EN) {mCANIsPutReady(COMM_MSGGRP_SDO | COMM_SDO_1); _CO_COMM_SDO1_TXEvent(); mCANSendMessage();} COMM_SDO_1_TF = 0; } else // if (COMM_SDO_2_TF) // { // if (COMM_SDO_2_EN) {mCANIsPutReady(COMM_MSGGRP_SDO | COMM_SDO_2); _CO_COMM_SDO2_TXEvent(); mCANSendMessage();} // COMM_SDO_2_TF = 0; // } // else // if (COMM_SDO_3_TF) // { // if (COMM_SDO_3_EN) {mCANIsPutReady(COMM_MSGGRP_SDO | COMM_SDO_3); _CO_COMM_SDO3_TXEvent(); mCANSendMessage();} // COMM_SDO_3_TF = 0; // } // else // if (COMM_SDO_4_TF) // { // if (COMM_SDO_4_EN) {mCANIsPutReady(COMM_MSGGRP_SDO | COMM_SDO_4); _CO_COMM_SDO4_TXEvent(); mCANSendMessage();} // COMM_SDO_4_TF = 0; // }

73

//

else //Error, a message was queued in an object that does not exist {COMM_SDO_TF = 0;} } } else

if (COMM_PDO_TF) { if (COMM_STATE_OPER) if (!COMM_STATE_STOP) { if (COMM_PDO_1_TF) { if (COMM_TPDO_1_EN) {mCANIsPutReady(COMM_MSGGRP_PDO | COMM_PDO_1); _CO_COMM_PDO1_TXEvent(); mCANSendMessage();} COMM_PDO_1_TF = 0; } else #if CO_NUM_OF_PDO > 1 if (COMM_PDO_2_TF) { if (COMM_TPDO_2_EN) {mCANIsPutReady(COMM_MSGGRP_PDO | COMM_PDO_2); _CO_COMM_PDO2_TXEvent(); mCANSendMessage();} COMM_PDO_2_TF = 0; } else #endif #if CO_NUM_OF_PDO > 2 if (COMM_PDO_3_TF) { if (COMM_TPDO_3_EN) {mCANIsPutReady(COMM_MSGGRP_PDO | COMM_PDO_3); _CO_COMM_PDO3_TXEvent(); mCANSendMessage();} COMM_PDO_3_TF = 0; } else #endif #if CO_NUM_OF_PDO > 3 if (COMM_PDO_4_TF) { if (COMM_TPDO_4_EN) {mCANIsPutReady(COMM_MSGGRP_PDO | COMM_PDO_4); _CO_COMM_PDO4_TXEvent(); mCANSendMessage();} COMM_PDO_4_TF = 0; } else #endif // if (COMM_PDO_5_TF) // { // if (COMM_PDO_5_EN) {mCANIsPutReady(COMM_MSGGRP_PDO | COMM_PDO_5); _CO_COMM_PDO5_TXEvent(); mCANSendMessage();}

74

// COMM_PDO_5_TF = 0; // } // else // if (COMM_PDO_6_TF) // { // if (COMM_PDO_6_EN) {mCANIsPutReady(COMM_MSGGRP_PDO | COMM_PDO_6); _CO_COMM_PDO6_TXEvent(); mCANSendMessage();} // COMM_PDO_6_TF = 0; // } // else // if (COMM_PDO_7_TF) // { // if (COMM_PDO_7_EN) {mCANIsPutReady(COMM_MSGGRP_PDO | COMM_PDO_7); _CO_COMM_PDO7_TXEvent(); mCANSendMessage();} // COMM_PDO_7_TF = 0; // } // else // if (COMM_PDO_8_TF) // { // if (COMM_PDO_8_EN) {mCANIsPutReady(COMM_MSGGRP_PDO | COMM_PDO_8); _CO_COMM_PDO8_TXEvent(); mCANSendMessage();}

// // //

COMM_PDO_8_TF = 0; } else //Error, a message was queued in an object that does not exist {COMM_PDO_TF = 0;} }

} } } /********************************************************************* * Function: void _CO_COMMTXFinEventManager(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This function dispatches any transmit finish events. * Note: ********************************************************************/

75

void _CO_COMMTXFinEventManager(void) { // Call the driver to determine if a message has been place on the bus mCANIsPutFin(); // If a message has been placed on the bus, then who's message // was it and generate an appropriate event if (COMM_STATE_PREOP) if (mCANFetchRetHandle()) { // Test the group of the message switch(mCANFetchRetHandle() & COMM_MSGGRP_MASK) { case COMM_MSGGRP_NETCTL: // Network management switch(mCANFetchRetHandle() & COMM_MSG_MASK) { // case COMM_NETCTL_NMTE: // if (COMM_NETCTL_NMTE_EN) _CO_COMM_NMTE_TXFinEvent(); // break; // case COMM_NETCTL_EMCY: // if (COMM_NETCTL_EMCY_EN) {if (!COMM_STATE_STOP) _CO_COMM_EMCY_TXFinEvent();} // break;

default: // Driver error: driver sent a message that has no endpoint /*call func*/ break; } break; case COMM_MSGGRP_SDO: // Addressed messages if (!COMM_STATE_STOP) { switch(mCANFetchRetHandle() & COMM_MSG_MASK) { // case COMM_SDO_1: //SDO1 // if (COMM_SDO_1_EN) _CO_COMM_SDO1_TXFinEvent(); // break; // case COMM_SDO_2: //SDO1 // if (COMM_SDO_2_EN) _CO_COMM_SDO2_TXFinEvent(); // break; // case COMM_SDO_3: //SDO1 // if (COMM_SDO_3_EN) _CO_COMM_SDO3_TXFinEvent(); // break;

76

// // _CO_COMM_SDO4_TXFinEvent(); // default:

case COMM_SDO_4: //SDO1 if (COMM_SDO_4_EN) break; // not valid, driver error /*call func*/ break;

} } break; case COMM_MSGGRP_PDO: // Direct messages if (COMM_STATE_OPER) if (!COMM_STATE_STOP) { switch(mCANFetchRetHandle() & COMM_MSG_MASK) { case COMM_PDO_1: //TPDO1 if (COMM_TPDO_1_EN){CO_PDO1TXFinEvent();} break; #if CO_NUM_OF_PDO > 1 case COMM_PDO_2: //RPDO1 if (COMM_TPDO_2_EN){CO_PDO2TXFinEvent();} break; #endif

// // // // // // // // // // // //

#if CO_NUM_OF_PDO > 2 case COMM_PDO_3: //TPDO2 if (COMM_TPDO_3_EN){CO_PDO3TXFinEvent();} break; #endif #if CO_NUM_OF_PDO > 3 case COMM_PDO_4: //RPDO2 if (COMM_TPDO_4_EN){CO_PDO4TXFinEvent();} break; #endif case COMM_PDO_5: //RPDO2 if (COMM_PDO_5_EN){CO_PDO5TXFinEvent();} break; case COMM_PDO_6: //RPDO2 if (COMM_PDO_6_EN){CO_PDO6TXFinEvent();} break; case COMM_PDO_7: //RPDO2 if (COMM_PDO_7_EN){CO_PDO7TXFinEvent();} break; case COMM_PDO_8: //RPDO2 if (COMM_PDO_8_EN){CO_PDO8TXFinEvent();} break;

77

default: // not valid, driver error /*call func*/ break; } } break; default: // not valid, driver error /*call func*/ break; } } } /********************************************************************* * Function: void _CO_COMMLSTimeEventManager(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This function dispatches any time events. * * Note: ********************************************************************/ void _CO_COMMLSTimeEventManager(void) { // If in at least a pre-operational state if (COMM_STATE_PREOP) { // PDO object time events if (COMM_TPDO_EN) { if (COMM_TPDO_1_EN){CO_PDO1LSTimerEvent();} #if CO_NUM_OF_PDO > 1 if (COMM_TPDO_2_EN){CO_PDO2LSTimerEvent();} #endif #if CO_NUM_OF_PDO > 2 if (COMM_TPDO_3_EN){CO_PDO3LSTimerEvent();} #endif #if CO_NUM_OF_PDO > 3 if (COMM_TPDO_4_EN){CO_PDO4LSTimerEvent();} #endif // if (COMM_PDO_5_EN){} // if (COMM_PDO_6_EN){} // if (COMM_PDO_7_EN){} // if (COMM_PDO_8_EN){} }

78

// Network related object time events if (COMM_NETCTL_EN) { // if (COMM_NETCTL_NMT_EN){/*call func*/;} // NMT // if (COMM_NETCTL_SYNC_EN){/*call func*/;} // SYNC // if (COMM_NETCTL_TMSTP_EN){/*call func*/;} // Time Stamp if (COMM_NETCTL_NMTE_EN){_CO_COMM_NMTE_LSTimerEvent();} heartbeat, node guard // if (COMM_NETCTL_EMCY_EN){/*call func*/;} // Emergency } // SDO object time events if (COMM_SDO_EN) { if (COMM_SDO_1_EN){_CO_COMM_SDO1_LSTimerEvent();} if (COMM_SDO_2_EN){_CO_COMM_SDO2_LSTimerEvent();} if (COMM_SDO_3_EN){_CO_COMM_SDO3_LSTimerEvent();} if (COMM_SDO_4_EN){_CO_COMM_SDO4_LSTimerEvent();} }

// NMT boot,

// // // } }

79

5. CO_DEV.c
/***************************************************************************** * * Microchip CANopen Stack (Device Info) * ***************************************************************************** * FileName: CO_DEV.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * Software License Agreement * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * This file contains many of the standard objects defined by CANopen. * * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03*/ #include "CO_TYPES.H"

// CANopen object 0x1000 rom unsigned long rCO_DevType = // CANopen object 0x1008 rom unsigned char rCO_DevName[] = // CANopen object 0x1009 rom unsigned char rCO_DevHardwareVer[] = // CANopen object 0x100A rom unsigned char rCO_DevSoftwareVer[] =

0x111111L;

"Microchip CANopen Device";

"V1.0";

"V1.0";

80

// CANopen object 0x1018 rom unsigned char rCO_DevIdentityIndx = 0x4; rom unsigned long rCO_DevVendorID = rom unsigned long rCO_DevProductCode = rom unsigned long rCO_DevRevNo = rom unsigned long rCO_DevSerialNo = // CANopen object 0x1001 unsigned char uCO_DevErrReg; // CANopen object 0x1002 unsigned long uCO_DevManufacturerStatReg;

0x12345678L; 0x87654321L; 0x12345678L; 0x87654321L;

6. CO_dict.c
/***************************************************************************** * * Microchip CANopen Stack (Dictionary Services) * *****************************************************************************/ #include #include #include #include #include #include #include #include #include "CO_DEFS.DEF" "CO_TYPES.H" "CO_ABERR.H" "CO_DICT.H" "CO_MEMIO.H" "CO_DICT.DEF" "CO_MFTR.DEF" "CO_PDO.DEF" "CO_STD.DEF" // Global definitions // Standard types // Abort types // Dictionary header // Memory IO // Standard type and device specific objects // Manufacturer specific objects // PDO objects // CANopen standard objects

// Params used by the dictionary DICT_PARAM uDict;

rom unsigned char * _pTmpDBase; unsigned char _tDBaseLen; unsigned char MULTIPLEXOR _uDictTemp[4]; _tMplex;

rom unsigned char __dummy[4] = {0,0,0,0};

81

/* Dictionary database built into ROM */ rom DICT_OBJECT_TEMPLATE _db_objects[] = rom DICT_OBJECT_TEMPLATE _db_device[] = rom DICT_OBJECT_TEMPLATE _db_sdo[] = rom DICT_OBJECT_TEMPLATE _db_pdo1_rx_comm[] = rom DICT_OBJECT_TEMPLATE _db_pdo1_rx_map[] = rom DICT_OBJECT_TEMPLATE _db_pdo1_tx_comm[] = rom DICT_OBJECT_TEMPLATE _db_pdo1_tx_map[] = rom DICT_OBJECT_TEMPLATE _db_manufacturer_g1[] = {DICTIONARY_MANUFACTURER_SPECIFIC_1}; rom DICT_OBJECT_TEMPLATE _db_manufacturer_g2[] = {DICTIONARY_MANUFACTURER_SPECIFIC_2}; rom DICT_OBJECT_TEMPLATE _db_manufacturer_g3[] = {DICTIONARY_MANUFACTURER_SPECIFIC_3}; rom DICT_OBJECT_TEMPLATE _db_manufacturer_g4[] = {DICTIONARY_MANUFACTURER_SPECIFIC_4}; rom DICT_OBJECT_TEMPLATE _db_standard_g1[] = rom DICT_OBJECT_TEMPLATE _db_standard_g2[] = rom DICT_OBJECT_TEMPLATE _db_standard_g3[] = rom DICT_OBJECT_TEMPLATE _db_standard_g4[] =

{DICTIONARY_DATA_TYPES}; {DICTIONARY_DEVICE_INFO}; {DICTIONARY_SDO}; {DICTIONARY_PDO1_RX_COMM}; {DICTIONARY_PDO1_RX_MAP}; {DICTIONARY_PDO1_TX_COMM}; {DICTIONARY_PDO1_TX_MAP};

{DICTIONARY_STANDARD_1}; {DICTIONARY_STANDARD_2}; {DICTIONARY_STANDARD_3}; {DICTIONARY_STANDARD_4};

/********************************************************************* * Function: void _CO_DictObjectRead(void) * PreCondition: _CO_DictObjectDecode() must have been called to * fill in the object structure. * Input: none * Output: none * Side Effects: none * Overview: Read the object referenced by uDict.obj. * Note: ********************************************************************/ void _CO_DictObjectRead(void) { // If the object is valid, control code must be something other than 0 if (uDict.obj->ctl) { // Process any functionally defined objects if (uDict.obj->ctl & FDEF_BIT) { uDict.ret = E_SUCCESS; uDict.cmd = DICT_OBJ_READ; uDict.obj->p.pFunc(); return; }

82

else // Decode the type of object switch (uDict.obj->ctl & ACCESS_BITS) { case CONST: //Copy ROM to RAM, uDict.obj->reqLen specifies the amount CO_MEMIO_CopyRomToRam(uDict.obj->p.pROM + uDict.obj->reqOffst, uDict.obj>pReqBuf, uDict.obj->reqLen); break; case RO: case RW: //Copy RAM to RAM, uDict.obj->reqLen specifies the amount CO_MEMIO_CopySram(uDict.obj->p.pRAM + uDict.obj->reqOffst, uDict.obj>pReqBuf, uDict.obj->reqLen); break; default: // Error, cannot read object uDict.ret = E_CANNOT_READ; return; } } uDict.ret = E_SUCCESS; return; }

/********************************************************************* * Function: void _CO_DictObjectWrite(void) * * PreCondition: _CO_DictObjectDecode() must have been called to * fill in the object structure. * * Input: none * * Output: none * * Side Effects: none * * Overview: Write the object referenced by uDict.obj. * * Note: ********************************************************************/ void _CO_DictObjectWrite(void) { // If the object is found if (uDict.obj->ctl) {

83

if (uDict.obj->ctl & FDEF_BIT) { uDict.ret = E_SUCCESS; uDict.cmd = DICT_OBJ_WRITE; uDict.obj->p.pFunc(); return; } else // Decode the type of object switch (uDict.obj->ctl & ACCESS_BITS) { case RW: case WO: //Copy RAM to RAM, uDict.obj->reqLen specifies the amount CO_MEMIO_CopySram(uDict.obj->pReqBuf, uDict.obj->p.pRAM, uDict.obj->reqLen); break; default: // Error, write not allowed uDict.ret = E_CANNOT_WRITE; return; } } uDict.ret = E_SUCCESS; return; }

/********************************************************************* * Function: void _CO_DictObjectDecode(void) * * PreCondition: The multiplexor referenced by uDict must have been * initialized. * * Input: none * * Output: none * * Side Effects: none * * Overview: Find the object in the dictionary and return * information related to the object. The user must * pass a pointer to a structure that contains the * multiplexor. The decode process will fill the * rest of the structure with other pertenent * information. * * Note: ********************************************************************/

84

/* Decode the object*/ void _CO_DictObjectDecode(void) { // Copy the multiplexor to a local storage area _tMplex = *(MULTIPLEXOR *)(&(uDict.obj->index)); switch (_tMplex.index.bytes.B1.byte & 0xF0) { case 0x00: // Data types _pTmpDBase = (rom unsigned char *)_db_objects; _tDBaseLen = sizeof(_db_objects)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x20: // Manufacturer specific _pTmpDBase = (rom unsigned char *)_db_manufacturer_g1; _tDBaseLen = sizeof(_db_manufacturer_g1)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x30: _pTmpDBase = (rom unsigned char *)_db_manufacturer_g2; _tDBaseLen = sizeof(_db_manufacturer_g2)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x40: _pTmpDBase = (rom unsigned char *)_db_manufacturer_g3; _tDBaseLen = sizeof(_db_manufacturer_g3)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x50: _pTmpDBase = (rom unsigned char *)_db_manufacturer_g4; _tDBaseLen = sizeof(_db_manufacturer_g4)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x60: // Standard _pTmpDBase = (rom unsigned char *)_db_standard_g1; _tDBaseLen = sizeof(_db_standard_g1)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x70: _pTmpDBase = (rom unsigned char *)_db_standard_g2; _tDBaseLen = sizeof(_db_standard_g2)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x80: _pTmpDBase = (rom unsigned char *)_db_standard_g3; _tDBaseLen = sizeof(_db_standard_g3)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x90: _pTmpDBase = (rom unsigned char *)_db_standard_g4; _tDBaseLen = sizeof(_db_standard_g4)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x10: switch (_tMplex.index.bytes.B1.byte & 0x0F) { case 0x00: // Device specific information _pTmpDBase = (rom unsigned char *)_db_device; _tDBaseLen = sizeof(_db_device)/sizeof(DICT_OBJECT_TEMPLATE); break;

85

case 0x02: // SDO Server/Client _pTmpDBase = (rom unsigned char *)_db_sdo; _tDBaseLen = sizeof(_db_sdo)/sizeof(DICT_OBJECT_TEMPLATE); break; case 0x04: // PDO Receive Comm if (_tMplex.index.bytes.B0.byte == 0x00) { _pTmpDBase = (rom unsigned char *)_db_pdo1_rx_comm; _tDBaseLen = sizeof(_db_pdo1_rx_comm)/sizeof(DICT_OBJECT_TEMPLATE); } else { // Index not found in database uDict.ret = E_OBJ_NOT_FOUND; return; } break;

case 0x06:

// PDO Receive Map

if (_tMplex.index.bytes.B0.byte == 0x00) { _pTmpDBase = (rom unsigned char *)_db_pdo1_rx_map; _tDBaseLen = sizeof(_db_pdo1_rx_map)/sizeof(DICT_OBJECT_TEMPLATE); } else { // Index not found in database uDict.ret = E_OBJ_NOT_FOUND; return; } break;

case 0x08: // PDO Transmit Comm if (_tMplex.index.bytes.B0.byte == 0x00) { _pTmpDBase = (rom unsigned char *)_db_pdo1_tx_comm; _tDBaseLen = sizeof(_db_pdo1_tx_comm)/sizeof(DICT_OBJECT_TEMPLATE); }

86

else { // Index not found in database uDict.ret = E_OBJ_NOT_FOUND; return; } break;

case 0x0A:

// PDO Transmit Map

if (_tMplex.index.bytes.B0.byte == 0x00) { _pTmpDBase = (rom unsigned char *)_db_pdo1_tx_map; _tDBaseLen = sizeof(_db_pdo1_tx_map)/sizeof(DICT_OBJECT_TEMPLATE); } else { // Index not found in database uDict.ret = E_OBJ_NOT_FOUND; return; } break;

default: // Index not found in database uDict.ret = E_OBJ_NOT_FOUND; return; } break; default: // Index not found in database uDict.ret = E_OBJ_NOT_FOUND; return; }

// Adjust the status uDict.ret = E_OBJ_NOT_FOUND; // Copy the index and sub-index to local memory *(_DATA4 *)(&(_uDictTemp[0])) = *(rom _DATA4 *)_pTmpDBase;

87

// Scan the database and load the pointer while(_tDBaseLen) { // Match the index if ((_uDictTemp[1] == _tMplex.index.bytes.B1.byte) && (_uDictTemp[0] == _tMplex.index.bytes.B0.byte)) { // Adjust the status uDict.ret = E_SUBINDEX_NOT_FOUND; // If the sub index matches then return success code if ((_uDictTemp[2] == _tMplex.sindex.byte) || (_uDictTemp[3] & FSUB_BIT)) { // Copy control information *((DICT_OBJECT_TEMPLATE *)(&(uDict.obj->index))) = *((rom DICT_OBJECT_TEMPLATE *)(_pTmpDBase)); // If functionally defined sub-index, copy sub-index from request if (_uDictTemp[3] & FSUB_BIT) uDict.obj->subindex = _tMplex.sindex.byte; // If function specific then call the app function for // read/write, mapping, and length info if (_uDictTemp[3] & FDEF_BIT) //if (uDict.obj->ctl & FDEF_BIT) { uDict.ret = E_SUCCESS; uDict.cmd = DICT_OBJ_INFO; uDict.obj->p.pFunc(); return; } else { uDict.ret = E_SUCCESS; return; } } } // Adjust the pointer _pTmpDBase += sizeof(DICT_OBJECT_TEMPLATE); _tDBaseLen--; // Copy the index and sub-index to local memory *(_DATA4 *)(&(_uDictTemp[0])) = *(rom _DATA4 *)_pTmpDBase; } return; }

88

7.CO_MAIN.C
/***************************************************************************** * Microchip CANopen Stack (Main Managing Routines) ***************************************************************************** * FileName: CO_MAIN.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * Software License Agreement * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... *****************************************************************************/ #include #include #include #include "CO_TYPES.H" "CO_CANDRV.H" "CO_COMM.H" "CO_NMTE.H" // Data types // Driver services // Object // Error protocols: heartbeat, node-guard

89

/********************************************************************* * Function: void CO_ProcessAllEvents(void) * * PreCondition: All driver and CANopen initialization must be * complete before calling this function. * * Input: none * * Output: none * * Side Effects: none * * Overview: This function is the main entry into CANopen * background processing. In addition the driver * background functions are controlled from here. * * Note: This function should be called as often as * necessary to capture CAN events. ********************************************************************/ void CO_ProcessAllEvents(void) { // Process driver events _CANEventManager(); // Process receive events _CO_COMMRXEventManager(); // Process transmit events _CO_COMMTXRdyEventManager(); // Process transmit events _CO_COMMTXFinEventManager(); }

90

8. CO_MEMIO.C
/***************************************************************************** * * Microchip CANopen Stack (Memory APIs) * *****************************************************************************/

#include "CO_DEFS.DEF" #include "CO_MEMIO.H"

// Global definitions

// Private structures used to set block copy sizes typedef struct _DATA_BLOCK_16 { unsigned char bytes[16]; }_DATA16; typedef struct _DATA_BLOCK_8 { unsigned char bytes[8]; }_DATA8; typedef struct _DATA_BLOCK_4 { unsigned char bytes[4]; }_DATA4; /********************************************************************* * Function: void CO_MEMIO_CopySram(unsigned char *pIn, * *pOut, * * * PreCondition: none * * Input: unsigned char *pIn - pointer to in buffer * unsigned char *pOut - pointer to out buffer * unsigned int len - number of bytes to copy * * Output: none * * Side Effects: none * * Overview: Copy memory SRAM to SRAM. * * Note: ********************************************************************/

unsigned char unsigned int len)

91

void CO_MEMIO_CopySram(unsigned char *pIn, unsigned char *pOut, unsigned int len) { while (len) { if (len < 4) { *pOut = *pIn; pOut++; pIn++; len--; } else if (len < 8) { *((_DATA4 *)pOut) = *((_DATA4 *)(pIn)); pOut += 4; pIn += 4; len -= 4; } else if (len < 16) { *((_DATA8 *)pOut) = *((_DATA8 *)(pIn)); pOut += 8; pIn += 8; len -= 8; } else { *((_DATA16 *)pOut) = *((_DATA16 *)(pIn)); pOut += 16; pIn += 16; len -= 16; } } }

92

/********************************************************************* * Function: void CO_MEMIO_CopyRomToRam(rom unsigned char *pIn, * unsigned char *pOut, * unsigned int len) * * PreCondition: none * * Input: unsigned char *pIn - pointer to rom in buffer * unsigned char *pOut - pointer to sram out buffer * unsigned int len - number of bytes to copy * Output: none * Side Effects: none * Overview: Copy memory ROM to SRAM. * Note: ********************************************************************/ void CO_MEMIO_CopyRomToRam(rom unsigned char *pIn, unsigned char *pOut, unsigned int len) { #if (CO_SPEED_UP_CODE) *pOut; *pIn; while (len) { if (len < 4) { _asm TBLRDPOSTINC movff TABLAT,POSTINC0 _endasm len--; } else if (len < 8) { _asm TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 _endasm len-=4; }

//1

//1 //2 //3 //4

93

else { _asm TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 TBLRDPOSTINC movff TABLAT,POSTINC0 _endasm len-=8; } }

//1 //2 //3 //4 //5 //6 //7 //8

#else while (len) { if (len < 4) { *pOut = *pIn; pOut++; pIn++; len--; } else if (len < 8) { *((_DATA4 *)(pOut)) = *((rom _DATA4 *)pIn); pOut += 4; pIn += 4; len -= 4; }

94

else { *((_DATA8 *)(pOut)) = *((rom _DATA8 *)pIn); pOut += 8; pIn += 8; len -= 8; } } #endif }

9.CO_NMT.C
/***************************************************************************** * Microchip CANopen Stack (Network Management and Communications) ***************************************************************************** * FileName: CO_NMT.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * Software License Agreement * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * * This is the network management object. * * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... * *****************************************************************************/

95

// Global definitions #include #include #include #include #include "CO_TYPES.H" "CO_CANDRV.H" "CO_COMM.H" "p18f2585.h" "CO_TOOLS.H" // Data types // Driver services // Object // COB ID tools

// Event functions for reset requests void CO_NMTStateChangeEvent(void); void CO_NMTResetEvent(void); void CO_NMTAppResetRequest(void); // Handle for NMT unsigned char _hNMT; UNSIGNED32

_NMT_COBID;

/********************************************************************* * Function: void _CO_COMM_NMT_Open(void) * * PreCondition: The ECAN driver must be initialized. * * Input: none * * Output: none * * Side Effects: none * * Overview: This function opens an in endpoint for network * management. * * Note: ********************************************************************/ void _CO_COMM_NMT_Open(void) { // Open a receive message endpoint in the driver _NMT_COBID.word = 0x01L; mTOOLS_CO2MCHP(_NMT_COBID.word); _NMT_COBID.word = mTOOLS_GetCOBID(); mCANOpenMessage((COMM_MSGGRP_NETCTL) | COMM_NETCTL_NMT, _NMT_COBID.word , _hNMT); // Enable NMT if (_hNMT) COMM_NETCTL_NMT_EN = 1; }

96

/********************************************************************* * Function: void _CO_COMM_NMT_Close(void) * * PreCondition: The ECAN driver must be initialized. * * Input: none * * Output: none * * Side Effects: none * * Overview: This function closes the in endpoint. * * Note: ********************************************************************/ void _CO_COMM_NMT_Close(void) { // Call the driver, request to close the receive endpoint mCANCloseMessage(_hNMT); COMM_NETCTL_NMT_EN = 0; }

/********************************************************************* * Function: void _CO_COMM_NMT_RXEvent(void) * * PreCondition: The ECAN driver must be initialized. * * Input: none * * Output: none * * Side Effects: none * * Overview: This function processes receive events for this * endpoint, in particular network management. * * Note: ********************************************************************/

97

void _CO_COMM_NMT_RXEvent(void) { // If the length of the data is 2 then continue if (mCANGetDataLen() == 2) { // Check the received Node ID or broadcast if ((mCANGetDataByte1() == _uCO_nodeID.byte) || (!mCANGetDataByte1())) { // OPP, STOP, PRE // x x 0 Not started, will never enter this function // 0 0 1 Pre-operational // 0 1 1 Stopped from pre-operational // 1 0 1 Operational // 1 1 1 Stopped from operational // Decode the network request and execute switch(mCANGetDataByte0()) { case 1: // Start Node COMM_STATE_OPER = 1; COMM_STATE_STOP = 0; CO_NMTStateChangeEvent(); // Notify the app break; case 2: // Stop Node COMM_STATE_STOP = 1; CO_NMTStateChangeEvent(); // Notify the app break; case 128: // Pre-operational COMM_STATE_OPER = 0; COMM_STATE_STOP = 0; CO_NMTStateChangeEvent(); // Notify the app break; case 129: // Reset node CO_NMTAppResetRequest(); case 130: // // Reset communications CO_NMTResetEvent();

//

//

//

// //

// Notify the app

// Notify the app

// Reset Communications _CO_COMMResetEventManager(); break; }// Unknown requests, ignore } } }

98

10. CO_NMTE.c

/***************************************************************************** * * Microchip CANopen Stack (Network Management Error Communications Handler) * ***************************************************************************** * FileName: CO_NMTE.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * * Software License Agreement * * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * * * * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... * *****************************************************************************/

99

// Heartbeat or node-guard #include #include #include #include #include #include #include #include "CO_DEFS.DEF" "CO_TYPES.H" "CO_CANDRV.H" "CO_COMM.H" "CO_DICT.H" "CO_NMTE.H" "CO_TOOLS.H" "p18f2585.h" // Global definitions // Data types // Driver services // Object // Dictionary Object Services // Network Management Error services // COB ID tools

UNSIGNED32 short long UNSIGNED8 UNSIGNED8 UNSIGNED16 UNSIGNED16 UNSIGNED8

_uNMTE_COBID; _uNMTETimer; _uNMTEState; _uNMTELocalState; _uNMTEHeartBeat; _uNMTEGuardTime; _uNMTELifeFactor;

unsigned char

_hNMTE;

void CO_NMTENodeGuardErrEvent(void);

/********************************************************************* * Function: void _CO_COMM_NMTE_HeartBeatAccessEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: Process access events to the heartbeat. * * Note: ********************************************************************/ void _CO_COMM_NMTE_HeartBeatAccessEvent(void) { switch (uDict.cmd) { //case DICT_OBJ_INFO: // Get information about the object // break;

100

case DICT_OBJ_READ: // Read the object *(UNSIGNED16 *)(uDict.obj->pReqBuf) = _uNMTEHeartBeat; break; case DICT_OBJ_WRITE: // Write the object _uNMTEHeartBeat = *(UNSIGNED16 *)(uDict.obj->pReqBuf); // Reset the state _uNMTEState.byte = 0; // If the heartbeat is greater than 0 then enable heartbeat if (_uNMTEHeartBeat.word) { NMTE_TMR_LOCAL_EN = 1; _uNMTETimer = _uNMTEHeartBeat.word; } else // else if the node guard and life is greater than 0 then enable node guard if (_uNMTEGuardTime.word && _uNMTELifeFactor.byte) { _uNMTELocalState.byte = 0x80; NMTE_NODE_GUARD_EN = 1; NMTE_TMR_LOCAL_EN = 1; _uNMTETimer = _uNMTEGuardTime.word * _uNMTELifeFactor.byte; } break; } } /********************************************************************* * Function: void _CO_COMM_NMTE_GuardTimeAccessEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: Process access events to the guard time. * * Note: ********************************************************************/ void _CO_COMM_NMTE_GuardTimeAccessEvent(void) { switch (uDict.cmd) { //case DICT_OBJ_INFO: // Get information about the object // break;

101

case DICT_OBJ_READ: // Read the object *(UNSIGNED16 *)(uDict.obj->pReqBuf) = _uNMTEGuardTime; break; case DICT_OBJ_WRITE: // Write the object _uNMTEGuardTime = *(UNSIGNED16 *)(uDict.obj->pReqBuf); // Reset the state _uNMTEState.byte = 0; // If the heartbeat is greater than 0 then enable heartbeat if (_uNMTEHeartBeat.word) { NMTE_TMR_LOCAL_EN = 1; _uNMTETimer = _uNMTEHeartBeat.word; } else // else if the node guard and life is greater than 0 then enable node guard if (_uNMTEGuardTime.word && _uNMTELifeFactor.byte) { _uNMTELocalState.byte = 0x80; NMTE_NODE_GUARD_EN = 1; NMTE_TMR_LOCAL_EN = 1; _uNMTETimer = _uNMTEGuardTime.word * _uNMTELifeFactor.byte; } break; } }

/********************************************************************* * Function: void _CO_COMM_NMTE_GuardTimeAccessEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: Process access events to the life time factor. * * Note: ********************************************************************/ void _CO_COMM_NMTE_LifeFactorAccessEvent(void) { switch (uDict.cmd) { //case DICT_OBJ_INFO: // Get information about the object // break;

102

case DICT_OBJ_READ: // Read the object *(UNSIGNED8 *)(uDict.obj->pReqBuf) = _uNMTELifeFactor; break; case DICT_OBJ_WRITE: // Write the object _uNMTELifeFactor = *(UNSIGNED8 *)(uDict.obj->pReqBuf); // Reset the state _uNMTEState.byte = 0; // If the heartbeat is greater than 0 then enable heartbeat if (_uNMTEHeartBeat.word) { NMTE_TMR_LOCAL_EN = 1; _uNMTETimer = _uNMTEHeartBeat.word; } else // else if the node guard and life is greater than 0 then enable node guard if (_uNMTEGuardTime.word && _uNMTELifeFactor.byte) { _uNMTELocalState.byte = 0x80; NMTE_NODE_GUARD_EN = 1; NMTE_TMR_LOCAL_EN = 1; _uNMTETimer = _uNMTEGuardTime.word * _uNMTELifeFactor.byte; } break; } }

/********************************************************************* * Function: void _CO_COMM_NMTE_Open(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: Open the NMTE endpoint. * * Note: ********************************************************************/ void _CO_COMM_NMTE_Open(void) { // Set the COB ID and convert it to MCHP _uNMTE_COBID.word = 0x700L + _uCO_nodeID.byte; mTOOLS_CO2MCHP(_uNMTE_COBID.word); _uNMTE_COBID.word = mTOOLS_GetCOBID();

103

_uNMTEState.byte = 0; // If the heartbeat is greater than 0 then enable heartbeat if (_uNMTEHeartBeat.word) { NMTE_TMR_LOCAL_EN = 1; COMM_NETCTL_NMTE_EN = 1; _uNMTETimer = _uNMTEHeartBeat.word; } else // else if the node guard and life is greater than 0 then enable node guard if (_uNMTEGuardTime.word && _uNMTELifeFactor.byte) { // Call the driver and request to open a receive endpoint mCANOpenMessage((COMM_MSGGRP_NETCTL) | COMM_NETCTL_NMTE, _uNMTE_COBID.word, _hNMTE); if (_hNMTE) { COMM_NETCTL_NMTE_EN = 1; // Reset the toggle memory _uNMTELocalState.byte = 0x80; NMTE_NODE_GUARD_EN = 1; NMTE_TMR_LOCAL_EN = 1; _uNMTETimer = _uNMTEGuardTime.word * _uNMTELifeFactor.byte; } } }

/********************************************************************* * Function: void _CO_COMM_NMTE_Close(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: Close the NMTE endpoint. * * Note: ********************************************************************/

104

void _CO_COMM_NMTE_Close(void) { // Call the driver, request to close the receive endpoint mCANCloseMessage(_hNMTE); COMM_NETCTL_NMTE_EN = 0; }

/********************************************************************* * Function: void _CO_COMM_NMTE_RXEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is the receive event handler for the NMTE * endpoint. * * Note: This is only used for nodeguard. ********************************************************************/ void _CO_COMM_NMTE_RXEvent(void) { // If node guard is used and an RTR with 1 byte is received if (NMTE_NODE_GUARD_EN) { if (mCANIsGetRTR()) { if (mCANGetDataLen() == 1) { // Queue a request to send data COMM_NETCTL_NMTE_TF = 1; // Reset the timer _uNMTETimer = _uNMTEGuardTime.word * _uNMTELifeFactor.byte; } } } }

105

/********************************************************************* * Function: void _CO_COMM_NMTE_TXEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is the transmit event handler for the NMTE * endpoint. Node guarding and heartbeat * transmissions are handled. * * Note: ********************************************************************/ void _CO_COMM_NMTE_TXEvent(void) { { // Set the COB *(unsigned long *)(mCANGetPtrTxCOB()) = _uNMTE_COBID.word; // Set the length mCANPutDataLen(1);

// Send the state or the boot if (!NMTE_BOOT_SERVICE) { // Toggle and strip old state (also known as bootup state) _uNMTELocalState.byte = _uNMTELocalState.byte & 0x80; if (NMTE_NODE_GUARD_EN) {_uNMTELocalState.bits.b7 = (~_uNMTELocalState.bits.b7);} else {_uNMTELocalState.bits.b7 = 0;} // Set the data if (COMM_STATE_STOP) _uNMTELocalState.byte = _uNMTELocalState.byte | 4; else if (COMM_STATE_OPER) _uNMTELocalState.byte = _uNMTELocalState.byte | 5; else if (COMM_STATE_PREOP) _uNMTELocalState.byte = _uNMTELocalState.byte | 127; // Load the data mCANPutDataByte0(_uNMTELocalState.byte); } else { NMTE_BOOT_SERVICE = 0; mCANPutDataByte0(0); } } }

106

/********************************************************************* * Function: void _CO_COMM_NMTE_LSTimerEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is the timer event handler for the NMTE * endpoint. * * Note: ********************************************************************/ void _CO_COMM_NMTE_LSTimerEvent(void) { // Process only if the local timer is enabled if (NMTE_TMR_LOCAL_EN) { // Adjust the time _uNMTETimer -= CO_TICK_PERIOD; // If the timer is zero then //if (_uNMTETimer == 0) if (_uNMTETimer <= 0) { // If the heartbeat protocol is enabled if (!NMTE_NODE_GUARD_EN) { // Reset the timer _uNMTETimer = _uNMTETimer + _uNMTEHeartBeat.word; // Queue the endpoint to send a heartbeat COMM_NETCTL_NMTE_TF = 1; } // Else the node guard protocol is enabled else { // Reset the timer _uNMTETimer = _uNMTEGuardTime.word * _uNMTELifeFactor.byte; // Notify the application of an error CO_NMTENodeGuardErrEvent(); } } } }

//

107

11. CO_PDO.c
/***************************************************************************** * * Microchip CANopen Stack (Process Data Objects) * ***************************************************************************** * FileName: CO_PDO.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * * Software License Agreement * * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * * * * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... * *****************************************************************************/ #include #include #include #include #include #include "CO_DEFS.DEF" "CO_TYPES.H" "CO_CANDRV.H" "CO_COMM.H" "CO_PDO.H" "p18f2585.h" // Global definitions // Data types // Driver services // Object

108

#if CO_NUM_OF_PDO < 1 #error "Number of PDOs too low, must have at least 1..." #endif #if CO_NUM_OF_PDO > 4 #error "Number of PDOs too high, this version only supports up to 4 PDOs..." #endif

UNSIGNED32 UNSIGNED32 _PDOBUF unsigned char

uRPDOComm1; uTPDOComm1; _uPDO1; _uPDOHandles1;

// RPDO communication setting // TPDO communication setting

#if CO_NUM_OF_PDO > 1 UNSIGNED32 uRPDOComm2; UNSIGNED32 uTPDOComm2; _PDOBUF _uPDO2; unsigned char _uPDOHandles2; #endif #if CO_NUM_OF_PDO > 2 UNSIGNED32 uRPDOComm3; UNSIGNED32 uTPDOComm3; _PDOBUF _uPDO3; unsigned char _uPDOHandles3; #endif #if CO_NUM_OF_PDO > 3 UNSIGNED32 uRPDOComm4; UNSIGNED32 uTPDOComm4; _PDOBUF _uPDO4; unsigned char _uPDOHandles4; #endif

// RPDO communication setting // TPDO communication setting

// RPDO communication setting // TPDO communication setting

// RPDO communication setting // TPDO communication setting

void _CO_COMM_PDO1_Open(void) { // Call the driver and request to open a receive endpoint mCANOpenMessage((COMM_MSGGRP_PDO) | COMM_PDO_1, uRPDOComm1.word, _uPDOHandles1); if (_uPDOHandles1) COMM_RPDO_1_EN = 1; COMM_TPDO_1_EN = 1; } void _CO_COMM_PDO1_Close(void) { // Call the driver, request to close the receive endpoint mCANCloseMessage(_uPDOHandles1); COMM_RPDO_1_EN = 0; COMM_TPDO_1_EN = 0; }

109

void _CO_COMM_PDO1_RXEvent(void) { *((_DATA8 *)(_uPDO1.RPDO.buf)) = *((_DATA8 *)(mCANGetPtrRxData())); _uPDO1.RPDO.len = mCANGetDataLen(); } void _CO_COMM_PDO1_TXEvent(void) { // Set the COB *(unsigned long *)(mCANGetPtrTxCOB()) = uTPDOComm1.word; // Call the driver, load data to transmit *((_DATA8 *)(mCANGetPtrTxData())) = *((_DATA8 *)(_uPDO1.TPDO.buf)); mCANPutDataLen(_uPDO1.TPDO.len); }

#if CO_NUM_OF_PDO > 1 void _CO_COMM_PDO2_Open(void) { // Call the driver and request to open a receive endpoint mCANOpenMessage((COMM_MSGGRP_PDO) | COMM_PDO_2, uRPDOComm2.word, _uPDOHandles2); if (_uPDOHandles2) COMM_RPDO_2_EN = 1; } void _CO_COMM_PDO2_Close(void) { // Call the driver, request to close the receive endpoint mCANCloseMessage(_uPDOHandles2); COMM_RPDO_2_EN = 0; } void _CO_COMM_PDO2_RXEvent(void) { *((_DATA8 *)(_uPDO2.RPDO.buf)) = *((_DATA8 *)(mCANGetPtrRxData())); _uPDO2.RPDO.len = mCANGetDataLen(); } void _CO_COMM_PDO2_TXEvent(void) { // Set the COB *(unsigned long *)(mCANGetPtrTxCOB()) = uTPDOComm2.word; // Call the driver, load data to transmit *((_DATA8 *)(mCANGetPtrTxData())) = *((_DATA8 *)(_uPDO2.TPDO.buf)); mCANPutDataLen(_uPDO2.TPDO.len); } #endif

110

#if CO_NUM_OF_PDO > 2 void _CO_COMM_PDO3_Open(void) { // Call the driver and request to open a receive endpoint mCANOpenMessage((COMM_MSGGRP_PDO) | COMM_PDO_3, uRPDOComm3.word, _uPDOHandles3); if (_uPDOHandles3) COMM_RPDO_3_EN = 1; } void _CO_COMM_PDO3_Close(void) { // Call the driver, request to close the receive endpoint mCANCloseMessage(_uPDOHandles3); COMM_RPDO_3_EN = 0; } void _CO_COMM_PDO3_RXEvent(void) { *((_DATA8 *)(_uPDO3.RPDO.buf)) = *((_DATA8 *)(mCANGetPtrRxData())); _uPDO3.RPDO.len = mCANGetDataLen(); } void _CO_COMM_PDO3_TXEvent(void) { // Set the COB *(unsigned long *)(mCANGetPtrTxCOB()) = uTPDOComm3.word; // Call the driver, load data to transmit *((_DATA8 *)(mCANGetPtrTxData())) = *((_DATA8 *)(_uPDO3.TPDO.buf)); mCANPutDataLen(_uPDO3.TPDO.len); } #endif

#if CO_NUM_OF_PDO > 3 void _CO_COMM_PDO4_Open(void) { // Call the driver and request to open a receive endpoint mCANOpenMessage((COMM_MSGGRP_PDO) | COMM_PDO_4, uRPDOComm4.word, _uPDOHandles4); if (_uPDOHandles4) COMM_RPDO_4_EN = 1; } void _CO_COMM_PDO4_Close(void) { // Call the driver, request to close the receive endpoint mCANCloseMessage(_uPDOHandles4); COMM_RPDO_4_EN = 0; }

111

void _CO_COMM_PDO4_RXEvent(void) { *((_DATA8 *)(_uPDO4.RPDO.buf)) = *((_DATA8 *)(mCANGetPtrRxData())); _uPDO4.RPDO.len = mCANGetDataLen(); } void _CO_COMM_PDO4_TXEvent(void) { // Set the COB *(unsigned long *)(mCANGetPtrTxCOB()) = uTPDOComm4.word; // Call the driver, load data to transmit *((_DATA8 *)(mCANGetPtrTxData())) = *((_DATA8 *)(_uPDO4.TPDO.buf)); mCANPutDataLen(_uPDO4.TPDO.len); } #endif

12. CO_SDO1.c
/***************************************************************************** * * Microchip CANopen Stack (The Default SDO) * ***************************************************************************** * FileName: CO_SDO1.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * Software License Agreement * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... * *****************************************************************************/

112

#include #include #include #include #include #include #include #include

"CO_DEFS.DEF" "CO_TYPES.H" "CO_ABERR.H" "CO_CANDRV.H" "CO_COMM.H" "CO_DICT.H" "CO_TOOLS.H" "p18f2585.h"

// Global definitions // Data types // Abort types // Driver services // Object // Dictionary Object Services // COB ID tools

union _SDO_CTL { unsigned char byte; struct _SDO_INITIATE_CTL { unsigned s:1; unsigned e:1; unsigned n:2; unsigned x:1; unsigned cmd:3; }ictl; struct _SDO_REGULAR_CTL { unsigned c:1; unsigned n:3; unsigned t:1; unsigned cmd:3; }rctl; struct _SDO_RESPONSE { unsigned x:4; unsigned t:1; unsigned cmd:3; }rsp; }; union _SDO_STATE { unsigned char byte; struct _SDO_STATE_BITS { unsigned :3; unsigned ntime:1; unsigned tog:1; unsigned start:1; unsigned dnld:1; unsigned abrt:1; }bits; };

113

rom unsigned char UNSIGNED32 UNSIGNED32 unsigned char union _SDO_STATE REQ_STAT union _SDO_CTL DICT_OBJ inits unsigned int UNSIGNED16

_uSDO1COMMIndx = 3; // The length of the object _uSDO1_CS_COBID; _uSDO1_SC_COBID; _hSDO1; // COB IDs used by the default SDO

// Handle to the connection

_uSDO1State; // State bitmap for this SDO _uSDO1ACode; // Abort code _uSDO1Ctl; // Received control byte buffer _uSDO1Dict; // Local dictionary object, loaded during _uSDO1Timer; // Watchdog, defined by the application _uSDO1BytesLeft; // Bytes to send

/* Buffers used in this design */ unsigned char _uSDO1RxBuf[CO_SDO1_MAX_RX_BUF]; // Receive space for downloads unsigned char _uSDO1TxBuf[8]; // Transmit space for uploads

/********************************************************************* * Function: void _CO_COMM_SDO1_CS_COBIDAccessEvent(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: Process any access events to the SDO client to * server COB ID. * * Note: ********************************************************************/ // Process access events to the COB ID void _CO_COMM_SDO1_CS_COBIDAccessEvent(void) { switch (mCO_DictGetCmd()) { case DICT_OBJ_READ: // Read the object // Translate MCHP COB to CANopen COB mTOOLS_MCHP2CO(_uSDO1_CS_COBID.word); // Return the COBID *(unsigned long *)(uDict.obj->pReqBuf) = mTOOLS_GetCOBID(); break; } }

114

/********************************************************************* * Function: void _CO_COMM_SDO1_SC_COBIDAccessEvent(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: Process any access events to the SDO server to * client COB ID. * * Note: ********************************************************************/ // Process access events to the COB ID void _CO_COMM_SDO1_SC_COBIDAccessEvent(void) { switch (mCO_DictGetCmd()) { case DICT_OBJ_READ: // Read the object // Translate MCHP COB to CANopen COB mTOOLS_MCHP2CO(_uSDO1_SC_COBID.word); // Return the COBID *(unsigned long *)(uDict.obj->pReqBuf) = mTOOLS_GetCOBID(); break; } }

/********************************************************************* * Function: void _CO_COMM_SDO1_Open(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This function opens the default SDO * communications. * * Note: ********************************************************************/

115

void _CO_COMM_SDO1_Open(void) { // Set the client to server COB ID and convert it to MCHP _uSDO1_CS_COBID.word = 0x600L + _uCO_nodeID.byte; mTOOLS_CO2MCHP(_uSDO1_CS_COBID.word); _uSDO1_CS_COBID.word = mTOOLS_GetCOBID(); // Set the server to client COB ID and convert it to MCHP _uSDO1_SC_COBID.word = 0x580L + _uCO_nodeID.byte; mTOOLS_CO2MCHP(_uSDO1_SC_COBID.word); _uSDO1_SC_COBID.word = mTOOLS_GetCOBID(); // Open a receive message endpoint in the driver mCANOpenMessage(COMM_MSGGRP_SDO | COMM_SDO_1, _uSDO1_CS_COBID.word, _hSDO1); if (_hSDO1) COMM_SDO_1_EN = 1; // Reset internal variables _uSDO1State.byte = 0; }

/********************************************************************* * Function: void _CO_COMM_SDO1_Close(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This function closes the default SDO * communications. * * Note: ********************************************************************/ void _CO_COMM_SDO1_Close(void) { // Call the driver, request to close the receive endpoint mCANCloseMessage(_hSDO1); COMM_SDO_1_EN = 0; }

116

/********************************************************************* * Function: void _CO_COMM_SDO1_LSTimerEvent(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This is the low-speed timer event handler for * the SDO1 endpoint. * Note: ********************************************************************/ void _CO_COMM_SDO1_LSTimerEvent(void) { // Process only if the connection is in the middle of active segmented comm if (_uSDO1State.bits.start) { // Adjust the time TODO _uSDO1Timer -= CO_TICK_PERIOD; // Reset SDO1 states if a timeout while receiving if ((signed int)_uSDO1Timer <= 0) { // Reset the states _uSDO1State.byte = 0; // Queue an abort, SDO timeout _uSDO1ACode = E_SDO_TIME; COMM_SDO_1_TF = 1; } } } /********************************************************************* * Function: void _CO_COMM_SDO1_TXEvent(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This is the SDO1 transmit event handler. * * Note: ********************************************************************/

117

void _CO_COMM_SDO1_TXEvent(void) { // Set the CID *(unsigned long *)(mCANGetPtrTxCOB()) = _uSDO1_SC_COBID.word; // Set the length mCANPutDataLen(8); if (_uSDO1ACode == E_SUCCESS) { // Move the data to the transmit buffer *(_DATA8 *)(mCANGetPtrTxData()) = *(_DATA8 *)_uSDO1TxBuf; } else { // Set the abort code *(mCANGetPtrTxData()) = 0x80; // Set the multiplexor *(mCANGetPtrTxData() + 1) = ((UNSIGNED16 *)(&(_uSDO1Dict.index)))->bytes.B0.byte; *(mCANGetPtrTxData() + 2) = ((UNSIGNED16 *)(&(_uSDO1Dict.index)))->bytes.B1.byte; *(mCANGetPtrTxData() + 3) = _uSDO1Dict.subindex; switch (_uSDO1ACode) { case E_TOGGLE: // Toggle not alternated *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x05030000L; break; case E_SDO_TIME: // SDO protocol timed out *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x05040000L; break; case E_CS_CMD: // Client/server command specifier not valid or unknown *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x05040001L; break; case E_MEMORY_OUT: // Out of memory *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x05040005L; break; case E_UNSUPP_ACCESS: // Unsupported access to an object *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06010000L; break; case E_CANNOT_READ: // Attempt to read a write only object *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06010001L; break; case E_CANNOT_WRITE: // Attempt to write a read only object *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06010002L; break;

118

case E_OBJ_NOT_FOUND: // Object does not exist in the object dictionary *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06020000L; break; case E_OBJ_CANNOT_MAP: // Object cannot be mapped to the PDO *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06040041L; break; case E_OBJ_MAP_LEN: // The number and length of the objects to be mapped would //exceed PDO length *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06040042L; break; case E_GEN_PARAM_COMP: // General parameter incompatibility reason *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06040043L; break; case E_GEN_INTERNAL_COMP: // General internal incompatibility in the device *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06040047L; break; case E_HARDWARE: // Access failed due to a hardware error *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06060000L; break; case E_LEN_SERVICE: // Data type does not match, length of service parameter does not //match *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06070010L; break; case E_LEN_SERVICE_HIGH: //too high *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06070012L; break; case E_LEN_SERVICE_LOW: //too low *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06070013L; break; case E_SUBINDEX_NOT_FOUND: // Sub-index does not exist *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06090011L; break; case E_PARAM_RANGE: // Value range of parameter exceeded *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06090030L; break; case E_PARAM_HIGH: // Value of parameter written too high *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06090031L; break; // Data type does not match, length of service parameter // Data type does not match, length of service parameter

119

case E_PARAM_LOW: // Value of parameter written too low *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06090032L; break; case E_MAX_LT_MIN: // Maximum value is less than minimum value *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x06090036L; break; case E_GENERAL: // genral error *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x08000000L; break; case E_TRANSFER: // Data cannot be transfered or stored to the application *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x08000020L; break; case E_LOCAL_CONTROL: // Data cannot be transfered or stored to the application because //of local control *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x08000021L; break; case E_DEV_STATE: // Data cannot be transfered or //stored to the application because of the device present state *(unsigned long *)(mCANGetPtrTxData() + 4) = 0x08000022L; break; } } }

/********************************************************************* * Function: void _CO_COMM_SDO1_RXEvent(void) * * PreCondition: * * Input: none * * Output: none * * Side Effects: none * * Overview: This is the SDO1 receive event handler. * * Note: ********************************************************************/

120

void _CO_COMM_SDO1_RXEvent(void) { // Process only if all 8 bytes of data are received if (mCANGetDataLen() == 8) { // Init the abort code to success _uSDO1ACode = E_SUCCESS; // Get the first byte of the received message _uSDO1Ctl.byte = mCANGetDataByte0(); switch(_uSDO1Ctl.byte & 0xE0) { case 0x00: // Download // Continue only if initiated and in download state if (_uSDO1State.bits.start) if (_uSDO1State.bits.dnld) { // Compare the toggle bits. if ((_uSDO1State.byte ^ _uSDO1Ctl.byte) & 0x10) { // Reset states _uSDO1State.byte = 0; // abort, toggle not alternated _uSDO1ACode = E_TOGGLE; COMM_SDO_1_TF = 1; return; } // Copy data from the driver *((_DATA7*)(_uSDO1RxBuf + _uSDO1Dict.reqOffst)) = *((_DATA7*)(mCANGetPtrRxData() + 1)); // Adjust the count or offset to the next segment _uSDO1Dict.reqOffst += (~_uSDO1Ctl.rctl.n) & 0x07; // If the count is greater than the object length then abort if (_uSDO1Dict.reqOffst > _uSDO1Dict.len) { // Reset states _uSDO1State.byte = 0; // Abort _uSDO1ACode = E_LEN_SERVICE; COMM_SDO_1_TF = 1; return; } // Set the next expected toggle _uSDO1State.bits.tog = ~_uSDO1State.bits.tog; // Set the header to respond, b'001t0000

121

_uSDO1TxBuf[0] = (_uSDO1Ctl.byte | 0x20) & 0xF0; // Check for a complete flag if (_uSDO1Ctl.rctl.c) { // Set the pointer to the buffer _uSDO1Dict.pReqBuf = _uSDO1RxBuf; // Write the object mCO_DictObjectWrite(_uSDO1Dict); // Reset states _uSDO1State.byte = 0; // Send code, whatever was returned from the object _uSDO1ACode = mCO_DictGetRet(); COMM_SDO_1_TF = 1; } else { // Queue to send acknowledge COMM_SDO_1_TF = 1; } } break;

case 0x20: // Initiate Download // Kill the current start if any _uSDO1State.bits.start = 0; // Store the multiplexor locally _uSDO1TxBuf[1] = ((UNSIGNED16 *)(&(_uSDO1Dict.index)))->bytes.B0.byte = mCANGetDataByte1(); _uSDO1TxBuf[2] = ((UNSIGNED16 *)(&(_uSDO1Dict.index)))->bytes.B1.byte = mCANGetDataByte2(); _uSDO1TxBuf[3] = _uSDO1Dict.subindex = mCANGetDataByte3(); // Preload potential reserved locations _uSDO1TxBuf[4] = 0; _uSDO1TxBuf[5] = 0; _uSDO1TxBuf[6] = 0; _uSDO1TxBuf[7] = 0; // Decode the object; this gets the data from the dictionary // If the object is functionally defined, then the data is retrieved // from the object's defined function. mCO_DictObjectDecode(_uSDO1Dict);

122

// Was the object in the dictionary if (mCO_DictGetRet() == E_SUCCESS) { // Check the access for this request; must have write capability if (_uSDO1Dict.ctl & WR_BIT) { // Expedited download if (_uSDO1Ctl.ictl.e) { // If the count is specified, set the request length from the header if (_uSDO1Ctl.ictl.s) _uSDO1Dict.reqLen = (((~_uSDO1Ctl.ictl.n) & 0x03) + 1); // Otherwise set the length from the object else _uSDO1Dict.reqLen = _uSDO1Dict.len; if (_uSDO1Dict.reqLen == _uSDO1Dict.len) { // Reset states _uSDO1State.byte = 0;

// Set the pointer to the driver _uSDO1Dict.pReqBuf = mCANGetPtrRxData() + 4; // Call the object dictionary write function mCO_DictObjectWrite(_uSDO1Dict);

// If the write was successful, queue to send acknowledge _uSDO1TxBuf[0] = 0x60; // Send abort, code returned from object _uSDO1ACode = mCO_DictGetRet(); COMM_SDO_1_TF = 1; } else { // abort, data length does not match _uSDO1ACode = E_LEN_SERVICE; COMM_SDO_1_TF = 1; } }

// Segmented download

123

else { // If the count is specified if (_uSDO1Ctl.ictl.s) { // Test the two upper most bytes, should be zero if (mCANGetDataByte6() | mCANGetDataByte7()) { // Send abort, length does not match, 0607 0010 _uSDO1ACode = E_LEN_SERVICE; COMM_SDO_1_TF = 1; return; } // Compare the length against the object's defined length if (*((unsigned int *)(mCANGetPtrRxData() + 4)) != _uSDO1Dict.len) { // abort, data length does not match _uSDO1ACode = E_LEN_SERVICE; COMM_SDO_1_TF = 1; return; } } // Set the requested length _uSDO1Dict.reqLen = _uSDO1Dict.len;

// Indicate a start download _uSDO1State.bits.start = 1; _uSDO1State.bits.dnld = 1; // First toggle should be 0 _uSDO1State.bits.tog = 0; // Reset the data count _uSDO1Dict.reqOffst = 0; // Start the watchdog _uSDO1Timer = CO_SDO1_MAX_SEG_TIME; //_uSDO1State.bits.ntime = 0; // Queue to send acknowledge _uSDO1TxBuf[0] = 0x60; COMM_SDO_1_TF = 1; } }

124

else { // abort, access problem _uSDO1ACode = E_CANNOT_WRITE; COMM_SDO_1_TF = 1; } } // Object not found else { // Abort, return the appropriate code _uSDO1ACode = mCO_DictGetRet(); COMM_SDO_1_TF = 1; } break;

case 0x40: // Initiate Upload // Kill the current start _uSDO1State.bits.start = 0; // Store the multiplexor locally _uSDO1TxBuf[1] = ((UNSIGNED16 *)(&(_uSDO1Dict.index)))->bytes.B0.byte = mCANGetDataByte1(); _uSDO1TxBuf[2] = ((UNSIGNED16 *)(&(_uSDO1Dict.index)))->bytes.B1.byte = mCANGetDataByte2(); _uSDO1TxBuf[3] = _uSDO1Dict.subindex = mCANGetDataByte3(); // Preload potential reserved locations _uSDO1TxBuf[4] = 0; _uSDO1TxBuf[5] = 0; _uSDO1TxBuf[6] = 0; _uSDO1TxBuf[7] = 0; // Decode the object; this gets the data from the dictionary mCO_DictObjectDecode(_uSDO1Dict); // Check the return status from the decode if (mCO_DictGetRet() == E_SUCCESS) { // Check the access for this request; must have read capability if (_uSDO1Dict.ctl & RD_BIT) { // Reset offset _uSDO1Dict.reqOffst = 0; // Reset states _uSDO1State.byte = 0;

125

// If the object len is greater than 4 then segment upload if (_uSDO1Dict.len > 4) { // Set the watchdog _uSDO1Timer = CO_SDO1_MAX_SEG_TIME; //_uSDO1State.bits.ntime = 0; // Indicate a start upload _uSDO1State.bits.start = 1; // Set pointer to internal buffer _uSDO1Dict.pReqBuf = &(_uSDO1TxBuf[4]);

// Set the size of the object _uSDO1TxBuf[4] = ((UNSIGNED16 *)(&(_uSDO1Dict.len)))->bytes.B0.byte; _uSDO1TxBuf[5] = ((UNSIGNED16 *)(&(_uSDO1Dict.len)))->bytes.B1.byte; // Set the response command, size indicated _uSDO1TxBuf[0] = 0x41; // Queue to send acknowledge COMM_SDO_1_TF = 1; } // Expedited upload else { // Set the length in the header switch ((unsigned char)(_uSDO1Dict.len)) { case 1: _uSDO1TxBuf[0] = 0x4F; break; case 2: _uSDO1TxBuf[0] = 0x4B; break; case 3: _uSDO1TxBuf[0] = 0x47; break; case 4: _uSDO1TxBuf[0] = 0x43; break; } // Set the read length _uSDO1Dict.reqLen = _uSDO1Dict.len;

// Set the pointer to the transmit buffer _uSDO1Dict.pReqBuf = &(_uSDO1TxBuf[4]); // Read the data from the object into the buffer mCO_DictObjectRead(_uSDO1Dict);

126

// Pass any codes _uSDO1ACode = mCO_DictGetRet(); COMM_SDO_1_TF = 1; } } else { // abort, access problem _uSDO1ACode = E_CANNOT_READ; COMM_SDO_1_TF = 1; } } // Object not found else { // Abort, return the appropriate code _uSDO1ACode = mCO_DictGetRet(); COMM_SDO_1_TF = 1; } break;

case 0x60: // Upload if (_uSDO1State.bits.start) // Continue only if initiated if (!_uSDO1State.bits.dnld) // and in a upload state { // Compare the toggle bits. if ((_uSDO1State.byte ^ _uSDO1Ctl.byte) & 0x10) { // Reset states _uSDO1State.byte = 0; // abort, toggle not alternated _uSDO1ACode = E_TOGGLE; COMM_SDO_1_TF = 1; return; }

// Set the pointer to the transmit buffer _uSDO1Dict.pReqBuf = &(_uSDO1TxBuf[1]); // Set the offset _uSDO1BytesLeft.word = _uSDO1Dict.len - _uSDO1Dict.reqOffst;

127

// If the data to be sent is less than 8 then set n and c if (_uSDO1BytesLeft.word > 7) { _uSDO1TxBuf[0] = 0x00; _uSDO1Dict.reqLen = 7; } else { // Reset states _uSDO1State.byte = 0; switch (_uSDO1BytesLeft.bytes.B0.byte) { _uSDO1TxBuf[0] = 0x0D; _uSDO1Dict.reqLen = 1; break; _uSDO1TxBuf[0] = 0x0B; _uSDO1Dict.reqLen = 2; break; _uSDO1TxBuf[0] = 0x09; _uSDO1Dict.reqLen = 3; break; _uSDO1TxBuf[0] = 0x07; _uSDO1Dict.reqLen = 4; break; _uSDO1TxBuf[0] = 0x05; _uSDO1Dict.reqLen = 5; break; _uSDO1TxBuf[0] = 0x03; _uSDO1Dict.reqLen = 6; break; _uSDO1TxBuf[0] = 0x01; _uSDO1Dict.reqLen = 7; break; } }

case 1: case 2: case 3: case 4: case 5: case 6: case 7:

// Setup the toggle if (~_uSDO1Ctl.rctl.t){((union _SDO_CTL *)(_uSDO1TxBuf))->rctl.t = 0;} else {((union _SDO_CTL *)(_uSDO1TxBuf))->rctl.t = 1;} // Read the data from the object into the transmit buffer mCO_DictObjectRead(_uSDO1Dict); // Adjust the offset _uSDO1Dict.reqOffst += _uSDO1Dict.reqLen; // Set the next expected toggle _uSDO1State.bits.tog = ~_uSDO1State.bits.tog; // Queue to send the data _uSDO1ACode = mCO_DictGetRet(); COMM_SDO_1_TF = 1; } break;

case 0x80: // Abort Request // Reset SDO states _uSDO1State.byte = 0; break;

128

default: // Send abort, not a valid command _uSDO1ACode = E_CS_CMD; COMM_SDO_1_TF = 1; break; } } }

13. CO_TOOLS.c
/***************************************************************************** * * Microchip CANopen Stack (COB Conversion Tools) * ***************************************************************************** * FileName: CO_TOOLS.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * * Software License Agreement * * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... * *****************************************************************************/

129

#include "CO_TYPES.H"

// Data types

typedef struct _MCHP_SID { union _SIDH { unsigned char byte; }h; union _SIDL { unsigned char byte; struct _SIDL_BITS { unsigned unsigned unsigned unsigned unsigned }bits; }l; }MCHP_SID;

:2; b0:1; id:1; b1:1; SIDL:3;

typedef struct _MCHP_EID { union _EIDUH { unsigned char byte; }uh; union _EIDUL { unsigned char byte; struct _EIDUL_BITS { unsigned unsigned unsigned unsigned unsigned }bits; }ul; union _EIDH { unsigned char byte; }h;

EIDUL1:2; b0:1; id:1; b1:1; EIDUL2:3;

130

union _EIDL { unsigned char byte; }l; }MCHP_EID;

typedef union _CID { unsigned long lword; MCHP_EID ext; MCHP_SID std; }MCHP_CID;

typedef struct _CO_CID { union _CO_L { unsigned char byte; }l; union _CO_H { unsigned char byte; }h; union _CO_UL { unsigned char byte; }ul; union _CO_UH { unsigned char byte; struct _CO_UH_BITS { unsigned unsigned unsigned unsigned }bits; }uh; }CO_CID;

:5; id:1; b0:1; b1:1;

UNSIGNED32 UNSIGNED32

_uCOB_ID_in; _uCOB_ID_out;

131

/********************************************************************* * Function: void _CO_COB_CANopen2MCHP(void) * * PreCondition: _uCOB_ID_in must be loaded. * * Input: none * * Output: none * * Side Effects: none * * Overview: This function converts the CANopen COB format to * the MCHP format. * * Note: B3 B2 B1 B0 * ----------------------------------* CANopen format 28 - 24 23 - 16 15 - 8 7 - 0 * nmtxxxxx xxxxxxxx xxxxxxxx xxxxxxxx * MCHP format 7 - 0 15 - 8 20 - 16 28 - 21 * xxxxxxxx xxxxxxxx xxxntmxx xxxxxxxx * * CANopen format 10 - 8 7 - 0 * nmt----- -------- -----xxx xxxxxxxx * MCHP format 3 - 0 10 - 3 * -------- -------- xxxntm-- xxxxxxxx * n = option bit 1 * m = option bit 2 * t = ID type (standard = 0, extended = 1) ********************************************************************/ void _CO_COB_CANopen2MCHP(void) { // If this is an extended ID if (_uCOB_ID_in.bytes.B3.byte & 0x20) { // Shift bits 28 - 16 *(unsigned int *)(&_uCOB_ID_out.bytes.B0.byte) = (*(unsigned int *)(&_uCOB_ID_in.bytes.B2.byte)) << 3; // Temporarily store SIDH _uCOB_ID_out.bytes.B3.byte = _uCOB_ID_out.bytes.B1.byte; // Generate SIDL _uCOB_ID_out.bytes.B1.byte = ((_uCOB_ID_out.bytes.B0.byte & 0xE0) | (_uCOB_ID_in.bytes.B2.byte & 0x03)) | 0x08; // Copy SIDH _uCOB_ID_out.bytes.B0.byte = _uCOB_ID_out.bytes.B3.byte; // Copy EIDL and EIDH _uCOB_ID_out.bytes.B3.byte = _uCOB_ID_in.bytes.B0.byte; _uCOB_ID_out.bytes.B2.byte = _uCOB_ID_in.bytes.B1.byte; } // Else 11-bit ID

132

else { // Convert the ID _uCOB_ID_out.word = ((unsigned int)(_uCOB_ID_in.word) << 5); _uCOB_ID_out.bytes.B2.byte = _uCOB_ID_out.bytes.B0.byte; _uCOB_ID_out.bytes.B0.byte = _uCOB_ID_out.bytes.B1.byte; _uCOB_ID_out.bytes.B1.byte = _uCOB_ID_out.bytes.B2.byte & 0xE0; _uCOB_ID_out.bytes.B2.byte = 0; } // Set the option bits if (_uCOB_ID_in.bytes.B3.bits.b7) _uCOB_ID_out.bytes.B1.bits.b4 = 1; if (_uCOB_ID_in.bytes.B3.bits.b6) _uCOB_ID_out.bytes.B1.bits.b2 = 1; } /********************************************************************* * Function: void _CO_COB_CANopen2MCHP(void) * * PreCondition: _uCOB_ID_in must be loaded. * * Input: none * * Output: none * * Side Effects: none * * Overview: This function converts the CANopen COB format to * the MCHP format. * * Note: B3 B2 B1 B0 * ----------------------------------* CANopen format 28 - 24 23 - 16 15 - 8 7 - 0 * nmtxxxxx xxxxxxxx xxxxxxxx xxxxxxxx * MCHP format 7 - 0 15 - 8 20 - 16 28 - 21 * xxxxxxxx xxxxxxxx xxxntmxx xxxxxxxx * * CANopen format 10 - 8 7 - 0 * nmt----- -------- -----xxx xxxxxxxx * MCHP format 3 - 0 10 - 3 * -------- -------- xxxntm-- xxxxxxxx * * n = option bit 1 * m = option bit 2 * t = ID type (standard = 0, extended = 1) ********************************************************************/ void _CO_COB_MCHP2CANopen(void) { // If this is an extended ID if (_uCOB_ID_in.bytes.B1.byte & 0x08) { // Generate part of upper high and part of upper low _uCOB_ID_out.bytes.B3.byte = _uCOB_ID_in.bytes.B0.byte; _uCOB_ID_out.bytes.B2.byte = _uCOB_ID_in.bytes.B1.byte;

133

*(unsigned int *)(&_uCOB_ID_out.bytes.B2.byte) = ((*(unsigned int *)(&_uCOB_ID_out.bytes.B2.byte)) >> 3); _uCOB_ID_out.bytes.B3.byte = _uCOB_ID_out.bytes.B3.byte | 0x20; // Get the last two bits to complete upper low _uCOB_ID_out.bytes.B2.byte = (_uCOB_ID_out.bytes.B2.byte & 0xFC) | (_uCOB_ID_in.bytes.B1.byte & 0x03); // Get high _uCOB_ID_out.bytes.B0.byte = _uCOB_ID_in.bytes.B3.byte; // Get low _uCOB_ID_out.bytes.B1.byte = _uCOB_ID_in.bytes.B2.byte; } // Else 11-bit ID else { // Swap the bytes _uCOB_ID_out.bytes.B1.byte = _uCOB_ID_in.bytes.B0.byte; _uCOB_ID_out.bytes.B0.byte = _uCOB_ID_in.bytes.B1.byte; // Generate the low byte and part of the high byte (*(unsigned int *)(&_uCOB_ID_out.bytes.B0.byte)) = ((*(unsigned int *)(&_uCOB_ID_out.bytes.B0.byte)) >> 5); } // Set the option bits if (_uCOB_ID_in.bytes.B1.bits.b2) _uCOB_ID_out.bytes.B3.bits.b6 = 1; if (_uCOB_ID_in.bytes.B1.bits.b4) _uCOB_ID_out.bytes.B3.bits.b7 = 1; }

134

14. DemoObj.c
/***************************************************************************** * * Microchip CANopen Stack (Demonstration Object) * ***************************************************************************** * FileName: DemoObj.C * Dependencies: * Processor: PIC18F with CAN * Compiler: C18 02.30.00 or higher * Linker: MPLINK 03.70.00 or higher * Company: Microchip Technology Incorporated * * Software License Agreement * * The software supplied herewith by Microchip Technology Incorporated * (the "Company") is intended and supplied to you, the Company's * customer, for use solely and exclusively with products manufactured * by the Company. * * The software is owned by the Company and/or its supplier, and is * protected under applicable copyright laws. All rights are reserved. * Any use in violation of the foregoing restrictions may subject the * user to criminal sanctions under applicable laws, as well as to * civil liability for the breach of the terms and conditions of this * license. * * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * * * * * * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Ross Fosler 11/13/03 ... * *****************************************************************************/

#include "CO_MAIN.H" #include "p18f2585.h" #define RTR_DIS bytes.B1.bits.b2 #define STD_DIS bytes.B1.bits.b3

135

#define PDO_DIS bytes.B1.bits.b4 // These are mapping constants for TPDO1 // starting at 0x1A00 in the dictionary //rom unsigned long uTPDO1Map = 0x60000108; rom unsigned long uTPDO1Map = 0x60000; //rom unsigned long uRPDO1Map = 0x62000108; rom unsigned long uRPDO1Map = 0x62000; rom unsigned long uPDO1Dummy = 0x00000008; unsigned char uIOinFilter; unsigned char uIOinPolarity; unsigned char uIOinIntChange; unsigned char uIOinIntRise; unsigned char uIOinIntFall; unsigned char uIOinIntEnable; // 0x6003 filter // 0x6002 polarity // 0x6006 interrupt on change // 0x6007 interrupt on positive edge // 0x6008 interrupt on negative edge // 0x6005 enable interrupts

unsigned char uIOinDigiInOld; // unsigned char change ; unsigned char change1 ; // enable triggering the output port through writing in the object dictionary

// Static data refered to by the dictionary rom unsigned char rMaxIndex1 = 1; rom unsigned char rMaxIndex2 = 8; rom unsigned char uDemoTPDO1Len = 2;

unsigned char uLocalXmtBuffer[8]; unsigned char uLocalRcvBuffer[8]; UNSIGNED8 uDemoState; unsigned char uDemoSyncCount; unsigned char uDemoSyncSet;

// Local buffer for TPDO1 // local buffer fot RPDO1 // Bits used to control various states // Counter for synchronous types // Internal TPDO type control

/********************************************************************* * Function: void DemoInit(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is the initialization to the demonstration * object. * * Note: ********************************************************************/

136

void DemoInit(void) { // Port C 0-3 inputs 4-7 outputs TRISC=0x0F; LATC=0x00; PORTC=0x00; change = 0; change1 = 0; uDemoSyncSet = 255; uIOinFilter = 0; uIOinPolarity = 0; uIOinIntChange = 1; uIOinIntRise = 0; uIOinIntFall = 0; uIOinIntEnable = 1; uIOinDigiInOld = uLocalXmtBuffer[0] = 0; uLocalRcvBuffer[1] = uLocalXmtBuffer[1] = 0; uLocalRcvBuffer[2] = uLocalXmtBuffer[2] = 0; uLocalRcvBuffer[3] = uLocalXmtBuffer[3] = 0; uLocalRcvBuffer[4] = uLocalXmtBuffer[4] = 0; uLocalRcvBuffer[5] = uLocalXmtBuffer[5] = 0; uLocalRcvBuffer[6] = uLocalXmtBuffer[6] = 0; uLocalRcvBuffer[7] = uLocalXmtBuffer[7] = 0;

// Convert to MCHP mTOOLS_CO2MCHP(mCOMM_GetNodeID().byte + 0x00000180L); // Store the COB mTPDOSetCOB(1, mTOOLS_GetCOBID()); // Convert to MCHP mTOOLS_CO2MCHP(mCOMM_GetNodeID().byte + 0x00000200L); // Store the COB mRPDOSetCOB(1, mTOOLS_GetCOBID()); // Set the pointer to the buffers mTPDOSetTxPtr(1, (unsigned char *)(&uLocalXmtBuffer[0])); // Set the pointer to the buffers mRPDOSetRxPtr(1, (unsigned char *)(&uLocalRcvBuffer[0])); // Set the length mTPDOSetLen(1, 8);

137

/********************************************************************* * Function: void CO_COMMSyncEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is a simple demonstration of a SYNC event * handling function. * * Note: ********************************************************************/ void CO_COMMSyncEvent(void) { // Process only if in a synchronous mode if ((uDemoSyncSet == 0) && (uDemoState.bits.b2)) { // Reset the synchronous transmit and transfer to async uDemoState.bits.b2 = 0; uDemoState.bits.b0 = 1; } else if ((uDemoSyncSet >= 1) && (uDemoSyncSet <= 240)) { // Adjust the sync counter uDemoSyncCount--; // If time to generate sync if (uDemoSyncCount == 0) { // Reset the sync counter uDemoSyncCount = uDemoSyncSet; // Start the PDO transmission uDemoState.bits.b0 = 1; } } }

138

/********************************************************************* * Function: void DemoProcessEvents(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is a simple demonstration of a demo state * machine for cooperative multitasking. * * Note: ********************************************************************/ void DemoProcessEvents(void) { // Read the input port (*(UNSIGNED8 *)uLocalXmtBuffer).bits.b0 = ~PORTCbits.RC0; (*(UNSIGNED8 *)uLocalXmtBuffer).bits.b1 = ~PORTCbits.RC1; (*(UNSIGNED8 *)uLocalXmtBuffer).bits.b2 = ~PORTCbits.RC2; (*(UNSIGNED8 *)uLocalXmtBuffer).bits.b3 = ~PORTCbits.RC3;

// Determine the change if any change = uIOinDigiInOld ^ uLocalXmtBuffer[0]; // Cycle the current value to the old uIOinDigiInOld = uLocalXmtBuffer[0]; if (change) uDemoState.bits.b1 = 1; if (uDemoState.bits.b1) { switch (uDemoSyncSet) { case 0: // Asyclic synchronous transmit // Set a synchronous transmit flag uDemoState.bits.b2 = 1; break; case 254: // Asynchronous transmit case 255: // Reset the asynchronous transmit flag uDemoState.bits.b0 = 1; break; } }

139

// If ready to send if (mTPDOIsPutRdy(1) && uDemoState.bits.b0) { // Tell the stack data is loaded for transmit mTPDOWritten(1); // Reset any synchronous or asynchronous flags uDemoState.bits.b0 = 0; uDemoState.bits.b1 = 0; } // If any data has been received if (mRPDOIsGetRdy(1)|| (change1 ^uLocalRcvBuffer[0]) ) { // Write out the first byte of the buffer LATC = uLocalRcvBuffer[0]; change1 = uLocalRcvBuffer[0];

// PDO read, free the driver to accept more data mRPDORead(1); } }

/********************************************************************* * Function: void CO_COMM_RPDO1_COBIDAccessEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is a simple demonstration of a RPDO COB access * handling function. * * Note: This function is called from the dictionary. ********************************************************************/ void CO_COMM_RPDO1_COBIDAccessEvent(void) { switch (mCO_DictGetCmd()) { case DICT_OBJ_READ: // Read the object // Translate MCHP COB to CANopen COB mTOOLS_MCHP2CO(mRPDOGetCOB(1));

140

// Return the COBID *(unsigned long *)(uDict.obj->pReqBuf) = mTOOLS_GetCOBID(); break; case DICT_OBJ_WRITE: // Write the object // Translate the COB to MCHP format mTOOLS_CO2MCHP(*(unsigned long *)(uDict.obj->pReqBuf)); // If the request is to stop the PDO if ((*(UNSIGNED32 *)(&mTOOLS_GetCOBID())).PDO_DIS) { // And if the COB received matches the stored COB and type then close if (!((mTOOLS_GetCOBID() ^ mRPDOGetCOB(1)) & 0xFFFFEFFFL)) { // but only close if the PDO endpoint was open if (mRPDOIsOpen(1)) {mRPDOClose(1);} // Indicate to the local object that this PDO is disabled (*(UNSIGNED32 *)(&mRPDOGetCOB(1))).PDO_DIS = 1; } else {mCO_DictSetRet(E_PARAM_RANGE);} //error } // Else if the TPDO is not open then start the TPDO else { // And if the COB received matches the stored COB and type then open if (!((mTOOLS_GetCOBID() ^ mRPDOGetCOB(1)) & 0xFFFFEFFFL)) { // but only open if the PDO endpoint was closed if (!mRPDOIsOpen(1)) {mRPDOOpen(1);} // Indicate to the local object that this PDO is enabled (*(UNSIGNED32 *)(&mRPDOGetCOB(1))).PDO_DIS = 0; } else {mCO_DictSetRet(E_PARAM_RANGE);} //error } break; } }

141

/********************************************************************* * Function: void CO_COMM_TPDO1_COBIDAccessEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is a simple demonstration of a TPDO COB access * handling function. * * Note: This function is called from the dictionary. ********************************************************************/ void CO_COMM_TPDO1_COBIDAccessEvent(void) { switch (mCO_DictGetCmd()) { case DICT_OBJ_READ: // Read the object // Translate MCHP COB to CANopen COB mTOOLS_MCHP2CO(mTPDOGetCOB(1)); // Return the COBID *(unsigned long *)(uDict.obj->pReqBuf) = mTOOLS_GetCOBID(); break; case DICT_OBJ_WRITE: // Write the object // Translate the COB to MCHP format mTOOLS_CO2MCHP(*(unsigned long *)(uDict.obj->pReqBuf)); // If the request is to stop the PDO if ((*(UNSIGNED32 *)(&mTOOLS_GetCOBID())).PDO_DIS) { // And if the COB received matches the stored COB and type then close if (!((mTOOLS_GetCOBID() ^ mTPDOGetCOB(1)) & 0xFFFFEFFFL)) { // but only close if the PDO endpoint was open if (mTPDOIsOpen(1)) {mTPDOClose(1);} // Indicate to the local object that this PDO is disabled (*(UNSIGNED32 *)(&mTPDOGetCOB(1))).PDO_DIS = 1; } else {mCO_DictSetRet(E_PARAM_RANGE);} //error }

142

// Else if the TPDO is not open then start the TPDO else { // And if the COB received matches the stored COB and type then open if (!((mTOOLS_GetCOBID() ^ mTPDOGetCOB(1)) & 0xFFFFEFFFL)) { // but only open if the PDO endpoint was closed if (!mTPDOIsOpen(1)) {mTPDOOpen(1);} // Indicate to the local object that this PDO is enabled (*(UNSIGNED32 *)(&mTPDOGetCOB(1))).PDO_DIS = 0; } else {mCO_DictSetRet(E_PARAM_RANGE);} //error } break; } }

/********************************************************************* * Function: void CO_COMM_TPDO1_TypeAccessEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: This is a simple demonstration of a TPDO type access * handling function. * * Note: This function is called from the dictionary. ********************************************************************/ void CO_COMM_TPDO1_TypeAccessEvent(void) { unsigned char tempType; switch (mCO_DictGetCmd()) { //case DICT_OBJ_INFO: // Get information about the object // The application should use this to load the // structure with legth, access, and mapping. // break; case DICT_OBJ_READ: // Read the object // Write the Type to the buffer *(uDict.obj->pReqBuf) = uDemoSyncSet; break;

143

case DICT_OBJ_WRITE: // Write the object tempType = *(uDict.obj->pReqBuf); if ((tempType >= 0) && (tempType <= 240)) { // Set the new type and resync uDemoSyncCount = uDemoSyncSet = tempType; } else if ((tempType == 254) || (tempType == 255)) { uDemoSyncSet = tempType; } else {mCO_DictSetRet(E_PARAM_RANGE);} //error break; } } /********************************************************************* * Function: void CO_PDO1LSTimerEvent(void) * * PreCondition: none * * Input: none * * Output: none * * Side Effects: none * * Overview: none * * Note: none ********************************************************************/ void CO_PDO1LSTimerEvent(void) { } /********************************************************************* * Function: void CO_PDO1TXFinEvent(void) * PreCondition: none * Input: none * Output: none * Side Effects: none * Overview: none * Note: none ********************************************************************/ void CO_PDO1TXFinEvent(void) { }

144

15. CO_DEFS.DEF
#define CAN_BITRATE0_BRGCON1 #define CAN_BITRATE0_BRGCON2 #define CAN_BITRATE0_BRGCON3 #define CAN_BITRATE1 #define CAN_BITRATE1_BRGCON1 #define CAN_BITRATE1_BRGCON2 #define CAN_BITRATE1_BRGCON3 #define CAN_BITRATE2 #define CAN_BITRATE2_BRGCON1 #define CAN_BITRATE2_BRGCON2 #define CAN_BITRATE2_BRGCON3 #define CAN_BITRATE3 #define CAN_BITRATE3_BRGCON1 #define CAN_BITRATE3_BRGCON2 #define CAN_BITRATE3_BRGCON3 #define CAN_BITRATE4 #define CAN_BITRATE4_BRGCON1 #define CAN_BITRATE4_BRGCON2 #define CAN_BITRATE4_BRGCON3 #define CAN_BITRATE5 #define CAN_BITRATE5_BRGCON1 #define CAN_BITRATE5_BRGCON2 #define CAN_BITRATE5_BRGCON3 #define CAN_BITRATE6 #define CAN_BITRATE6_BRGCON1 #define CAN_BITRATE6_BRGCON2 #define CAN_BITRATE6_BRGCON3 #define CAN_BITRATE7 #define CAN_BITRATE7_BRGCON1 #define CAN_BITRATE7_BRGCON2 #define CAN_BITRATE7_BRGCON3 #define CAN_BITRATE8 #define CAN_BITRATE8_BRGCON1 #define CAN_BITRATE8_BRGCON2 #define CAN_BITRATE8_BRGCON3 #define CAN_MAX_RCV_ENDP 8 #define CO_NUM_OF_PDO 1 #define CO_SPEED_UP_CODE 0 #define CO_TICK_PERIOD #define CO_SDO1_MAX_RX_BUF #define CO_SDO1_MAX_SEG_TIME 0x00 0x92 0x82 1 0x41 0x92 0x82 1 0x01 0x92 0x82 1 0x01 0x92 0x82 1 0x03 0x92 0x82 1 0x07 0x92 0x82 1 0x41 0xBA 0x07 1 0x41 0xBA 0x07 1 0x41 0xBA 0x07

8 20 500 // Time in milliseconds

145

16. CO_dict.def
/********************************************************************* * Be sure to include all headers here that relate to the symbols * below. ********************************************************************/ #include #include #include #include "CO_DEV.H" "CO_SYNC.H" "CO_NMTE.H" "CO_SDO1.H" // Standard device information // SYNC Object support // Error protocols: heartbeat, node-guard // SDO1, the default SDO

//

<index_l>,<index_h>,<sub index>,<type>,<count>,<ptr>

/********************************************************************* * This memory region defines the data types. All the indices in this * definition must range from 0x0001 to 0x009F. According to the * CANOpen specification these are not required to be handled. If * they are implimented then they should be read only and return the * length of the object. ********************************************************************/ #define DICTIONARY_DATA_TYPES \\ {0x0001,0x00,WO | ROM_BIT | MAP_BIT,1,{(rom unsigned char *)&__dummy[0]}}, \\ {0x0002,0x00,WO | ROM_BIT | MAP_BIT,1,{(rom unsigned char *)&__dummy[0]}}, \\ {0x0003,0x00,WO | ROM_BIT | MAP_BIT,2,{(rom unsigned char *)&__dummy[0]}}, \\ {0x0004,0x00,WO | ROM_BIT | MAP_BIT,4,{(rom unsigned char *)&__dummy[0]}}, \\ {0x0005,0x00,WO | ROM_BIT | MAP_BIT,1,{(rom unsigned char *)&__dummy[0]}}, \\ {0x0006,0x00,WO | ROM_BIT | MAP_BIT,2,{(rom unsigned char *)&__dummy[0]}}, \\ {0x0007,0x00,WO | ROM_BIT | MAP_BIT,4,{(rom unsigned char *)&__dummy[0]}} /********************************************************************* * This memory region defines the device. All the indices in this * definition must range from 0x1000 to 0x10FF. ********************************************************************/ #define DICTIONARY_DEVICE_INFO \\ {0x1000,0x00,CONST,4,{(rom unsigned char *)&rCO_DevType}}, \\ {0x1017,0x00,FUNC | RO,2,{(rom unsigned char *)&_CO_COMM_NMTE_HeartBeatAccessEvent}}, \\ {0x1018,0x04,CONST,4,{(rom unsigned char *)&rCO_DevSerialNo}}

146

/********************************************************************* * This memory region defines the SDOs. All the indices in this * definition must range from 0x1200 to 0x12FF. SDO servers range * from 0x1200 to 0x127F. SDO clients range from 0x1280 to 0x13FF. ********************************************************************/ #define DICTIONARY_SDO \\ {0x1200,0x00,CONST,1,{(rom unsigned char *)&_uSDO1COMMIndx}}, \\ {0x1200,0x01,FUNC | RO,4,{(rom unsigned char *)&_CO_COMM_SDO1_CS_COBIDAccessEvent}}, \\ {0x1200,0x02,FUNC | RO,4,{(rom unsigned char *)&_CO_COMM_SDO1_SC_COBIDAccessEvent}}

17. CO_PDO.DEF
#include "demoObj.h"

/********************************************************************* * This memory region defines receive PDOs. All the indices in this * definition must range from 0x1400 to 0x15FF. ********************************************************************/ #define DICTIONARY_PDO1_RX_COMM \\ {0x1400,0x00,CONST,1,{(rom unsigned char *)&rMaxIndex1}}, {0x1400,0x01,RO | FUNC,4,{(rom unsigned char *)&CO_COMM_RPDO1_COBIDAccessEvent}} /********************************************************************* * This memory region defines receive PDOs mapping. All the indices * in this definition must range from 0x1600 to 0x17FF. ********************************************************************/ #define DICTIONARY_PDO1_RX_MAP \\ {0x1600,0x00,CONST,1,{(rom unsigned char *)&rMaxIndex2}}, \\ {0x1600,0x01,CONST,4,{(rom unsigned char *)&uRPDO1Map}}, {0x1600,0x02,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1600,0x03,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1600,0x04,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1600,0x05,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1600,0x06,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1600,0x07,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1600,0x08,CONST,4,{(rom unsigned char *)&uPDO1Dummy}} /********************************************************************* * This memory region defines transmit PDOs. All the indices in this * definition must range from 0x1800 to 0x19FF. ********************************************************************/

\\

\\ \\ \\ \\ \\ \\ \\

147

#define \\

DICTIONARY_PDO1_TX_COMM

{0x1800,0x00,CONST,1,{(rom unsigned char *)&uDemoTPDO1Len}}, \\ {0x1800,0x01,RO | FUNC,4,{(rom unsigned char *)&CO_COMM_TPDO1_COBIDAccessEvent}}, \\ {0x1800,0x02,RO | FUNC,1,{(rom unsigned char *)&CO_COMM_TPDO1_TypeAccessEvent}} /********************************************************************* * This memory region defines receive PDOs mapping. All the indices * in this definition must range from 0x1A00 to 0x1BFF. ********************************************************************/ #define DICTIONARY_PDO1_TX_MAP {0x1A00,0x00,CONST,1,{(rom unsigned char *)&rMaxIndex2}}, \\ {0x1A00,0x01,CONST,4,{(rom unsigned char *)&uTPDO1Map}}, {0x1A00,0x02,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1A00,0x03,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1A00,0x04,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1A00,0x05,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1A00,0x06,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1A00,0x07,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}, {0x1A00,0x08,CONST,4,{(rom unsigned char *)&uPDO1Dummy}}

\\ \\ \\ \\ \\ \\ \\ \\

18. CO_STD.DEF
/********************************************************************* * Be sure to include all headers here that relate to the symbols * below. ********************************************************************/ #include "DemoObj.h" /********************************************************************* * This memory region defines standard objects. All the * indices in this definition must range from 0x6000 to 0x6FFF. ********************************************************************/ #define DICTIONARY_STANDARD_1 {0x6000,0x00,RO,1,{(rom unsigned char *)&uLocalXmtBuffer[0]}}, \\ {0x6200,0x00,RW,1,{(rom unsigned char *)&uLocalRcvBuffer[0]}} /********************************************************************* * This memory region defines standard objects. All the * indices in this definition must range from 0x7000 to 0x7FFF. ********************************************************************/ #define DICTIONARY_STANDARD_2 {0x7000,0x00,0,1,{(rom unsigned char *)&__dummy}}, {0x7000,0x00,0,1,{(rom unsigned char *)&__dummy}}

\\

\\ \\

148

/********************************************************************* * This memory region defines standard objects. All the * indices in this definition must range from 0x8000 to 0x8FFF. ********************************************************************/ #define DICTIONARY_STANDARD_3 {0x8000,0x00,0,1,{(rom unsigned char *)&__dummy}}, {0x8000,0x00,0,1,{(rom unsigned char *)&__dummy}} /********************************************************************* * This memory region defines standard objects. All the * indices in this definition must range from 0x9000 to 0x9FFF. ********************************************************************/ #define DICTIONARY_STANDARD_4 {0x9000,0x00,0,1,{(rom unsigned char *)&__dummy}}, {0x9000,0x00,0,1,{(rom unsigned char *)&__dummy}}

\\ \\

\\ \\

149

Potrebbero piacerti anche