diff -r 1c0edf99def0 -r c75cdcc5ce87 documentation/ethercat_doc.tex --- a/documentation/ethercat_doc.tex Wed Jul 02 14:41:29 2008 +0000 +++ b/documentation/ethercat_doc.tex Thu Jul 03 15:17:51 2008 +0000 @@ -6,6 +6,57 @@ % %------------------------------------------------------------------------------ +% +% Conventions +% The IgH EtherCAT Master +% Feature Summary +% License +% Architecture +% Phases +% Behavior (Scanning) TODO +% Application Interface +% Interface version +% Master Requesting and Releasing +% Master Locking +% Slave configuration +% Configuring Pdo assignment and mapping +% Domains (memory) +% Pdo entry registration +% Sdo configuration +% Sdo access +% Cyclic operation +% Ethernet Devices +% Device Interface +% Device Modules +% Network Driver Basics +% EtherCAT Network Drivers +% Device Selection +% The Device Interface +% Patching Network Drivers +% The Master's State Machines +% Master +% Slave scanning +% SII +% Pdo assign/mapping +% Slave configuration +% State change +% Pdo assign/mapping +% CoE upload/download/information +% Mailbox Protocol Implementations +% Ethernet-over-EtherCAT (EoE) +% CANopen-over-EtherCAT (CoE) +% User Space +% The ethercat command +% System Integration +% The EtherCAT Init Script +% The EtherCAT Sysconfig File +% Monitoring and Debugging +% Installation +% Example applications +% Bibliography +% Glossary +% + \documentclass[a4paper,12pt,BCOR6mm,bibtotoc,idxtotoc]{scrbook} \usepackage[latin1]{inputenc} @@ -17,6 +68,7 @@ \usepackage{svn} \usepackage{textcomp} \usepackage{url} +\usepackage{SIunits} \usepackage[pdfpagelabels,plainpages=false]{hyperref} \setlength{\parskip}{0.8ex plus 0.8ex minus 0.5ex} @@ -30,7 +82,7 @@ }{} \lstset{basicstyle=\ttfamily\small,numberstyle=\tiny,aboveskip=4mm, - belowskip=2mm,gobble=2,escapechar=`} + belowskip=2mm,escapechar=`} \renewcommand\lstlistlistingname{List of Listings} % Workaround for lstlistoflistings bug @@ -60,7 +112,8 @@ \SVN $Date$ \SVN $Revision$ -\newcommand{\masterversion}{1.1.1} +\newcommand{\masterversion}{1.4.0} +\newcommand{\linenum}[1]{\normalfont\textcircled{\tiny #1}} \makeindex \makenomenclature @@ -112,37 +165,37 @@ The following typographic conventions are used: \begin{itemize} -\item \textit{Italic face} is used for newly introduced terms, file - names, parameter names and in-text source code elements. -\item \texttt{Typewriter face} is used for code examples and - command line output. -\item \texttt{\textbf{Bold typewriter face}} is used for user input in - command lines. + +\item \textit{Italic face} is used for newly introduced terms and file names. + +\item \texttt{Typewriter face} is used for code examples and command line +output. + +\item \texttt{\textbf{Bold typewriter face}} is used for user input in command +lines. + \end{itemize} -Data values and addresses are specified as hexadecimal values with the -prefix 0x. Example: 0x88A4. Unless otherwise noted, address values are -specified as byte addresses. - -Concerning bit operations, the phrase ``setting a bit'', stands for -setting the bit to $1$, ``clearing a bit'' means setting it to $0$, -respectively. +Data values and addresses are usually specified as hexadecimal values. These +are marked in the \textit{C} programming language style with the prefix +\lstinline+0x+ (example: \lstinline+0x88A4+). Unless otherwise noted, address +values are specified as byte addresses. Function names are always printed with parentheses, but without -parameters. So, if a function \textit{ecrt\_request\_master()} has -empty parentheses, this does not mean, that it has no parameters. - -If shell commands have to be entered, this is marked by a prompt: - -\begin{lstlisting}[gobble=2] - `\$` +parameters. So, if a function \lstinline+ecrt_request_master()+ has +empty parentheses, this shall not imply that it has no parameters. + +If shell commands have to be entered, this is marked by a dollar prompt: + +\begin{lstlisting} +$ \end{lstlisting} Further, if a shell command has to be entered as the superuser, the -prompt ends with a mesh: - -\begin{lstlisting}[gobble=2] - # +prompt is a mesh: + +\begin{lstlisting} +# \end{lstlisting} %------------------------------------------------------------------------------ @@ -151,12 +204,7 @@ \label{chapter:master} \pagenumbering{arabic} -This section will first introduce the master's general features and -the concepts used for master development and will then explain the -master's general architecture and offer details of the different -modules. In addition, it will cover state machine definitions, mailbox -protocol implementation and the user space interface. The last section -will deal with timing aspects. +This chapter covers some general information about the EtherCAT master. %------------------------------------------------------------------------------ @@ -164,81 +212,121 @@ \label{sec:summary} \index{Master!Features} -The list below gives a short summary of the features of the -implemented EtherCAT master. +The list below gives a short summary of the master features. \begin{itemize} -\item The master runs as a kernel module for Linux 2.6. -\item It comes with EtherCAT-capable network driver for RealTek - RTL8139 (and compatible) network interface cards. + +\item Designed as a kernel module for Linux 2.6. + +\item Comes with EtherCAT-capable drivers for several common Ethernet devices. + \begin{itemize} + \item The Ethernet hardware is operated without interrupts. - \item Drivers for additional Ethernet hardware can easily be - implemented due to a common device interface provided by the - master. + + \item Drivers for additional Ethernet hardware can easily be implemented + using the common device interface (see section~\ref{sec:ecdev}) provided by + the master module. + \end{itemize} -\item The master module supports multiple EtherCAT masters on one - machine. -\item The master code supports any Linux realtime extension through - its independent architecture. + +\item The master module supports multiple EtherCAT masters running in +parallel. + +\item The master code supports any Linux realtime extension through its +independent architecture. + \begin{itemize} - \item RTAI\nomenclature{RTAI}{RealTime Application Interface}, - ADEOS\nomenclature{ADEOS}{Adaptive Domain Environment for - Operating Systems}, etc. + + \item RTAI\nomenclature{RTAI}{Realtime Application Interface}, + ADEOS\nomenclature{ADEOS}{Adaptive Domain Environment for Operating + Systems}, etc. + \item It runs well even without realtime extensions. + \end{itemize} -\item Common ``realtime interface'' for modules, that want to use - EtherCAT functionality. + +\item Common ``realtime interface'' for applications, that want to use +EtherCAT functionality (see section~\ref{sec:ecrt}). + +\item \textit{Domains} are introduced, to allow grouping of process + data transfers with different slave groups and task periods. + \begin{itemize} - \item Synchronous and asynchronous sending and receiving of frames - is supported. - \item Avoidance of unnecessary copy operations for process data. + + \item Handling of multiple domains with different task periods. + + \item Automatic calculation of process data mapping, FMMU and sync manager + configuration within each domain. + \end{itemize} -\item \textit{Domains} are introduced, to allow grouping of process - data objects. + +\item Communication through several finite state machines. + \begin{itemize} - \item Handling of multiple domains with different sampling rates. - \item Automatic calculation of process data mapping, FMMU and sync manager - configuration within each domain. + + \item Automatic bus scanning after topology changes. + + \item Bus monitoring during operation. + + \item Automatic reconfiguration of slaves (for example after power failure) + during operation. + \end{itemize} -\item Communication through serveral finite state machines. + +\item CANopen-over-EtherCAT (CoE) + \begin{itemize} - \item Bus monitoring possible during realtime operation. - \item Automatic reconfiguration of slaves on bus power failure - during realtime operation. - \item Controlling of single slaves during realtime operation. + + \item Sdo upload, download and information service. + + \item Slave configuration via Sdos. + + \item Sdo access from user-space and from the application. + \end{itemize} -\item Master idle mode. + +\item Ethernet-over-EtherCAT (EoE) + \begin{itemize} - \item Automatic scanning of slaves upon topology changes. - \item Bus visualisation and EoE processing without a realtime module - connected. + + \item Transparent use of EoE slaves via virtual network interfaces. + + \item Natively supports either a switched or a routed EoE network + architecture. + \end{itemize} -\item Implementation of the CANopen-over-EtherCAT (CoE) protocol. + +\item User space command-line-tool ``ethercat``. + \begin{itemize} - \item Configuration of CoE-capable slaves via Sdo interface. + + \item Showing the current bus with slaves, Pdos and Sdos. + \item Showing the bus configuration. + \item Showing domains and process data. + \item Setting the master's debug level. + \item Writing alias addresses. + \item Sdo uploading/downloading. + \item Reading/writing a slave's SII. + \item Setting slave states. + \item Generate slave description XML. + \end{itemize} -\item Implementation of the Ethernet-over-EtherCAT (EoE) protocol. - \begin{itemize} - \item Each master creates virtual network devices that are - automatically coupled to EoE-cap\-able slaves found. - \item This implementation natively supports either a switched or a - routed EoE network architecture. - \end{itemize} -\item User space interface via the System Filesystem - (Sysfs)\nomenclature{Sysfs}{System Filesystem}. - \begin{itemize} - \item User space tool for bus visualisation. - \item Slave E$^2$PROM image reading and writing. - \end{itemize} + \item Seamless system integration though LSB\nomenclature{LSB}{Linux Standard Base} compliance. + \begin{itemize} + \item Master and network device configuration via Sysconfig files. - \item Linux Standard Base compatible init script for master control. + + \item Init script for master control. + \end{itemize} + \item Virtual read-only network interface for monitoring and debugging purposes. + \end{itemize} %------------------------------------------------------------------------------ @@ -253,107 +341,180 @@ %------------------------------------------------------------------------------ -\section{General Master Architecture} -\label{sec:masterarch} +\chapter{Architecture} +\label{sec:arch} \index{Master!Architecture} The EtherCAT master is integrated into the Linux 2.6 kernel. This was -an early design decision, which has been made for serveral reasons: +an early design decision, which has been made for several reasons: \begin{itemize} -\item Kernel code has significantly better realtime characteristics, - i.~e. less jitter than user space code. It was foreseeable, that a - fieldbus master has a lot of cyclic work to do. Cyclic work is - usually triggered by timer interrupts inside the kernel. The - execution delay of a function that processes timer interrupts is - less, when it resides in kernel space, because there is no need of - time-consuming context switches to a user space process. + +\item Kernel code has significantly better realtime characteristics, i.~e. +less latency than user space code. It was foreseeable, that a fieldbus master +has a lot of cyclic work to do. Cyclic work is usually triggered by timer +interrupts inside the kernel. The execution delay of a function that processes +timer interrupts is less, when it resides in kernel space, because there is no +need of time-consuming context switches to a user space process. + \item It was also foreseeable, that the master code has to directly - communicate with the Ethernet hardware. This has to be done in the - kernel anyway (through network device drivers), which is one more - reason for the master code being in kernel space. +communicate with the Ethernet hardware. This has to be done in the kernel +anyway (through network device drivers), which is one more reason for the +master code being in kernel space. + \end{itemize} -A general overview of the master architecture can be seen in -figure~\ref{fig:masterarch}. +Figure~\ref{fig:arch} gives a general overview of the master architecture. \begin{figure}[htbp] \centering - \includegraphics[width=.9\textwidth]{images/masterarch} + \includegraphics[width=.9\textwidth]{images/architecture} \caption{Master architecture} - \label{fig:masterarch} + \label{fig:arch} \end{figure} \paragraph{Master Module} \index{Master module} -The EtherCAT master mainly consists of the master module, containing -one or more EtherCAT masters (section~\ref{sec:mastermod}), the -``Device Interface'' (section~\ref{sec:ecdev}) and the ``Realtime -Interface'' (section~\ref{sec:ecrt}). +The EtherCAT master mainly consists of the master module, containing one or +more EtherCAT masters (section~\ref{sec:mastermod}), the ``Device Interface'' +(section~\ref{sec:ecdev}) and the ``Realtime Interface'' +(section~\ref{sec:ecrt}). \paragraph{Device Modules} \index{Device modules} Furthermore there are EtherCAT-capable network device driver -modules\index{Device modules}, that connect to the EtherCAT master via -the device interface. These modified network drivers can handle both -network devices used for EtherCAT operation and ``normal'' Ethernet -devices. The common case is, that the master module offers a single -EtherCAT master: An EtherCAT-capable network device driver module -connects one network device to this master, that is now able to send -and receive EtherCAT frames, while all other network devices handled -by the network driver get connected to the kernel's network stack as -usual. - -\paragraph{Realtime Modules} - -A ``realtime module''\index{Realtime module} is a kernel module, that -uses the EtherCAT master for cyclic exchange of process data with -EtherCAT slaves. Realtime modules are not part of the EtherCAT master -code\footnote{Although there are serveral examples provided in the - \textit{examples} directory, see chapter~\ref{chapter:usage} for - more information}, so anybody wanting to use the master has to write -one. A realtime module can ``request'' a master through the realtime -interface. If this succeeds, the module has the control over the -master. It can now configure slaves and set up a process data image -(see section~\ref{sec:processdata}) for cyclic exchange. This cyclic -code has to be provided by the realtime module, so it is in hands of -the developer, which mechanism to use for this. Moreover he has to -decide, whether or not using a Linux realtime extension. - -\paragraph{Why ``Realtime'' Module?} - -The name shall not imply, that a linux realtime extension is -mandatory: The master runs well even without realtime extensions, as -section~\ref{sec:mini} shows. However, the code using the master is -time-critical, because process data IO has to be done in cyclic work. -Some EtherCAT slaves support watchdog units, that stop driving the -outputs when process data was not exchanged for some time. So the -names ``realtime interface'' and ``realtime module'' are quite -appropriate. - -%------------------------------------------------------------------------------ - -\subsection{Handling of Process Data} +modules\index{Device modules}, that connect to the EtherCAT master via the +device interface. These modified network drivers can handle both network +devices used for EtherCAT operation and ``normal'' Ethernet devices. The +common case is, that the master module offers a single EtherCAT master: An +EtherCAT-capable network device driver module connects one network device to +this master, that is now able to send and receive EtherCAT frames, while all +other network devices handled by the network driver get connected to the +kernel's network stack as usual. + +\paragraph{Application Modules} + +An application module''\index{Application module} is a kernel module, that +uses the EtherCAT master (usually for cyclic exchange of process data with +EtherCAT slaves). These modules are not part of the EtherCAT master +code\footnote{Although there are some examples provided in the +\textit{examples} directory, see chapter~\ref{chapter:usage}}, but have to be +generated or written by the application engineer. An application module can +``request'' a master through the realtime interface (see +section~\ref{sec:ecrt}). If this succeeds, the module has the control over the +master: It can provide a bus configuration and exchange process data. + +%------------------------------------------------------------------------------ + +\section{Phases} +\index{Master phases} + +The EtherCAT master has several phases (see fig.~\ref{fig:phases}): + +\begin{figure}[htbp] + \centering + \includegraphics[width=.9\textwidth]{images/phases} + \caption{Master phases and transitions} + \label{fig:phases} +\end{figure} +\begin{description} + +\item[Orphaned phase]\index{Orphaned phase} This mode takes effect, when the +master has no Ethernet device connected. No bus communication is possible. + +\item[Idle phase]\index{Idle phase} takes effect when the master has an +Ethernet device connected, but is not requested by any application. The master +runs its state machine (see section~\ref{sec:fsm-master}), that automatically +scans the bus for slaves and executes pending operations from the user space +interface (for example Sdo access). The command-line tool can be used to access +the bus, but there is no process data exchange because of the missing bus +configuration. + +\item[Operation phase]\index{Operation phase} The master is requested by an +application that can provide a bus configuration and exchange process data. + +\end{description} + +%------------------------------------------------------------------------------ + +\section{General behavior} % FIXME +\index{Master behavior} + +\ldots + +%------------------------------------------------------------------------------ + +\section{The Master Module} % FIXME +\label{sec:mastermod} +\index{Master module} + +The EtherCAT master is designed to run as a kernel module. Moreover +the master kernel module \textit{ec\_master} can handle multiple +masters at the same time: The number of masters has to be passed to +the module with the parameter \textit{ec\_master\_count}, that +defaults to $1$. A certain master can later be addressed by its index. +For example, if the master module has been loaded with the command + +\begin{lstlisting}[gobble=2] + # `\textbf{modprobe ec\_master ec\_master\_count=2}` +\end{lstlisting} + +the two masters can be addressed by their indices 0 and 1 respectively +(see figure~\ref{fig:masters}). This master index mandatory for +certain functions of the master interfaces. + +\begin{figure}[htbp] + \centering + \includegraphics[width=.5\textwidth]{images/masters} + \caption{Multiple masters in one module} + \label{fig:masters} +\end{figure} + +\paragraph{Master Log Messages} + +The master module gives information about it's state and events via +the Syslog interface. The module loading command above should result +in the Syslog messages below (or similar): + +\begin{lstlisting}[gobble=2] + EtherCAT: Master driver, 1.1 (stable) - rev. 513, + compiled by fp at Aug 09 2006 09:43:50 + EtherCAT: Initializing 2 EtherCAT master(s)... + EtherCAT: Initializing master 0. + EtherCAT: Initializing master 1. + EtherCAT: Master driver initialized. +\end{lstlisting} + +The master provides information about it's version number, subversion +revision number and compile information, like the date of compilation +and the user, who compiled. All messages are prefixed either with +\texttt{EtherCAT:}, \texttt{EtherCAT WARNING:} or \texttt{EtherCAT + ERROR:}, which makes searching the logs easier. + +%------------------------------------------------------------------------------ + +\section{Handling of Process Data} % FIXME \label{sec:processdata} +\ldots + \paragraph{Process Data Image} \index{Process data} -The slaves offer their inputs and outputs by presenting the master -so-called ``Process Data Objects'' (Pdos\index{Pdo}). The available -Pdos can be determined by reading out the slave's TXPDO and RXPDO -E$^2$PROM categories. The realtime module can register the Pdos for -data exchange during cyclic operation. The sum of all registered Pdos -defines the ``process data image'', which is exchanged via the -``Logical ReadWrite'' datagrams introduced +The slaves offer their inputs and outputs by presenting the master so-called +``Process Data Objects'' (Pdos\index{Pdo}). The available Pdos can be +determined by reading out the slave's TXPDO and RXPDO E$^2$PROM categories. The +application can register the Pdos for data exchange during cyclic operation. +The sum of all registered Pdos defines the ``process data image'', which is +exchanged via the ``Logical ReadWrite'' datagrams introduced in~\cite[section~5.4.2.4]{dlspec}. \paragraph{Process Data Domains} \index{Domain} -The process data image can be easily managed by creating co-called +The process data image can be easily managed by creating so-called ``domains'', which group Pdos and allocate the datagrams needed to exchange them. Domains are mandatory for process data exchange, so there has to be at least one. They were introduced for the following @@ -382,7 +543,7 @@ \paragraph{FMMU Configuration} \index{FMMU!Configuration} -A realtime module can register Pdos for process data exchange. Every +An application can register Pdos for process data exchange. Every Pdo is part of a memory area in the slave's physical memory, that is protected by a sync manager \cite[section~6.7]{dlspec} for synchronized access. In order to make a sync manager react on a @@ -406,98 +567,485 @@ \begin{figure}[htbp] \centering \includegraphics[width=\textwidth]{images/fmmus} - \caption{FMMU configuration for serveral domains} + \caption{FMMU configuration for several domains} \label{fig:fmmus} \end{figure} -\paragraph{Process Data Pointers} - -The figure also demonstrates the way, the realtime module can access the -exchanged process data: At Pdo registration, the realtime module has -to provide the address of a process data pointer. Upon calculation of -the domain image and allocation of process data memory, this pointer -is redirected to the appropriate location inside the domain's process -data memory and can later be easily dereferenced by the module code. - -%------------------------------------------------------------------------------ - -\subsection{Operation Modes} -\index{Master modes} - -The EtherCAT master has serveral modes of operation: +\paragraph{Process Data Pointers} % FIXME + +The figure also demonstrates the way, the application can access the exchanged +process data: At Pdo registration, the application has to provide the address +of a process data pointer. Upon calculation of the domain image and allocation +of process data memory, this pointer is redirected to the appropriate location +inside the domain's process data memory and can later be easily dereferenced by +the module code. + +%------------------------------------------------------------------------------ + +\chapter{Application Interface} +\label{sec:ecrt} +\index{Application interface} + +%------------------------------------------------------------------------------ + +\section{The Realtime Interface} % FIXME move information to ecrt.h, reference +\label{sec:ecrt} +\index{Realtime interface} + +The realtime interface provides functions and data structures for applications +to access and use an EtherCAT master. + +% \paragraph{Master Phases} +% +% Every application should use the master in three phases: +% +% \begin{enumerate} +% \item \textit{Startup} - The master is requested and the bus is +% validated. Domains are created and Pdos are registered. Slave +% configurations are applied. +% \item \textit{Operation} - Cyclic code is run, process data is +% exchanged and the master state machine is executed. +% \item \textit{Shutdown} - Cyclic code is stopped and the master +% is released. +% \end{enumerate} + +\subsubsection{Master Requesting and Releasing} + +Before an application can access an EtherCAT master provided by the +master module, it has to reserve one for exclusive use. After use, it +has to release the requested master and make it available for other +modules. This is done with the following functions: + +\begin{lstlisting}[gobble=2,language=C] + ec_master_t *ecrt_request_master(unsigned int master_index); + void ecrt_release_master(ec_master_t *master); +\end{lstlisting} + +The \textit{ecrt\_request\_master()} function has to be the first function a +module has to call, when using EtherCAT. The function takes the index of the +master as its argument. The first master has index 0, the $n$th master has +index $n - 1$. The number of existent masters has to be specified when loading +the master module (see section~\ref{sec:mastermod}). The function tries to +reserve the specified master and scans for slaves. It returns a pointer to the +reserved master object upon success, or \textit{NULL} if an error occurred. + +The \textit{ecrt\_release\_master()} function releases a reserved +master after use. It takes the pointer to the master object returned +by \textit{ecrt\_request\_master()} as its argument and can never +fail. + +\subsubsection{Master Methods} +\label{sec:ecrt-master} + +\paragraph{Domain Creation} + +For process data exchange, at least one process data domain is needed +(see section~\ref{sec:processdata}). + +\begin{lstlisting}[gobble=2,language=C] + ec_domain_t *ecrt_master_create_domain(ec_master_t *master); +\end{lstlisting} + +The \textit{ecrt\_master\_create\_domain()} method creates a new +process data domain and returns a pointer to the new domain object. +This object can be used for registering process data objects and +exchange process data in cyclic operation. On failure, the function +returns \textit{NULL}. + +\paragraph{Slave Handlers} + +To access a certain slave, there is a method to get a slave handler: + +\begin{lstlisting}[gobble=2,language=C] + ec_slave_t *ecrt_master_get_slave(const ec_master_t *, + const char *); +\end{lstlisting} + +The \textit{ecrt\_master\_get\_slave()} method returns a pointer to a +certain slave object, specified by its ASCII address (see +section~\ref{sec:addr}). If the address is invalid, \textit{NULL} is +returned. + +\paragraph{Master Activation} + +When all domains are created, and all process data objects are +registered, the master can be activated: + +\begin{lstlisting}[gobble=2,language=C] + int ecrt_master_activate(ec_master_t *master); + void ecrt_master_deactivate(ec_master_t *master); +\end{lstlisting} + +By calling the \textit{ecrt\_master\_activate()} method, all slaves +are configured according to the prior method calls and are brought +into OP state. In this case, the method has a return value of 0. +Otherwise (wrong configuration or bus failure) the method returns +non-zero. + +The \textit{ecrt\_master\_deactivate()} method is the counterpart to +the activate call: It brings all slaves back into INIT state again. +This method should be called prior to +\textit{ecrt\_\-master\_\-release()}. + +\paragraph{Locking Callbacks} + +For concurrent master access, the application has to provide a locking +mechanism (see section~\ref{sec:concurr}): + +\begin{lstlisting}[gobble=2,language=C] + void ecrt_master_callbacks(ec_master_t *master, + int (*request_cb)(void *), + void (*release_cb)(void *), + void *cb_data); +\end{lstlisting} + +The ``request lock'' and ``release lock'' callbacks can be set with +the \textit{ecrt\_master\_call\-backs()} method. It takes two function +pointers and a data value as additional arguments. The arbitrary data +value will be passed as argument on every callback. Asynchronous +master access (like EoE processing) is only possible if these +callbacks have been set. + +\paragraph{Preparation of Cyclic Data Exchange} + +Cyclic operation mostly consists of the three steps input, processing and +output. In EtherCAT terms this would mean: Receive datagrams, evaluate process +data and send datagrams. The first cycle differs from this principle, because +no datagrams have been sent yet, so there is nothing to receive. To avoid +having a case differentiation (in terms of an \textit{if} clause), the +following method exists: + +\begin{lstlisting}[gobble=2,language=C] + void ecrt_master_prepare(ec_master_t *master); +\end{lstlisting} + +As a last thing before cyclic operation, a call to the +\textit{ecrt\_master\_prepare()} method should be issued. It makes all +process data domains queue their datagrams and issues a send command, +so that the first receive call in cyclic operation will not fail. + +\paragraph{Frame Sending and Receiving} + +To send all queued datagrams and to later receive the sent datagrams +there are two methods: + +\begin{lstlisting}[gobble=2,language=C] + void ecrt_master_send(ec_master_t *master); + void ecrt_master_receive(ec_master_t *master); +\end{lstlisting} + +The \textit{ecrt\_master\_send()} method takes all datagrams, that +have been queued for transmission, packs them into frames, and passes +them to the network device for sending. + +The \textit{ecrt\_master\_receive()} queries the network device for +received frames (by calling the ISR\index{ISR}), extracts received +datagrams and dispatches the results to the datagram objects in the +queue. Received datagrams, and the ones that timed out, will be +marked, and then dequeued. + +\paragraph{Running the Operation State Machine} + +The master's operation state machine (see section~\ref{sec:fsm-op}) +monitors the bus in cyclic operation and reconfigures slaves, if +necessary. Therefore, the following method should be called +cyclically: + +\begin{lstlisting}[gobble=2,language=C] + void ecrt_master_run(ec_master_t *master); +\end{lstlisting} + +The \textit{ecrt\_master\_run()} method executes the master's +operation state machine step by step. It returns after processing one +state and queuing a datagram. Calling this function is not mandatory, +but highly recommended. + +\paragraph{Master Monitoring} + +It is also highly recommended to evaluate the master's error state. In +this way it is possible to notice lost network links, failed bus +segments, and other issues: + +\begin{lstlisting}[gobble=2,language=C] + int ecrt_master_state(const ec_master_t *master); +\end{lstlisting} + +The \textit{ecrt\_master\_state()} method returns the master's error +state. The following states are defined as part of the realtime +interface: \begin{description} -\item[Orphaned Mode] This mode takes effect, when the master has no - EtherCAT-capable network device connected. No bus communication is - possible, so this mode is not of further interest. -\item[Idle Mode]\index{Idle mode} takes effect when the master is - unused (i.~e. there is no realtime module, that reserved the - master). In this case, the master has the ability to scan the bus by - itsself and generously allow bus access from user space. This mode - is meant for maintenance and visualisation. -\item[Operation Mode]\index{Operation mode} The master is reserved for - exclusive access by a realtime module. In this mode, the master is - adjusted for availability and monitoring. Access from user space is - very restrictive and mostly limited to reading direction. - +\item[EC\_MASTER\_OK] means, that no error has occurred. +\item[EC\_MASTER\_LINK\_ERROR] means, that the network link is + currently down. +\item[EC\_MASTER\_BUS\_ERROR] means, that one or more slaves do not + respond. \end{description} -Figure~\ref{fig:modes} shows the three modes and the possible mode -transitions. +\subsubsection{Domain Methods} +\label{sec:ecrt-domain} + +\paragraph{Pdo Registration} + +To access data of a slave's Pdo in cyclic operation, it is necessary +to make it part of a process data domain: + +\begin{lstlisting}[gobble=2,language=C] + ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain, + const char *address, + uint32_t vendor_id, + uint32_t product_code, + const char *pdo_name + void **data_ptr); + int ecrt_domain_register_pdo_list(ec_domain_t *domain, + const ec_pdo_reg_t *pdos); +\end{lstlisting} + +The \textit{ecrt\_domain\_register\_pdo()} method registers a certain +Pdo as part of the domain and takes the address of the process data +pointer. This pointer will be set on master activation and then can be +parameter to the \textit{EC\_READ\_*} and \textit{EC\_WRITE\_*} macros +described below. + +A perhaps easier way to register multiple Pdos at the same time is to +fill an array of \textit{ec\_pdo\_reg\_t} and hand it to the +\textit{ecrt\_domain\_register\_pdo\_list()} method. Attention: This +array has to be terminated by an empty structure (\textit{\{\}})! + +\paragraph{Evaluating Domain Data} + +To evaluate domain data, the following method has to be used: + +\begin{lstlisting}[gobble=2,language=C] + void ecrt_domain_process(ec_domain_t *domain); +\end{lstlisting} + +The \textit{ecrt\_domain\_process()} method sets the domains state and +re-queues its datagram for sending. + +\paragraph{Domain State} + +Similar to the master state, a domain has an own error state: + +\begin{lstlisting}[gobble=2,language=C] + int ecrt_domain_state(const ec_domain_t *domain); +\end{lstlisting} + +The \textit{ecrt\_domain\_state()} method returns the domain's error state. It +is non-zero if \textbf{not} all process data values could be exchanged, and +zero otherwise. + +\subsubsection{Slave Methods} +\label{sec:ecrt-slave} + +\paragraph{Sdo Configuration} + +To configure slave Sdos, the function interface below can be used: + +\begin{lstlisting}[gobble=2,language=C] + int ecrt_slave_conf_sdo8(ec_slave_t *slave, + uint16_t sdo_index, + uint8_t sdo_subindex, + uint8_t value); + int ecrt_slave_conf_sdo16(ec_slave_t *slave, + uint16_t sdo_index, + uint8_t sdo_subindex, + uint16_t value); + int ecrt_slave_conf_sdo32(ec_slave_t *slave, + uint16_t sdo_index, + uint8_t sdo_subindex, + uint32_t value); +\end{lstlisting} + +The \textit{ecrt\_slave\_conf\_sdo*()} methods prepare the configuration of a +certain Sdo. The index and subindex of the Sdo, and the value have to be +specified. The configuration is done each time, the slave is reconfigured. The +methods only differ in the Sdo's data type. If the configuration could be +prepared, zero is returned. If an error occurred, non-zero is returned. + +\paragraph{Variable-sized Pdos} + +For specifying the size of variable-sized Pdos, the following method +can be used: + +\begin{lstlisting}[gobble=2,language=C] + int ecrt_slave_pdo_size(ec_slave_t *slave, + const char *pdo_name, + size_t size); +\end{lstlisting} + +The \textit{ecrt\_slave\_pdo\_size()} method takes the name of the Pdo +and the size. It returns zero on success, otherwise non-zero. + +\subsubsection{Process Data Access} +\label{sec:macros} + +The endianess of the process data could differ from that of the CPU. +Therefore, process data access has to be done by the macros below, +that are also provided by the realtime interface: + +\begin{lstlisting}[gobble=2,language=C] + #define EC_READ_BIT(DATA, POS) + #define EC_WRITE_BIT(DATA, POS, VAL) + + #define EC_READ_U8(DATA) + #define EC_READ_S8(DATA) + #define EC_READ_U16(DATA) + #define EC_READ_S16(DATA) + #define EC_READ_U32(DATA) + #define EC_READ_S32(DATA) + + #define EC_WRITE_U8(DATA, VAL) + #define EC_WRITE_S8(DATA, VAL) + #define EC_WRITE_U16(DATA, VAL) + #define EC_WRITE_S16(DATA, VAL) + #define EC_WRITE_U32(DATA, VAL) + #define EC_WRITE_S32(DATA, VAL) +\end{lstlisting} + +There are macros for bitwise access (\textit{EC\_READ\_BIT()}, +\textit{EC\_WRITE\_BIT()}), and byte-wise access (\textit{EC\_READ\_*()}, +\textit{EC\_WRITE\_*()}). The byte-wise macros carry the data type in their +name. Example: \textit{EC\_WRITE\_S16()} writes a 16 bit signed value to +EtherCAT data. The \textit{DATA} parameter is supposed to be a process data +pointer, as provided at Pdo registration. + +The macros use the kernel's endianess conversion macros, that are +preprocessed to empty macros in case of equal endianess. This is the +definition for the \textit{EC\_\-READ\_\-U16()} macro: + +\begin{lstlisting}[gobble=2,language=C] + #define EC_READ_U16(DATA) \ + ((uint16_t) le16_to_cpup((void *) (DATA))) +\end{lstlisting} + +The \textit{le16\_to\_cpup()} macro converts a little-endian, 16 bit +value to the CPU's architecture and takes a pointer to the input value +as its argument. If the CPU's architecture is little-endian, too (for +example on X86 and compatible), nothing has to be converted. In this +case, the macro is replaced with an empty macro by the preprocessor +and so there is no unneeded function call or case differentiation in +the code. + +For keeping it portable, it is highly recommended to make use of these +macros. + +%------------------------------------------------------------------------------ + +\subsection{Slave Addressing} +\label{sec:addr} +\index{Slave!Addressing} + +The master offers the several slave addressing schemes (for Pdo +registration or configuration) via the realtime interface. For this +reason, slave addresses are ASCII\nomenclature{ASCII}{American + Standard Code for Information Interchange}-coded and passed as a +string. The addressing schemes are independent of the EtherCAT +protocol and represent an additional feature of the master. + +Below, the allowed addressing schemes are described. The descriptions +are followed by a regular expression formally defining the addressing +scheme, and one or more examples. + +\begin{description} + +\item[Position Addressing] This is the normal addressing scheme, where each +slave is addressed by its ring position. The first slave has address 0, and the +$n$th slave has address $n - 1$. This addressing scheme is useful for small +buses that have a fixed number of slaves. + +RegEx: \texttt{[0-9]+} --- Example: \texttt{"42"} + +\item[Advanced Position Addressing] Bus couplers segment the bus into +(physical) blocks. Though the logical ring positions keep being the same, it is +easier to address a slave with its block number and the relative position +inside the block. This addressing is done by passing the (zero-based) index of +the bus coupler (not the coupler's ring position), followed by a colon and the +relative position of the actual slave starting at the bus coupler. + +RegEx: \texttt{[0-9]+:[0-9]+} --- Examples: \texttt{"0:42"}, \texttt{"2:7"} + +\item[Alias Addressing] Each slave can have a ``secondary slave address'' or +``alias address''\footnote{Information about how to set the alias can be found +in section~\ref{sec:eepromaccess}} stored in its E$^2$PROM. The alias is +evaluated by the master and can be used to address the slave, which is useful +when a clearly defined slave has to be addressed and the ring position is not +known or can change over time. This scheme is used by starting the address +string with a mesh (\#) followed by the alias address. The latter can also be +provided as hexadecimal value, prefixed with \textit{0x}. + +RegEx: \texttt{\#(0x[0-9A-F]+|[0-9]+)} --- Examples: \texttt{"\#6622"}, +\texttt{"\#0xBEEF"} + +\item[Advanced Alias Addressing] This is a mixture of the ``Alias Addressing'' +and ``Advanced Position Addressing'' schemes. A certain slave is addressed by +specifying its relative position after an aliased slave. This is very useful, +if a complete block of slaves can vary its position in the bus. The bus coupler +preceding the block should get an alias. The block slaves can then be addressed +by specifying this alias and their position inside the block. This scheme is +used by starting the address string with a mesh (\#) followed by the alias +address (which can be hexadecimal), then a colon and the relative position of +the slave to address. + +RegEx: \texttt{\#(0x[0-9A-F]+|[0-9]+):[0-9]+} --- Examples: +\texttt{"\#0xBEEF:7"}, \texttt{"\#6:2"} + +\end{description} + +In anticipation of section~\ref{sec:ecrt}, the functions accepting +these address strings are \textit{ecrt\_\-master\_\-get\_slave()}, +\textit{ecrt\_domain\_register\_pdo()} and +\textit{ecrt\_domain\_register\_pdo\_list()} (the latter through the +\textit{ec\_pdo\_reg\_t} structure). + +%------------------------------------------------------------------------------ + +\subsection{Concurrent Master Access} +\label{sec:concurr} +\index{Concurrency} + +In some cases, one master is used by several instances, for example when an +application does cyclic process data exchange, and there are EoE-capable slaves +that require to exchange Ethernet data with the kernel (see +section~\ref{sec:eoeimp}). For this reason, the master is a shared resource, +and access to it has to be sequentialized. This is usually done by locking with +semaphores, or other methods to protect critical sections. + +The master itself can not provide locking mechanisms, because it has no chance +to know the appropriate kind of lock. Imagine, the application uses RTAI +functionality, then ordinary kernel semaphores would not be sufficient. For +that, an important design decision was made: The application that reserved a +master must have the total control, therefore it has to take responsibility for +providing the appropriate locking mechanisms. If another instance wants to +access the master, it has to request the master lock by callbacks, that have to +be set by the application. Moreover the application can deny access to the +master if it considers it to be awkward at the moment. \begin{figure}[htbp] \centering - \includegraphics[width=.9\textwidth]{images/modes} - \caption{Master modes and transitions} - \label{fig:modes} + \includegraphics[width=.6\textwidth]{images/master-locks} + \caption{Concurrent master access} + \label{fig:locks} \end{figure} -\subsubsection{Idle Mode} -\index{Idle mode} - -The master enters idle mode upon connection of a device module (see -section~\ref{sec:device}) or releasing by a realtime module. The -master owns a kernel workqueue and a suitable work structure, which is -used to cyclically process the ``Idle state machine'' (see -section~\ref{sec:fsm-idle}). This state machine automatically scans -the bus for slaves (and re-scans upon topology changes), configures -slaves for idle operation and executes pending operations from the -user space interface (for example E$^2$PROM writing). On device -disconnection or realtime request, the idle mode is stopped by -cancelling the work and flushing the workqueue. - -\subsubsection{Operation Mode} -\index{Operation mode} - -Operation mode is entered when a realtime module requests the master. -The idle mode is stopped and the bus is scanned by getting the number -of slaves and executing the ``Slave scan state machine'' (see -section~\ref{sec:fsm-scan}) for each slave. The master is now ready to -create domains and accept Pdo registrations and slave configurations. -After that, cyclic communication can be done by the realtime module. - -\paragraph{Master Phases} - -Every realtime module should use the master in three phases: - -\begin{enumerate} -\item \textit{Startup} - The master is requested and the bus is - validated. Domains are created and Pdos are registered. Slave - configurations are applied. -\item \textit{Operation} - Cyclic code is run, process data is - exchanged and the master state machine is executed. -\item \textit{Shutdown} - Cyclic code is stopped and the master - is released. -\end{enumerate} - -%------------------------------------------------------------------------------ - -\section{Device Modules} -\label{sec:device} -\index{Device modules} - -Device modules are network device driver modules that handle Ethernet -devices, which the master can use to connect to an EtherCAT bus. +Figure~\ref{fig:locks} exemplary shows, how two processes share one master: The +application's cyclic task uses the master for process data exchange, while the +master-internal EoE process uses it to communicate with EoE-capable slaves. +Both have to acquire the master lock before access: The application task can +access the lock natively, while the EoE process has to use the callbacks. +Section~\ref{sec:concurrency} gives an example, of how to implement this. + +%------------------------------------------------------------------------------ + +\chapter{Ethernet devices} +\label{sec:devices} + +The EtherCAT protocol is based on the Ethernet standard. That's why the master +relies on standard Ethernet hardware to communicate with the bus. + +The term \textit{device} is used as a synonym for Ethernet network interface +hardware. There are device driver modules that handle Ethernet hardware, which +the master can use to connect to an EtherCAT bus. Section~\ref{sec:networkdrivers} offers an overview of general Linux network driver modules, while section~\ref{sec:requirements} will show @@ -507,7 +1055,7 @@ %------------------------------------------------------------------------------ -\subsection{Network Driver Basics} +\section{Network Driver Basics} \label{sec:networkdrivers} \index{Network drivers} @@ -542,7 +1090,7 @@ \index{Interrupt} A network device usually provides a hardware interrupt that is used to -notify the driver of received frames and success of transmittion, or +notify the driver of received frames and success of transmission, or errors, respectively. The driver has to register an interrupt service routine (ISR\index{ISR}\nomenclature{ISR}{Interrupt Service Routine}), that is executed each time, the hardware signals such an event. If the @@ -560,7 +1108,7 @@ interface''. In case of an Ethernet driver, this interface appears as \textit{ethX}, where X is a number assigned by the kernel on registration. The \textit{net\_device} structure receives events -(either from user space or from the network stack) via serveral +(either from user space or from the network stack) via several callbacks, which have to be set before registration. Not every callback is mandatory, but for reasonable operation the ones below are needed in any case: @@ -581,7 +1129,7 @@ \item[struct net\_device\_stats *(*get\_stats)(struct net\_device *)] This call has to return a pointer to the device's \textit{net\_device\_stats} structure, which permanently has to be - filled with frame statistics. This means, that everytime a frame is + filled with frame statistics. This means, that every time a frame is received, sent, or an error happened, the appropriate counter in this structure has to be increased. \end{description} @@ -592,27 +1140,23 @@ \paragraph{The netif Interface} \index{netif} -All other communication in the direction interface $\to$ network stack -is done via the \textit{netif\_*} calls. For example, on successful -device opening, the network stack has to be notified, that it can now -pass frames to the interface. This is done by calling -\textit{netif\_start\_queue()}. After this call, the -\textit{hard\_start\_xmit()} callback can be called by the network -stack. Furthermore a network driver usually manages a frame -transmission queue. If this gets filled up, the network stack has to -be told to stop passing further frames for a while. This happens with -a call to \textit{netif\_stop\_queue()}. If some frames have been -sent, and there is enough space again to queue new frames, this can be -notified with \textit{netif\_wake\_queue()}. Another important call is -\textit{netif\_receive\_skb()}\footnote{This function is part of the - NAPI (``New API''), that replaces the ``old'' kernel 2.4 technique - for interfacing to the network stack (with \textit{netif\_rx()}). - NAPI is a technique to improve network performance on Linux. Read - more in - http://www.cyberus.ca/\textasciitilde{}hadi/usenix-paper.tgz}: It -passes a frame to the network stack, that was just received by the -device. Frame data has to be packed into a so-called ``socket -buffer'' for that (see below). +All other communication in the direction interface $\to$ network stack is done +via the \textit{netif\_*} calls. For example, on successful device opening, the +network stack has to be notified, that it can now pass frames to the interface. +This is done by calling \textit{netif\_start\_queue()}. After this call, the +\textit{hard\_start\_xmit()} callback can be called by the network stack. +Furthermore a network driver usually manages a frame transmission queue. If +this gets filled up, the network stack has to be told to stop passing further +frames for a while. This happens with a call to \textit{netif\_stop\_queue()}. +If some frames have been sent, and there is enough space again to queue new +frames, this can be notified with \textit{netif\_wake\_queue()}. Another +important call is \textit{netif\_receive\_skb()}\footnote{This function is part +of the NAPI (``New API''), that replaces the ``old'' kernel 2.4 technique for +interfacing to the network stack (with \textit{netif\_rx()}). NAPI is a +technique to improve network performance on Linux. Read more in +\url{http://www.cyberus.ca/~hadi/usenix-paper.tgz}}: It passes a frame to the +network stack, that was just received by the device. Frame data has to be +packed into a so-called ``socket buffer'' for that (see below). \paragraph{Socket Buffers} \index{Socket buffer} @@ -620,7 +1164,7 @@ Socket buffers are the basic data type for the whole network stack. They serve as containers for network data and are able to quickly add data headers and footers, or strip them off again. Therefore a socket -buffer consists of an allocated buffer and serveral pointers that mark +buffer consists of an allocated buffer and several pointers that mark beginning of the buffer (\textit{head}), beginning of data (\textit{data}), end of data (\textit{tail}) and end of buffer (\textit{end}). In addition, a socket buffer holds network header @@ -636,7 +1180,7 @@ %------------------------------------------------------------------------------ -\subsection{EtherCAT Network Drivers} +\section{EtherCAT Device Drivers} \label{sec:requirements} There are a few requirements for Ethernet network devices to function @@ -661,7 +1205,7 @@ frames. Figure~\ref{fig:interrupt} shows two workflows for cyclic frame -transmittion and reception with and without interrupts. +transmission and reception with and without interrupts. \begin{figure}[htbp] \centering @@ -689,10 +1233,10 @@ The interrupt-less operation is desirable, because there is simply no need for an interrupt. Moreover hardware interrupts are not conducive -in improving the driver's realtime behaviour: Their undeterministic +in improving the driver's realtime behaviour: Their indeterministic incidences contribute to increasing the jitter. Besides, if a realtime extension (like RTAI) is used, some additional effort would have to be -made to priorize interrupts. +made to prioritize interrupts. \paragraph{Ethernet and EtherCAT Devices} @@ -726,14 +1270,14 @@ \item The modified driver gets more complicated, as it must handle EtherCAT and non-EtherCAT devices. \item Many additional case differentiations in the driver code. -\item Changes and bugfixes on the standard drivers have to be ported +\item Changes and bug fixes on the standard drivers have to be ported to the Ether\-CAT-capable versions from time to time. \end{itemize} %------------------------------------------------------------------------------ -\subsection{Device Selection} -\label{sec:seldev} +\section{Device Selection} +\label{sec:deviceselection} After loading the master module, at least one EtherCAT-capable network driver module has to be loaded, that connects one of its devices to @@ -754,7 +1298,7 @@ driver, telling it to handle the second device as an EtherCAT device and connecting it to the first master: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] # `\textbf{modprobe ec\_8139too ec\_device\_index=1}` \end{lstlisting} @@ -764,7 +1308,7 @@ %------------------------------------------------------------------------------ -\subsection{The Device Interface} +\section{The Device Interface} \label{sec:ecdev} \index{Device interface} @@ -786,7 +1330,7 @@ A network device driver can connect a physical device to an EtherCAT master with the \textit{ecdev\_register()} function. -\begin{lstlisting}[language=C] +\begin{lstlisting}[gobble=2,language=C] ec_device_t *ecdev_register(unsigned int master_index, struct net_device *net_dev, ec_isr_t isr, @@ -808,48 +1352,44 @@ Therefore the device module has to store this pointer for future use. In error case, the \textit{ecdev\_register()} returns \textit{NULL}, which means that the device could not be registered. The reason for -this is printed to \textit{syslog}\index{syslog}. In this case, the +this is printed to \textit{Syslog}\index{Syslog}. In this case, the device module is supposed to abort the module initialisation and let the \textit{insmod} command fail. \paragraph{Implicit Dependencies} -The reason for the module pointer has to be specified at device -registration is a non-trivial one: The master has to know about the -module, because there will be an implicit dependency between the -device module and a later connected realtime module: When a realtime -module connects to the master, the use count of the master module will -be increased, so that the master module can not be unloaded for the -time of the connection. This is reasonable, and so automatically done -by the kernel. The kernel knows about this dependency, because the -realtime module uses kernel symbols provided by the master module. -Moreover it is mandatory, that the device module can be unloaded -neither, because it is implicitely used by the realtime module, too. -Unloading it would lead to a fatal situation, because the master would -have no device to send and receive frames for the realtime module. -This dependency can not be detected automatically, because the -realtime module does not use any symbols of the device module. -Therefore the master explicitly increments the use counter of the -connected device module upon connection of a realtime module and -decrements it, if the realtime module disconnects. In this manner, it -is impossible to unload a device module while the master is in use. -This is done with the kernel function pair \textit{try\_module\_get()} -\index{try\_module\_get@\textit{try\_module\_get()}} and -\textit{module\_put()} \index{module\_put@\textit{module\_put()}}. The -first one increases the use count of a module and only fails, if the -module is currenly being unloaded. The last one decreases the use -count again and never fails. Both functions take a pointer to the -module as their argument, which the device module therefore has to -specify upon device registration. +The reason for the module pointer has to be specified at device registration is +a non-trivial one: The master has to know about the module, because there will +be an implicit dependency between the device module and a later connected +application module: When an application module connects to the master, the use +count of the master module will be increased, so that the master module can not +be unloaded for the time of the connection. This is reasonable, and so +automatically done by the kernel. The kernel knows about this dependency, +because the application module uses kernel symbols provided by the master +module. Moreover it is mandatory, that the device module can be unloaded +neither, because it is implicitly used by the application module, too. +Unloading it would lead to a fatal situation, because the master would have no +device to send and receive frames for the application. This dependency can not +be detected automatically, because the application module does not use any +symbols of the device module. Therefore the master explicitly increments the +use counter of the connected device module upon connection of an application +and decrements it, if it disconnects again. In this manner, it is impossible to +unload a device module while the master is in use. This is done with the kernel +function pair \textit{try\_module\_get()} +\index{try\_module\_get@\textit{try\_module\_get()}} and \textit{module\_put()} +\index{module\_put@\textit{module\_put()}}. The first one increases the use +count of a module and only fails, if the module is currently being unloaded. +The last one decreases the use count again and never fails. Both functions take +a pointer to the module as their argument, which the device module therefore +has to specify upon device registration. \paragraph{Device Unregistering} -The unregistration of a device is usually done in the device module's -cleanup function, by calling the \textit{ecdev\_unregister()} function -and specifying the master index and a pointer to the device object -again. - -\begin{lstlisting}[language=C] +The deregistration of a device is usually done in the device module's cleanup +function, by calling the \textit{ecdev\_unregister()} function and specifying +the master index and a pointer to the device object again. + +\begin{lstlisting}[gobble=2,language=C] void ecdev_unregister(unsigned int master_index, ec_device_t *device); \end{lstlisting} @@ -866,7 +1406,7 @@ receive frames, the master has to be notified about this by calling the \textit{ecdev\_start()} function. -\begin{lstlisting}[language=C] +\begin{lstlisting}[gobble=2,language=C] int ecdev_start(unsigned int master_index); \end{lstlisting} @@ -886,7 +1426,7 @@ messages of EoE slaves and leave ``Idle Mode''. The only parameter is \textit{master\_index}. This function can not fail. -\begin{lstlisting}[language=C] +\begin{lstlisting}[gobble=2,language=C] void ecdev_stop(unsigned int master_index); \end{lstlisting} @@ -902,7 +1442,7 @@ \textit{ecdev\_receive()} function to forward the received data to the connected EtherCAT master instead. -\begin{lstlisting}[language=C] +\begin{lstlisting}[gobble=2,language=C] void ecdev_receive(ec_device_t *device, const void *data, size_t size); @@ -918,14 +1458,13 @@ \paragraph{Handling the Link Status} -Information about the link status (i.~e. if there is a carrier signal -detected on the physical port) is also important to the master. This -information is usually gathered by the ISR and should be forwarded to -the master by calling the \textit{ecdev\_link\_state()} function. The -master then can react on this and warn the realtime module of a lost -link. - -\begin{lstlisting}[language=C] +Information about the link status (i.~e. if there is a carrier signal detected +on the physical port) is also important to the master. This information is +usually gathered by the ISR and should be forwarded to the master by calling +the \textit{ecdev\_link\_state()} function. The master then can react on this +and warn the application of a lost link. + +\begin{lstlisting}[gobble=2,language=C] void ecdev_link_state(ec_device_t *device, uint8_t new_state); \end{lstlisting} @@ -937,7 +1476,7 @@ %------------------------------------------------------------------------------ -\subsection{Patching Network Drivers} +\section{Patching Network Drivers} \label{sec:patching} \index{Network drivers} @@ -981,7 +1520,7 @@ First of all, there have to be additional global variables declared, as shown in the listing: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] static int ec_device_index = -1; static int ec_device_master_index = 0; static ec_device_t *rtl_ec_dev; @@ -989,17 +1528,17 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 1} -- \textcircled{\tiny 2}] To +\item[\linenum{1} -- \linenum{2}] To comply to the requirements for parameters of EtherCAT device modules described in section~\ref{sec:seldev}, there have to be additional parameter variables: \textit{ec\_\-device\_\-index} holds the index of the EtherCAT device and defaults to $-1$ (no EtherCAT device), while \textit{ec\_device\_master\_index} stores index of the master, the single device will be connected to. Default: $0$ -\item[\normalfont\textcircled{\tiny 3}] \textit{rtl\_ec\_dev} will be +\item[\linenum{3}] \textit{rtl\_ec\_dev} will be the pointer to the later registered RealTek EtherCAT device, which can be used as a parameter for device methods. -\item[\normalfont\textcircled{\tiny 4}] \textit{rtl\_ec\_net\_dev} is +\item[\linenum{4}] \textit{rtl\_ec\_net\_dev} is a pointer to the \textit{net\_device} structure of the dedicated device and is set while scanning the PCI bus and finding the device with the specified index. This is done inside the @@ -1012,7 +1551,7 @@ Below is the (shortened) coding of the device driver's module init function: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] static int __init rtl8139_init_module(void) { if (pci_module_init(&rtl8139_pci_driver) < 0) { @@ -1057,20 +1596,20 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 3}] This call initializes all +\item[\linenum{3}] This call initializes all RTL8139-compatible devices found on the pci bus. If a device with index \textit{ec\_device\_index} is found, a pointer to its \textit{net\_device} structure is stored in \textit{rtl\_ec\_net\_dev} for later use (see next listings). -\item[\normalfont\textcircled{\tiny 8}] If the specified device was +\item[\linenum{8}] If the specified device was found, \textit{rtl\_ec\_net\_dev} is non-zero. -\item[\normalfont\textcircled{\tiny 11}] The device is connected to +\item[\linenum{11}] The device is connected to the specified master with a call to \textit{ecdev\_register()}. If this fails, module loading is aborted. -\item[\normalfont\textcircled{\tiny 23}] The device registration was +\item[\linenum{23}] The device registration was successful and the master is started. This can fail, which aborts module loading. -\item[\normalfont\textcircled{\tiny 29}] If no EtherCAT device was +\item[\linenum{29}] If no EtherCAT device was found, a warning is output. \end{description} @@ -1080,7 +1619,7 @@ increased for each RTL8139-compatible device found. The code below is executed for each device: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] if (board_idx == ec_device_index) { rtl_ec_net_dev = dev; strcpy(dev->name, "ec0"); @@ -1088,7 +1627,7 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 1}] The device with the specified +\item[\linenum{1}] The device with the specified index will be the EtherCAT device. \end{description} @@ -1098,7 +1637,7 @@ registered. This has to be avoided for EtherCAT devices and so this is a typical example for an EtherCAT case differentiation: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] if (dev != rtl_ec_net_dev) { i = register_netdev(dev); if (i) goto err_out; @@ -1106,7 +1645,7 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 1}] If the current net\_device is +\item[\linenum{1}] If the current net\_device is not the EtherCAT device, it is registered at the network stack. \end{description} @@ -1117,7 +1656,7 @@ if-clauses, because interrupt operation is not wanted for EtherCAT devices. -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] if (dev != rtl_ec_net_dev) { retval = request_irq(dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); @@ -1125,7 +1664,7 @@ } \end{lstlisting} -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] if (dev != rtl_ec_net_dev) { /* Enable all known interrupts by setting the interrupt mask. */ @@ -1135,10 +1674,10 @@ \paragraph{Frame Sending} -The listing below shows an exerpt of the function representing the +The listing below shows an excerpt of the function representing the \textit{hard\_start\_xmit()} callback of the net\_device. -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] /* Note: the chip doesn't have auto-pad! */ if (likely(len < TX_BUF_SIZE)) { if (len < ETH_ZLEN) @@ -1157,7 +1696,7 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 6} + \textcircled{\tiny 10}] The +\item[\linenum{6} + \linenum{10}] The master uses a fixed socket buffer for transmission, which is reused and may not be freed. \end{description} @@ -1167,7 +1706,7 @@ During ordinary frame reception, a socket buffer is created and filled with the received data. This is not necessary for an EtherCAT device: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] if (dev != rtl_ec_net_dev) { /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ @@ -1204,11 +1743,11 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 28}] If the device is an EtherCAT +\item[\linenum{28}] If the device is an EtherCAT device, no socket buffer is allocated. Instead a pointer to the data (which is still in the device's receive ring) is passed to the EtherCAT master. Unnecessary copy operations are avoided. -\item[\normalfont\textcircled{\tiny 30} -- \textcircled{\tiny 32}] The +\item[\linenum{30} -- \linenum{32}] The device's statistics are updated as usual. \end{description} @@ -1219,7 +1758,7 @@ below shows the different processing for Ethernet and EtherCAT devices: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] if (dev != rtl_ec_net_dev) { if (tp->phys[0] >= 0) { mii_check_media(&tp->mii, netif_msg_link(tp), @@ -1234,11 +1773,11 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 3}] The ``media check'' is done +\item[\linenum{3}] The ``media check'' is done via the media independent interface (MII\nomenclature{MII}{Media Independent Interface}), a standard interface for Fast Ethernet devices. -\item[\normalfont\textcircled{\tiny 7} -- \textcircled{\tiny 10}] For +\item[\linenum{7} -- \linenum{10}] For EtherCAT devices, the link state is fetched manually from the appropriate device register, and passed to the EtherCAT master by calling \textit{ecdev\_\-link\_\-state()}. @@ -1248,7 +1787,7 @@ Below is the module's cleanup function: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] static void __exit rtl8139_cleanup_module (void) { printk(KERN_INFO "Cleaning up RTL8139-EtherCAT" @@ -1271,1283 +1810,46 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 6}] Stopping and unregistration is - only done, if a device was registered before. -\item[\normalfont\textcircled{\tiny 8}] The master is first stopped, - so it does not access the device any more. -\item[\normalfont\textcircled{\tiny 10}] After this, the device is - unregistered. The master is now ``ophaned''. + +\item[\linenum{6}] Stopping and deregistration is only done, if a device was +registered before. + +\item[\linenum{8}] The master is first stopped, so it does not access the +device any more. + +\item[\linenum{10}] After this, the device is unregistered. The master is now +``orphaned''. + \end{description} %------------------------------------------------------------------------------ -\section{The Master Module} -\label{sec:mastermod} -\index{Master module} - -The EtherCAT master is designed to run as a kernel module. Moreover -the master kernel module \textit{ec\_master} can handle multiple -masters at the same time: The number of masters has to be passed to -the module with the parameter \textit{ec\_master\_count}, that -defaults to $1$. A certain master can later be addressed by its index. -For example, if the master module has been loaded with the command - -\begin{lstlisting} - # `\textbf{modprobe ec\_master ec\_master\_count=2}` -\end{lstlisting} - -the two masters can be addressed by their indices 0 and 1 respectively -(see figure~\ref{fig:masters}). This master index mandatory for -certain functions of the master interfaces. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.5\textwidth]{images/masters} - \caption{Multiple masters in one module} - \label{fig:masters} -\end{figure} - -\paragraph{Master Log Messages} - -The master module gives information about it's state and events via -the syslog interface. The module loading command above should result -in the syslog messages below (or similar): - -\begin{lstlisting} - EtherCAT: Master driver, 1.1 (stable) - rev. 513, - compiled by fp at Aug 09 2006 09:43:50 - EtherCAT: Initializing 2 EtherCAT master(s)... - EtherCAT: Initializing master 0. - EtherCAT: Initializing master 1. - EtherCAT: Master driver initialized. -\end{lstlisting} - -The master provides information about it's version number, subversion -revision number and compile information, like the date of compilation -and the user, who compiled. All messages are prefixed either with -\texttt{EtherCAT:}, \texttt{EtherCAT WARNING:} or \texttt{EtherCAT - ERROR:}, which makes searching the logs easier. - -%------------------------------------------------------------------------------ - -\subsection{Class Reference} -\label{sec:classes} - -This section is not intended to be a complete reference of master -classes and functions\footnote{The comprehensive master reference can - be obtained at http://etherlab.org/download/download-en.html}, but -will give a general survey of the master's classes, and how they -interact. - -Figure~\ref{fig:uml-all} shows an UML class diagram of the master -classes. - -\begin{figure}[htbp] - \centering - \includegraphics[width=\textwidth]{images/uml-all} - \caption{UML class diagram with associations} - \label{fig:uml-all} -\end{figure} - -The following subsections introduce serveral classes with their -attributes and methods. - -%------------------------------------------------------------------------------ - -\subsubsection{The Master Class} -\label{sec:class-master} -\index{Master!Class} - -Figure~\ref{fig:uml-master} shows an UML class diagram of the master -class. There is a short explanation of the attributes and methods -below. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.8\textwidth]{images/uml-master} - \caption{Master UML class diagram} - \label{fig:uml-master} -\end{figure} - -\paragraph{Master Attributes} - -\begin{description} -\item[list] is a listhead structure that is needed to manage the list - of masters in the master module (see section~\ref{sec:mastermod}). -\item[reserved] is a flag, that marks the master as reserved for a - realtime module, so that a call to \textit{ecrt\_request\_master()} - fails, if another module is already using the master. -\item[index] contains the number of the master. The first master will - get index 0, the second index 1, and so on. -\item[kobj] In order to make the master object available via Sysfs - (see section~\ref{sec:sysfs}), this structure is needed inside the - master object (see section~\ref{sec:sysfs}). -\item[slaves] is the list of slaves. It consists of objects of the - \textit{ec\_slave\_t} class (see section~\ref{sec:class-slave}). -\item[slave\_count] is the number of slaves in the list. -\item[device] points to the network device that is used by the master - to send and receive frames (see section~\ref{sec:class-device}). It - is \textit{NULL}, if no device is connected. -\item[datagram\_queue] is a list of datagrams (see - section~\ref{sec:class-datagram}) that have to be sent by the - master, or have already been sent and wait to be received again. - Upon reception or error, the datagrams are dequeued. -\item[datagram\_index] contains the index value for the next datagram. - The master stores this incrementing index into every datagram, to - make it easier to assign a received datagram to the one sent before. -\item[domains] contains the list of domains created by the realtime - module (section~\ref{sec:class-domain}). -\item[debug\_level] controls, how much debugging output is printed by - the master: 0 means no debugging output, 1 means to output certain - executing marks and actions, and 2 means to output frame contents in - addition. This value can be changed at runtime via the Sysfs - interface (see section~\ref{sec:sysfs}). -\item[stats] is a statistics object that contains certain counters - (like the number of missed frames). These statistics are output on - demand, but at most once a second. -\item[workqueue] is the kernel workqueue used for idle mode. -\item[idle\_work] is the work object, that is queued. -\item[fsm] The attribute \textit{fsm} represents the master's finite - state machine, that does all the slave processing. See - sections~\ref{sec:class-fsm} and~\ref{sec:fsm} for further details. -\item[mode] contains the current master mode, if it is orphaned, idle, - or in operation mode. -\item[eoe\_timer] is the kernel timer used for EoE\index{EoE} - processing. -\item[eoe\_running] marks the state of EoE processing. -\item[eoe\_handlers] is the list of EoE handlers (see - section~\ref{sec:class-eoe}). -\item[internal\_lock] is a spinlock used in idle mode, that controls - the concurrency of the idle and EoE processes. -\item[request\_cb] The ``request lock'' callback function, the master - has to provide for foreign instances, which want to access the - master (see section~\ref{sec:concurr}). -\item[release\_cb] The callback function that will release the master - lock. -\item[cb\_data] This value will be passed as an argument to each - callback. -\item[eeprom\_write\_enable] flag can be written via Sysfs to enable - the general writing of E$^2$PROM contents. -\end{description} - -\paragraph{Public Master Methods} - -\begin{description} -\item[ec\_master\_init()] is the master's constructor. It initializes - all attributes, creates the workqueue, creates EoE handlers and the - state machine object, and adds the kernel object to the Sysfs - hierarchy. -\item[ec\_master\_clear()] is the destructor and undoes all these - actions. -\item[ec\_master\_reset()] clears the master, but initializes it - again. This is needed, when a realtime module disconnects: Slaves - and other attributes are cleared and are later rebuilt by the idle - process. -\item[ec\_master\_idle\_start/stop()] These methods enable or disable - the idle process. -\item[ec\_master\_eoe\_start/stop()] These methods do the same for the - EoE timer. -\item[ec\_master\_receive\_datagrams()] This method is called by the - device, which uses it to pass received frames to the master. The - frame is dissected and the contained datagrams are assigned to the - datagram objects in the datagram queue, which are dequeued on - reception or error. -\item[ec\_master\_queue\_datagram()] This method is used to queue a - new datagram for sending and receiving. -\item[ec\_master\_output\_stats()] This method is cyclically called to - output a summary of the \textit{stats} attribute at most once a - second. -\item[ec\_master\_clear\_slaves()] clears the list of slaves. This is - needed on connection/disconnection of a realtime module or at a - topology change in idle mode, when all slaves objects are rebuilt. -\end{description} - -\paragraph{Private Master Methods} - -A few of a master's methods are private, meaning, that they can only -be called from other master methods: - -\begin{description} -\item[ec\_master\_send\_datagrams()] searches the datagram queue for - unsent datagrams, allocates frames to send them, does the actual - sending and marks the datagrams as sent. -\item[ec\_master\_idle\_run()] is the work function for the idle mode. - It executes the idle state machine, described in - section~\ref{sec:fsm-idle}. -\item[ec\_master\_eoe\_run()] is called by the EoE timer and is - responsible for communicating with EoE-capable slaves. See - section~\ref{sec:eoeimp} for more information. -\end{description} - -\paragraph{Master Methods (Realtime Interface)} - -The master methods belonging to the Eth\-er\-CAT realtime -interface\index{ecrt@\textit{ecrt}}\nomenclature{ecrt}{EtherCAT - Realtime Interface} begin with the prefix \textit{ecrt} instead of -\textit{ec}. The functions of the realtime interface are explained in -section~\ref{sec:ecrt-master}. - -%------------------------------------------------------------------------------ - -\subsubsection{The Slave Class} -\label{sec:class-slave} -\index{Slave!Class} - -Figure~\ref{fig:uml-slave} shows an UML class diagram of the slave -class. There is a short explanation of the attributes and methods -below. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.8\textwidth]{images/uml-slave} - \caption{Slave UML class diagram} - \label{fig:uml-slave} -\end{figure} - -\paragraph{Slave Attributes} - -\begin{description} -\item[list] The master holds a slave list, therefore the slave class - must contain this structure used as an anchor for the linked - list. -\item[kobj] This pointer serves as base object for the slave's Sysfs - representation. -\item[master] is the pointer to the master owning this slave object. -\item[ring\_position] is the logical position in the logical ring - topology. -\item[station\_address] is the configured station address. This is - always the ring position~+~$1$). -\item[coupler\_index] is the index of the last bus coupler. -\item[coupler\_subindex] is the slave's position, counted from the - last bus coupler. See section~\ref{sec:addr} for more information. -\item[base\_*] These attributes contain base information about the - slave, that are read from the ``DL Information'' attribute. -\item[dl\_*] These fields store information of the ``DL Status'' - attribute, for example states of the the communication ports. -\item[sii\_*] These attributes contain values from the ``Slave - Information Interface'' \cite[section~6.4]{dlspec}, mostly identity - and mailbox information, but also the list of sync manager - configurations and Pdos. -\item[registered] This flag is set, if one or more Pdos of the slave - have been registered for process data exchange. Otherwise a warning - is output, because the slave is unused. -\item[fmmus] Is an array of FMMU configurations, that have to be - applied to the slave. -\item[fmmu\_count] contains number of FMMUs used. -\item[eeprom\_*] These fields contain E$^2$PROM contents and the - extracted category information \cite[section~5.4]{alspec}. -\item[new\_eeprom\_data] If this pointer is not \textit{NULL}, it - points to new E$^2$PROM contents, that have to be written to the - slave. -\item[new\_eeprom\_size] This field represents the size of the new - E$^2$PROM data. -\item[requested\_state] is the requested slave state. -\item[current\_state] is the current slave state. -\item[error\_flag] is used by the operation and idle state machines - to indicate, that a state transisition has failed and should not be - tried again until an external event happens. -\item[online] This flag contains the online state of the slave (i.~e. - if it currently responds to the masters commands). Changes of the - online state are always reported. -\item[varsize\_fields] is only suitable for slaves that provide Pdos - of variable size (like slaves that manage a sub-fieldbus) and - contains information about what size this fields actually should - have. -\end{description} - -\paragraph{Public Slave Methods} - -\begin{description} -\item[ec\_slave\_init()] The slave's constructor. -\item[ec\_slave\_clear()] The slave's destructor. -\item[ec\_prepare\_fmmu()] prepares an FMMU configuration. The FMMU is - configured for a certain sync manager and domain. -\item[ec\_fetch\_*()] Serveral methods to extract information of the - E$^2$PROM category contents. -\item[ec\_slave\_locate\_string()] extracts a string out of a STRING - category and allocates string memory. -\item[ec\_slave\_calc\_sync\_size()] calculates the size of sync - manager contents, because they can be variable due to variable-sized - Pdos. -\item[ec\_slave\_info()] This method prints all slave information into - a buffer for Sysfs reading. -\item[ec\_slave\_mbox\_*()] These functions prepare datagrams for - mailbox communication, or process mailbox responses, respectively. -\end{description} - -\paragraph{Private Slave Methods} - -\begin{description} -\item[ec\_slave\_write\_eeprom()] This function accepts E$^2$PROM data - from user space, does a quick validation of the contents and - schedules them for writing through the idle state machine. -\end{description} - -\paragraph{Slave Methods (Realtime Interface)} - -\begin{description} -\item[ecrt\_slave\_conf\_sdo*()] These methods accept Sdo - configurations, that are applied on slave activation (i.~e. - everytime the slave is configured). The methods differ only in the - data size of the Sdo (8, 16 or 32 bit). -\item[ecrt\_slave\_pdo\_size()] This method specifies the size of a - variable-sized Pdo. -\end{description} - -%------------------------------------------------------------------------------ - -\subsubsection{The Device Class} -\label{sec:class-device} -\index{Device!Class} - -The device class is responsible for communicating with the connected -EtherCAT-enabled network driver. Figure~\ref{fig:uml-device} shows its -UML class diagram. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.3\textwidth]{images/uml-device} - \caption{Device UML class diagram} - \label{fig:uml-device} -\end{figure} - -\paragraph{Device Attributes} - -\begin{description} -\item[master] A pointer to the master, which owns the device object. -\item[dev] This is the pointer to the \textit{net\_device} structure - of the connected network device driver. -\item[open] This flag stores, if the network device is ``opened'' and - ready for transmitting and receiving frames. -\item[tx\_skb] The transmittion socket buffer. Instead of allocating a - new socket buffer for each frame, the same socket buffer is recycled - and used for every frame. -\item[isr] The pointer to the network device's interrupt service - routine. \textit{ec\_isr\_t} is a type definition in the device - interface, which looks like below: - \begin{lstlisting}[gobble=4,language=C] - typedef irqreturn_t (*ec_isr_t)(int, void *, - struct pt_regs *); - \end{lstlisting} -\item[module] A pointer to the network driver module, to increase and - decrease the use counter (see paragraph ``Implicit Dependencies'' in - section~\ref{sec:ecdev}). -\item[link\_state] The current link state. It can be 0 ``down'' or 1 - ``up''. -\item[dbg] Every device objects contains a debugging interface (see - sectios~\ref{sec:class-debug} and~\ref{sec:debug}). -\end{description} - -\paragraph{Public Device Methods} - -\begin{description} -\item[ec\_device\_init()] The device constructor. -\item[ec\_device\_clear()] The device destructor. -\item[ec\_device\_open()] ``Opens'' the device for transmittion and - reception of frames. This is equivalent to the \textit{ifconfig up} - command for ordinary Ethernet devices. -\item[ec\_device\_close()] Stops frame transmittion and reception. - This is equivalent to the \textit{ifconfig down} command for - ordinary Ethernet devices. -\item[ec\_device\_call\_isr()] Calls the interrupt service routine of - the device. -\item[ec\_device\_tx\_data()] Returns a pointer into the memory of the - transmittion socket buffer \textit{tx\_skb}. This is used by the - master to assemble a new EtherCAT frame. -\item[ec\_device\_send()] Sends an assembled frame by passing it to - the device's \textit{hard\_\-start\_\-xmit()} callback. -\end{description} - -\paragraph{Device Methods (Device Interface)} - -The device methods belonging to the device interface are explained in -section~\ref{sec:ecdev}. - -%------------------------------------------------------------------------------ - -\subsubsection{The Datagram Class} -\label{sec:class-datagram} -\index{Datagram!Class} - -So send and receive a datagram, an object of the -\textit{ec\_datagram\_t} class is needed. It can be initialized with a -datagram type \cite[section~5.4]{dlspec} and length (optionally filled -with data) and appended to the master's datagram queue. -Figure~\ref{fig:uml-datagram} shows its UML class diagram. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.3\textwidth]{images/uml-datagram} - \caption{Datagram UML class diagram} - \label{fig:uml-datagram} -\end{figure} - -\paragraph{Datagram Attributes} - -\begin{description} -\item[list] This attribute is needed to make a list of datagrams, as - used in the domain class (see section~\ref{sec:class-domain}). -\item[queue] This attribute is the anchor to the master's datagram - queue, which is implemented as a linked list. -\item[type] The datagram type. \textit{ec\_\-datagram\_\-type\_\-t} is - an enumeration, which can have the values - \textit{EC\_\-DATAGRAM\_\-APRD}, \textit{EC\_\-DATAGRAM\_\-APWR}, - \textit{EC\_\-DATAGRAM\_\-NPRD}, \textit{EC\_\-DATAGRAM\_\-NPWR}, - \textit{EC\_\-DATAGRAM\_\-BRD}, \textit{EC\_\-DATAGRAM\_\-BWR} or - \textit{EC\_\-DATAGRAM\_\-LRW}. -\item[address] The slave address. For all addressing schemes take 4 - bytes, \textit{ec\_address\_t} is a union type: - \begin{lstlisting}[gobble=4,language=C] - typedef union { - struct { - uint16_t slave; /**< configured or - autoincrement - address */ - uint16_t mem; /**< physical memory - address */ - } physical; /**< physical address */ - uint32_t logical; /**< logical address */ - } ec_address_t; - \end{lstlisting} -\item[data] The actual data of the datagram. These are either filled - in before sending (at writing access) or are inserted by the - adressed slave(s) (at reading access). In any case, the data memory - must be dynamically allocated. Besides, this can be done before - cyclic processing with the \textit{ec\_datagram\_prealloc()} method - (see below). -\item[mem\_size] The size of the allocated memory, \textit{data} - points to. -\item[data\_size] The size of the actual data in the \textit{data} - memory. -\item[index] The sequential EtherCAT datagram index. This value is set - by the master on sending, to easier assign a received datagram to a - queued datagram object. -\item[working\_counter] The working counter of the datagram. This is - set to zero on sending and filled with the real value of the working - counter on datagram reception. -\item[state] The state of the datagram. - \textit{ec\_\-datagram\_\-state\_\-t} is an enumeration and can be - \textit{EC\_\-DATA\-GRAM\_\-INIT}, - \textit{EC\_\-DATA\-GRAM\_\-QUEU\-ED}, - \textit{EC\_\-DATA\-GR\-AM\_\-SEN\-T}, - \textit{EC\_\-DATA\-GRAM\_\-REC\-EIVED}, - \textit{EC\_\-DATA\-GRAM\_\-TIMED\_\-OUT} or - \textit{EC\_\-DA\-TA\-GRAM\_\-ERR\-OR}. -\item[t\_sent] This attribute is set to the timestamp, when the - datagram was sent, to later detect a timeout. -\end{description} - -\paragraph{Public Datagram Methods} - -\begin{description} -\item[ec\_datagram\_init()] The datagram's constructor. -\item[ec\_datagram\_clear()] The datagram's destructor. -\item[ec\_datagram\_prealloc()] Allocates memory for the datagram - data. This is especially needed, if the datagram structure will - later be used in a context, where no dynamic memory allocation is - allowed. -\item[ec\_datagram\_nprd()] Initializes a ``Node-Addressed Physical - Read'' datagram \cite[section~5.4.1.2]{dlspec}. -\item[ec\_datagram\_npwr()] Initializes a ``Node-Addressed Physical - Write'' datagram \cite[section~5.4.2.2]{dlspec}. -\item[ec\_datagram\_aprd()] Initializes a ``Auto-Increment Physical - Read'' datagram \cite[section~5.4.1.1]{dlspec}. -\item[ec\_datagram\_apwr()] Initializes a ``Auto-Increment Physical - Write'' datagram \cite[section~5.4.2.1]{dlspec}. -\item[ec\_datagram\_brd()] Initializes a ``Broadcast Read'' datagram - \cite[section~5.4.1.3]{dlspec}. -\item[ec\_datagram\_bwr()] Initializes a ``Broadcast Write'' datagram - \cite[section~5.4.2.3]{dlspec}. -\item[ec\_datagram\_lrw()] Initializes a ``Logical ReadWrite'' - datagram \cite[section~5.4.3.4]{dlspec}. -\end{description} - -%------------------------------------------------------------------------------ - -\subsubsection{The Domain Class} -\label{sec:class-domain} -\index{Domain!Class} - -The domain class encapsules Pdo registration and management of the -process data image and its exchange. The UML class diagram can be seen -in figure~\ref{fig:uml-domain}. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.4\textwidth]{images/uml-domain} - \caption{Domain UML class diagram} - \label{fig:uml-domain} -\end{figure} - -\paragraph{Domain Attributes} - -\begin{description} -\item[kobj] This \textit{kobject} structure is needed for the Sysfs - representation of the domain. -\item[list] The master manages a list of domains, so this list anchor - is needed. -\item[index] The domain's index. The first domain will get index 0, - the second index 1, and so on. -\item[master] A pointer to the master owning the domain. -\item[data\_size] The size of the domain's process data image. -\item[datagram] A linked list with the datagram objects, the domain - needs for process data exchange (see - section~\ref{sec:class-datagram}). -\item[base\_address] This attribute stores the logical offset, to - which the domain's process data are mapped. -\item[response\_count] The sum of the datagrams' working counters at - the last process data exchange. Changes are always reported. -\item[data\_regs] The (linked) list of Pdo registrations. The realtime - module requests the exchange of certain Pdos and supplies the - address of process data pointers, that will later point to the - respective locations in the process data image. These ``data - registrations'' are saved in the \textit{data\_regs} list. -\item[working\_counter\_changes] This field stores the number of - working counter changes since the last notification. This helps to - reduce syslog output in case of frequent changes. -\item[t\_last] The timestamp of the last working counter change - notification. -\end{description} - -\paragraph{Public Domain Methods} - -\begin{description} -\item[ec\_domain\_init()] The domain's constructor. -\item[ec\_domain\_clear()] The domain's destructor. -\item[ec\_domain\_alloc()] Allocates the process data image and the - respective datagrams based on the process data registrations. -\item[ec\_domain\_queue()] Queues the domain's datagrams for exchange - via the master. -\end{description} - -\paragraph{Private Domain Methods} - -\begin{description} -\item[ec\_domain\_reg\_pdo\_entry()] This method is used to do a Pdo - registration. It finds the appropriate sync manager covering the Pdo - data, calculates its offset in the sync-manager-protected memory and - prepares the FMMU configurations for the related slave. Then the Pdo - registration is appended to the list. -\item[ec\_domain\_clear\_data\_regs()] Clearing all process data - registrations is needed in serveral places and therefore has been - sourced out to an own method. -\item[ec\_domain\_add\_datagram()] This methods allocates a datagram - and appends it to the list. This is done during domain allocation. -\end{description} - -\paragraph{Domain Methods (Realtime Interface)} - -The domain methods belonging to the realtime interface are introduced -in section~\ref{sec:ecrt-domain}. - -%------------------------------------------------------------------------------ - -\subsubsection{The Finite State Machine Class} -\label{sec:class-fsm} -\index{FSM!Class} - -This class encapsules all state machines, except the EoE state -machine. Its UML class diagram can be seen in -figure~\ref{fig:uml-fsm}. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.9\textwidth]{images/uml-fsm} - \caption{Finite State Machine UML class diagram} - \label{fig:uml-fsm} -\end{figure} - -\paragraph{FSM Attributes} - -\begin{description} -\item[master] A pointer to the master owning the FSM object. -\item[slave] Serveral sub state machines are executed for single - slaves. This pointer stores the current slave for these FSMs. -\item[datagram] The FSM class has its own datagram, which is used in - every state and sub-state. -\item[master\_state] This function pointer stores the current state - function for one of the master's state machines. -\item[master\_slaves\_responding] This attribute is used in the - operation state machine (see section~\ref{sec:fsm-op}) to store the - number of slaves, that responded to the last broadcast command. -\item[master\_slave\_states] This attribute stores the slave states, - that were determined by the last broadcast command. -\item[master\_validation] This flag is used by the operation state - machine and is non-zero, if a bus validation has to be done. -\item[slave\_state] This function pointer stores the current state of - the slave scan state machine (see section~\ref{sec:fsm-scan}) or the - slave configuration state machine (see section~\ref{sec:fsm-conf}). -\item[sii\_state] This function pointer stores the current state of - the SII state machine (see section~\ref{sec:fsm-sii}). -\item[sii\_offset] This attribute is used by the SII state machine to - store the word address for the current read or write cycle. -\item[sii\_mode] If this attribute is zero, the SII access is done - with ``auto-increment'' datagrams \cite[section~5.4]{dlspec}. - If it is non-zero, ``station-address'' datagrams are used. -\item[sii\_value] This attribute stores the value to write, or the - read value, respectively. -\item[sii\_start] A timestamp attribute, that stores the beginning - time of an SII operation to detect a timeout. -\item[change\_state] This function pointer stores the current state of - the state change state machine. -\item[change\_new] This attribute stores the requested state for the - state change state machine. -\item[change\_start] A timestamp attribute to detect a timeout while - changing slave states. -\item[coe\_state] This function pointer stores the current state of - the CoE state machines. -\item[sdodata] This is an Sdo data object that stores information - about the current Sdo to write. -\item[coe\_start] A timestamp attribute to detect timeouts during CoE - configuration. -\end{description} - -\paragraph{Public FSM Methods} - -\begin{description} -\item[ec\_fsm\_init()] Constructor of the FSM class. -\item[ec\_fsm\_clear()] Destructor of the FSM class. -\item[ec\_fsm\_reset()] Resets the whole FSM object. This is needed to - restart the master state machines. -\item[ec\_fsm\_execute()] Executes one state of the current state - machine and then returns. -\item[ec\_fsm\_startup()] Initializes the master startup state - machine, which determines the number of slaves and executes the - slave scan state machine for each slave. -\item[ec\_fsm\_startup\_running()] Returns non-zero, if the startup - state machine did not terminate yet. -\item[ec\_fsm\_startup\_success()] Returns non-zero, if the startup - state machine terminated with success. -\item[ec\_fsm\_configuration()] Initializes the master configuration - state machine, which executes the slave configuration state machine - for each slave. -\item[ec\_fsm\_configuration\_running()] Returns non-zero, if the - configuration state machine did not terminate yet. -\item[ec\_fsm\_configuration\_success()] Returns non-zero, if the - configuration state machine terminated with success. -\end{description} - -\paragraph{FSM State Methods} - -The rest of the methods showed in the UML class diagram are state -methods of the state machines. These states are described in -section~\ref{sec:fsm}. - -%------------------------------------------------------------------------------ - -\subsubsection{The EoE Class} -\label{sec:class-eoe} -\index{EoE!Class} - -Objects of the \textit{ec\_eoe\_t} class are called EoE handlers. Each -EoE handler represents a virtual network interface and can be coupled -to a EoE-capable slave on demand. The UML class diagram can be seen in -figure~\ref{fig:uml-eoe}. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.4\textwidth]{images/uml-eoe} - \caption{EoE UML class diagram} - \label{fig:uml-eoe} -\end{figure} - -\paragraph{EoE Attributes} - -\begin{description} -\item[list] The master class maintains a list of EoE handlers. - Therefore this list anchor is needed. -\item[slave] If an EoE handler is coupled to a slave, this pointer - points to the related slave object. Otherwise it is \textit{NULL}. -\item[datagram] Every EoE handler owns a datagram object to exchange - data with the coupled slave via its state machine. -\item[state] This function pointer points to the current state of the - EoE state machine (see section~\ref{sec:eoeimp}). -\item[dev] A pointer to the \textit{net\_device} structure that - represents the network interface to the kernel. -\item[stats] The statistics object for the network interface. -\item[opened] This flag stores, if the network interface was opened. - No EoE processing will be done, if the device is not opened. -\item[t\_last] This timestamp attribute stores the time of the last - bit rate measurement. -\item[rx\_skb] A pointer to the current receive socket buffer. On - every first fragment of a received frame, a new receive socket - buffer is allocated. On every last fragment, this buffer will be - passed to the network stack. -\item[rx\_skb\_offset] This attribute stores the offset for the next - fragment data in the receive socket buffer. -\item[rx\_skb\_size] This attribute stores the current data size of - the receive socket buffer. -\item[rx\_expected\_fragment] The expected number of the next - fragment. If a fragment with an invalid number is received, the - whole frame will be dropped. -\item[rx\_counter] This is the sum of the octets received since the - last bit rate measurement. -\item[rx\_rate] This attribute stores the receive bit rate in bps. -\item[tx\_queue] Each EoE handler maintains a transmittion queue for - frames, that come in via the network interface. This queue is - implemented with a linked list and protected by a spinlock. -\item[tx\_queue\_active] This flag stores, if the transmittion queue - is currently accepting frames from the network stack. If the queue - gets filled up, frame transmittion is suspended with a call to - \textit{netif\_stop\_queue()}. If the fill state decreases below the - half capacity, frame transmittion is restarted with - \textit{netif\_wake\_queue()}. -\item[tx\_queued\_frames] The number of frames in the transmittion - queue. -\item[tx\_queue\_lock] The spinlock used to protect the transmittion - queue. This is needed, because the queue is accessed both from - network stack context and from the master's EoE timer. -\item[tx\_frame] The frame that is currently sent. The - \textit{ec\_eoe\_frame\_t} structure combines the socket buffer - structure with a list head to append it to the transmittion queue. -\item[tx\_frame\_number] The EoE protocol demands to maintain a - sequencial frame number, that must be increased with every frame - sent. -\item[tx\_fragment\_number] The sequencial number of the next fragment - to transmit. -\item[tx\_offset] Current frame data offset for the next fragment to - transmit. -\item[tx\_counter] The number of octets transferred since the last bit - rate measurement. -\item[tx\_rate] The recent transmittion bit rate in bps. -\end{description} - -\paragraph{Public EoE Methods} - -\begin{description} -\item[ec\_eoe\_init()] The EoE handler's constructor. The network - interface is allocated and registered. -\item[ec\_eoe\_clear()] The EoE handler's destructor. The network - interface is unregistered and all allocated memory is freed. -\item[ec\_eoe\_run()] Executes the EoE state machine (see - section~\ref{sec:eoeimp}) for this handler. -\item[ec\_eoe\_active()] Returns true, if the handler has a slave - coupled and the network interface is opened. -\end{description} - -\paragraph{Private EoE Methods} - -\begin{description} -\item[ec\_eoe\_flush()] Clears the transmittion queue and drops all - frames queued for sending. -\item[ec\_eoe\_send()] Sends one fragment of the current frame. -\end{description} - - -\paragraph{EoE State Methods} - -The rest of the private methods are state functions for the EoE state -machine, which is discussed in section~\ref{sec:eoeimp}. - -%------------------------------------------------------------------------------ - -\subsubsection{The Debug Class} -\label{sec:class-debug} - -The debug class maintains a virtual network interface. All frames that -are sent and received by the master will be forwarded to this network -interface, so that bus monitoring can be done with third party tools -(see section~\ref{sec:debug}). Figure~\ref{fig:uml-debug} shows the -UML class diagram. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.3\textwidth]{images/uml-debug} - \caption{Debug UML class diagram} - \label{fig:uml-debug} -\end{figure} - -\paragraph{Debug Attributes} - -\begin{description} -\item[dev] A pointer to the allocated \textit{net\_device} structure - that represents the network interface in the kernel. -\item[stats] An object for interface statistics. -\item[opened] Stores the state of the device. Frames will only be - forwarded, if the device was opened with the \textit{ifconfig up} - command (or something similar). -\end{description} - -\paragraph{Public Debug Methods} - -\begin{description} -\item[ec\_debug\_init()] The constructor. -\item[ec\_debug\_clear()] The destructor. -\item[ec\_debug\_send()] This method forwards a frame to the virtual - network interface. It dynamically allocates a new socket buffer and - passes it to the network stack. -\end{description} - -%------------------------------------------------------------------------------ - -\subsection{The Realtime Interface} -\label{sec:ecrt} -\index{Realtime interface} - -The realtime interface provides functions and data structures for -realtime modules to access and use an EtherCAT master. - -\subsubsection{Master Requesting and Releasing} - -Before a realtime module can access am EtherCAT master provided by the -master module, it has to reserve one for exclusive use. After use, it -has to release the requested master and make it available for other -modules. This is done with the following functions: - -\begin{lstlisting}[language=C] - ec_master_t *ecrt_request_master(unsigned int master_index); - void ecrt_release_master(ec_master_t *master); -\end{lstlisting} - -The \textit{ecrt\_request\_master()} function has to be the first -function a module has to call, when using EtherCAT. The function takes -the index of the master as its argument. The first master has index 0, -the $n$th master has index $n - 1$. The number of existent masters has -to be specified when loading the master module (see -section~\ref{sec:mastermod}). The function tries to reserve the -specified master and scans for slaves. It returns a pointer to the -reserved master object upon success, or \textit{NULL} if an error -occured. - -The \textit{ecrt\_release\_master()} function releases a reserved -master after use. It takes the pointer to the master object returned -by \textit{ecrt\_request\_master()} as its argument and can never -fail. - -\subsubsection{Master Methods} -\label{sec:ecrt-master} - -\paragraph{Domain Creation} - -For process data exchange, at least one process data domain is needed -(see section~\ref{sec:processdata}). - -\begin{lstlisting}[language=C] - ec_domain_t *ecrt_master_create_domain(ec_master_t *master); -\end{lstlisting} - -The \textit{ecrt\_master\_create\_domain()} method creates a new -process data domain and returns a pointer to the new domain object. -This object can be used for registering process data objects and -exchange process data in cyclic operation. On failure, the function -returns \textit{NULL}. - -\paragraph{Slave Handlers} - -To access a certain slave, there is a method to get a slave handler: - -\begin{lstlisting}[language=C] - ec_slave_t *ecrt_master_get_slave(const ec_master_t *, - const char *); -\end{lstlisting} - -The \textit{ecrt\_master\_get\_slave()} method returns a pointer to a -certain slave object, specified by its ASCII address (see -section~\ref{sec:addr}). If the address is invalid, \textit{NULL} is -returned. - -\paragraph{Master Activation} - -When all domains are created, and all process data objects are -registered, the master can be activated: - -\begin{lstlisting}[language=C] - int ecrt_master_activate(ec_master_t *master); - void ecrt_master_deactivate(ec_master_t *master); -\end{lstlisting} - -By calling the \textit{ecrt\_master\_activate()} method, all slaves -are configured according to the prior method calls and are brought -into OP state. In this case, the method has a return value of 0. -Otherwise (wrong configuration or bus failure) the method returns -non-zero. - -The \textit{ecrt\_master\_deactivate()} method is the counterpart to -the activate call: It brings all slaves back into INIT state again. -This method should be called prior to -\textit{ecrt\_\-master\_\-release()}. - -\paragraph{Locking Callbacks} - -For concurrent master access, the realtime module has to provide a -locking mechanism (see section~\ref{sec:concurr}): - -\begin{lstlisting}[language=C] - void ecrt_master_callbacks(ec_master_t *master, - int (*request_cb)(void *), - void (*release_cb)(void *), - void *cb_data); -\end{lstlisting} - -The ``request lock'' and ``release lock'' callbacks can be set with -the \textit{ecrt\_master\_call\-backs()} method. It takes two function -pointers and a data value as additional arguments. The arbitrary data -value will be passed as argument on every callback. Asynchronous -master access (like EoE processing) is only possible if these -callbacks have been set. - -\paragraph{Preparation of Cyclic Data Exchange} - -Cyclic operation mostly consists of the three steps input, processing -and output. In EtherCAT terms this would mean: Receive datagrams, -evaluate process data and send datagrams. The first cycle differs from -this principle, because no datagrams have been sent yet, so there is -nothing to receive. To avoid having a case differantiation (in terms -of an \textit{if} clause), the following method exists: - -\begin{lstlisting}[language=C] - void ecrt_master_prepare(ec_master_t *master); -\end{lstlisting} - -As a last thing before cyclic operation, a call to the -\textit{ecrt\_master\_prepare()} method should be issued. It makes all -process data domains queue their datagrams and issues a send command, -so that the first receive call in cyclic operation will not fail. - -\paragraph{Frame Sending and Receiving} - -To send all queued datagrams and to later receive the sent datagrams -there are two methods: - -\begin{lstlisting}[language=C] - void ecrt_master_send(ec_master_t *master); - void ecrt_master_receive(ec_master_t *master); -\end{lstlisting} - -The \textit{ecrt\_master\_send()} method takes all datagrams, that -have been queued for transmission, packs them into frames, and passes -them to the network device for sending. - -The \textit{ecrt\_master\_receive()} queries the network device for -received frames (by calling the ISR\index{ISR}), extracts received -datagrams and dispatches the results to the datagram objects in the -queue. Received datagrams, and the ones that timed out, will be -marked, and then dequeued. - -\paragraph{Running the Operation State Machine} - -The master's operation state machine (see section~\ref{sec:fsm-op}) -monitors the bus in cyclic operation and reconfigures slaves, if -necessary. Therefore, the following method should be called -cyclically: - -\begin{lstlisting}[language=C] - void ecrt_master_run(ec_master_t *master); -\end{lstlisting} - -The \textit{ecrt\_master\_run()} method executes the master's -operation state machine step by step. It returns after processing one -state and queuing a datagram. Calling this function is not mandatory, -but highly recommended. - -\paragraph{Master Monitoring} - -It is also highly recommended to evaluate the master's error state. In -this way it is possible to notice lost network links, failed bus -segments, and other issues: - -\begin{lstlisting}[language=C] - int ecrt_master_state(const ec_master_t *master); -\end{lstlisting} - -The \textit{ecrt\_master\_state()} method returns the master's error -state. The following states are defined as part of the realtime -interface: - -\begin{description} -\item[EC\_MASTER\_OK] means, that no error has occurred. -\item[EC\_MASTER\_LINK\_ERROR] means, that the network link is - currently down. -\item[EC\_MASTER\_BUS\_ERROR] means, that one or more slaves do not - respond. -\end{description} - -\subsubsection{Domain Methods} -\label{sec:ecrt-domain} - -\paragraph{Pdo Registration} - -To access data of a slave's Pdo in cyclic operation, it is necessary -to make it part of a process data domain: - -\begin{lstlisting}[language=C] - ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain, - const char *address, - uint32_t vendor_id, - uint32_t product_code, - const char *pdo_name - void **data_ptr); - int ecrt_domain_register_pdo_list(ec_domain_t *domain, - const ec_pdo_reg_t *pdos); -\end{lstlisting} - -The \textit{ecrt\_domain\_register\_pdo()} method registers a certain -Pdo as part of the domain and takes the address of the process data -pointer. This pointer will be set on master activation and then can be -parameter to the \textit{EC\_READ\_*} and \textit{EC\_WRITE\_*} macros -described below. - -A perhaps easier way to register multiple Pdos at the same time is to -fill an array of \textit{ec\_pdo\_reg\_t} and hand it to the -\textit{ecrt\_domain\_register\_pdo\_list()} method. Attention: This -array has to be terminated by an empty structure (\textit{\{\}})! - -\paragraph{Evaluating Domain Data} - -To evaluate domain data, the following method has to be used: - -\begin{lstlisting}[language=C] - void ecrt_domain_process(ec_domain_t *domain); -\end{lstlisting} - -The \textit{ecrt\_domain\_process()} method sets the domains state and -requeues its datagram for sending. - -\paragraph{Domain State} - -Similar to the master state, a domain has an own error state: - -\begin{lstlisting}[language=C] - int ecrt_domain_state(const ec_domain_t *domain); -\end{lstlisting} - -The \textit{ecrt\_domain\_state()} method returns the domain's error -state. It is non-zero if \underline{not} all process data values could -be exchanged, and zero otherwise. - -\subsubsection{Slave Methods} -\label{sec:ecrt-slave} - -\paragraph{Sdo Configuration} - -To configure slave Sdos, the function interface below can be used: - -\begin{lstlisting}[language=C] - int ecrt_slave_conf_sdo8(ec_slave_t *slave, - uint16_t sdo_index, - uint8_t sdo_subindex, - uint8_t value); - int ecrt_slave_conf_sdo16(ec_slave_t *slave, - uint16_t sdo_index, - uint8_t sdo_subindex, - uint16_t value); - int ecrt_slave_conf_sdo32(ec_slave_t *slave, - uint16_t sdo_index, - uint8_t sdo_subindex, - uint32_t value); -\end{lstlisting} - -The \textit{ecrt\_slave\_conf\_sdo*()} methods prepare the -configuration of a certain Sdo. The index and subindex of the Sdo, and -the value have to be specified. The configuration is done each time, -the slave is reconfigured. The methods only differ in the Sdo's data -type. If the configuration could be prepared, zero is returned. If an -error occured, non-zero is returned. - -\paragraph{Variable-sized Pdos} - -For specifying the size of variable-sized Pdos, the following method -can be used: - -\begin{lstlisting}[language=C] - int ecrt_slave_pdo_size(ec_slave_t *slave, - const char *pdo_name, - size_t size); -\end{lstlisting} - -The \textit{ecrt\_slave\_pdo\_size()} method takes the name of the Pdo -and the size. It returns zero on success, otherwise non-zero. - -\subsubsection{Process Data Access} -\label{sec:macros} - -The endianess of the process data could differ from that of the CPU. -Therefore, process data access has to be done by the macros below, -that are also provided by the realtime interface: - -\begin{lstlisting}[language=C] - #define EC_READ_BIT(DATA, POS) - #define EC_WRITE_BIT(DATA, POS, VAL) - - #define EC_READ_U8(DATA) - #define EC_READ_S8(DATA) - #define EC_READ_U16(DATA) - #define EC_READ_S16(DATA) - #define EC_READ_U32(DATA) - #define EC_READ_S32(DATA) - - #define EC_WRITE_U8(DATA, VAL) - #define EC_WRITE_S8(DATA, VAL) - #define EC_WRITE_U16(DATA, VAL) - #define EC_WRITE_S16(DATA, VAL) - #define EC_WRITE_U32(DATA, VAL) - #define EC_WRITE_S32(DATA, VAL) -\end{lstlisting} - -There are macros for bitwise access (\textit{EC\_READ\_BIT()}, -\textit{EC\_WRITE\_BIT()}), and bytewise access -(\textit{EC\_READ\_*()}, \textit{EC\_WRITE\_*()}). The bytewise macros -carry the data type in their name. Example: \textit{EC\_WRITE\_S16()} -writes a 16 bit signed value to EtherCAT data. The \textit{DATA} -parameter is supposed to be a process data pointer, as provided at Pdo -registration. - -The macros use the kernel's endianess conversion macros, that are -preprocessed to empty macros in case of equal endianess. This is the -definition for the \textit{EC\_\-READ\_\-U16()} macro: - -\begin{lstlisting}[language=C] - #define EC_READ_U16(DATA) \ - ((uint16_t) le16_to_cpup((void *) (DATA))) -\end{lstlisting} - -The \textit{le16\_to\_cpup()} macro converts a little-endian, 16 bit -value to the CPU's architecture and takes a pointer to the input value -as its argument. If the CPU's architecture is little-endian, too (for -example on X86 and compatible), nothing has to be converted. In this -case, the macro is replaced with an empty macro by the preprocessor -and so there is no unneeded function call or case differentiation in -the code. - -For keeping it portable, it is highly recommended to make use of these -macros. - -%------------------------------------------------------------------------------ - -\subsection{Slave Addressing} -\label{sec:addr} -\index{Slave!Addressing} - -The master offers the serveral slave addressing schemes (for Pdo -registration or configuration) via the realtime interface. For this -reason, slave addresses are ASCII\nomenclature{ASCII}{American - Standard Code for Information Interchange}-coded and passed as a -string. The addressing schemes are independent of the EtherCAT -protocol and represent an additional feature of the master. - -Below, the allowed addressing schemes are described. The descriptions -are followed by a regular expression formally defining the addressing -scheme, and one or more examples. - -\begin{description} -\item[Position Addressing] This is the normal addressing scheme, where - each slave is addressed by its ring position. The first slave has - address 0, and the $n$th slave has address $n - 1$. This addressing - scheme is useful for small busses that have a fixed number of slaves.\\ - RegEx: \texttt{[0-9]+} --- Example: \texttt{"42"} -\item[Advanced Position Addressing] Bus couplers segment the bus into - (physical) blocks. Though the logical ring positions keep being the - same, it is easier to address a slave with its block number and the - relative position inside the block. This addressing is done by - passing the (zero-based) index of the bus coupler (not the coupler's - ring position), followed by a colon and the relative position of the - actual slave starting at the bus coupler.\\ - RegEx: \texttt{[0-9]+:[0-9]+} --- Examples: \texttt{"0:42"}, - \texttt{"2:7"} -\item[Alias Addressing] Each slave can have a ``secondary slave - address'' or ``alias address''\footnote{Information about how to set - the alias can be found in section~\ref{sec:eepromaccess}} stored - in its E$^2$PROM. The alias is evaluated by the master and can be - used to address the slave, which is useful when a clearly defined - slave has to be addressed and the ring position is not known or can - change over time. This scheme is used by starting the address string - with a mesh (\#) followed by the alias address. The latter can also - be provided as hexadecimal value, prefixed with \textit{0x}.\\ - RegEx: \texttt{\#(0x[0-9A-F]+|[0-9]+)} --- Examples: - \texttt{"\#6622"}, \texttt{"\#0xBEEF"} -\item[Advanced Alias Addressing] This is a mixture of the ``Alias - Addressing'' and ``Advanced Position Addressing'' schemes. A certain - slave is addressed by specifying its relative position after an - aliased slave. This is very useful, if a complete block of slaves - can vary its position in the bus. The bus coupler preceeding the - block should get an alias. The block slaves can then be addressed by - specifying this alias and their position inside the block. This - scheme is used by starting the address string with a mesh (\#) - followed by the alias address (which can be hexadecimal), then a - colon and the relative posision of the slave to - address.\\ - RegEx: \texttt{\#(0x[0-9A-F]+|[0-9]+):[0-9]+} --- Examples: - \texttt{"\#0xBEEF:7"}, \texttt{"\#6:2"} -\end{description} - -In anticipation of section~\ref{sec:ecrt}, the functions accepting -these address strings are \textit{ecrt\_\-master\_\-get\_slave()}, -\textit{ecrt\_domain\_register\_pdo()} and -\textit{ecrt\_domain\_register\_pdo\_list()} (the latter through the -\textit{ec\_pdo\_reg\_t} structure). - -%------------------------------------------------------------------------------ - -\subsection{Concurrent Master Access} -\label{sec:concurr} -\index{Concurrency} - -In some cases, one master is used by serveral instances, for example -when a realtime module does cyclic process data exchange, and there -are EoE-capable slaves that require to exchange Ethernet data with the -kernel (see section~\ref{sec:eoeimp}). For this reason, the master is -a shared resource, and access to it has to be sequenctialized. This is -usually done by locking with semaphores, or other methods to protect -critical sections. - -The master itself can not provide locking mechanisms, because it has -no chance to know the appropriate kind of lock. Imagine, the realtime -module uses RTAI functionality, then ordinary kernel semaphores would -not be sufficient. For that, an important design decision was made: -The realtime module that reserved a master must have the total -control, therefore it has to take responsibility for providing the -appropriate locking mechanisms. If another instance wants to access -the master, it has to request the master lock by callbacks, that have -to be set by the realtime module. Moreover the realtime module can -deny access to the master if it consideres it to be awkward at the -moment. - -\begin{figure}[htbp] - \centering - \includegraphics[width=.6\textwidth]{images/master-locks} - \caption{Concurrent master access} - \label{fig:locks} -\end{figure} - -Figure~\ref{fig:locks} exemplary shows, how two processes share one -master: The realtime module's cyclic thread uses the master for -process data exchange, while the master-internal EoE process uses it -to communicate with EoE-capable slaves. Both have to aquire the master -lock before access: The realtime thread can access the lock natively, -while the EoE process has to use the master callbacks. -Section~\ref{sec:concurrency} gives an example, of how to implement -this. - -%------------------------------------------------------------------------------ - -\section{The Master's State Machines} +\chapter{State Machines} \label{sec:fsm} \index{FSM} -Many parts of the EtherCAT master are implemented as \textit{finite - state machines} (FSMs\nomenclature{FSM}{Finite State Machine}). -Though this leads to a higher grade of complexity in some aspects, is -opens many new possibilities. +Many parts of the EtherCAT master are implemented as \textit{finite state +machines} (FSMs\nomenclature{FSM}{Finite State Machine}). Though this leads +to a higher grade of complexity in some aspects, is opens many new +possibilities. The below short code example exemplary shows how to read all slave states and moreover illustrates the restrictions of ``sequential'' coding: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] ec_datagram_brd(datagram, 0x0130, 2); // prepare datagram if (ec_master_simple_io(master, datagram)) return -1; slave_states = EC_READ_U8(datagram->data); // process datagram \end{lstlisting} -The \textit{ec\_master\_simple\_io()} function provides a simple -interface for synchronously sending a single datagram and receiving -the result\footnote{For all communication issues have been meanwhile - sourced out into state machines, the function is deprecated and - stopped existing. Nevertheless it is adequate for showing it's own - restrictions.}. Internally, it queues the specified datagram, -invokes the \textit{ec\_master\_send\_datagrams()} function to send a -frame with the queued datagram and then waits actively for its -reception. +The \textit{ec\_master\_simple\_io()} function provides a simple interface for +synchronously sending a single datagram and receiving the result\footnote{For +all communication issues have been meanwhile sourced out into state machines, +the function is deprecated and stopped existing. Nevertheless it is adequate +for showing it's own restrictions.}. Internally, it queues the specified +datagram, invokes the \textit{ec\_master\_send\_datagrams()} function to send +a frame with the queued datagram and then waits actively for its reception. This sequential approach is very simple, reflecting in only three lines of code. The disadvantage is, that the master is blocked for the @@ -2580,7 +1882,7 @@ while the listings below show the basic approach by coding the example from above as a state machine: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] // state 1 ec_datagram_brd(datagram, 0x0130, 2); // prepare datagram ec_master_queue(master, datagram); // queue datagram @@ -2592,7 +1894,7 @@ datagrams, these are sent and received. Then the respective next states are executed: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] // state 2 if (datagram->state != EC_DGRAM_STATE_RECEIVED) { next_state = state_error; @@ -2607,7 +1909,7 @@ %------------------------------------------------------------------------------ -\subsection{State Machine Theory} +\section{State Machine Theory} \label{sec:fsmtheory} \index{FSM!Theory} @@ -2690,19 +1992,18 @@ \paragraph{Misunderstandings about state machines} -There is a phenomenon called ``state explosion'', that is oftenly -taken as a counter-argument against general use of state machines in -complex environments. It has to be mentioned, that this point is -misleading~\cite{fsmmis}. State explosions happen usually as a result -of a bad state machine design: Common mistakes are storing the present -values of all inputs in a state, or not dividing a complex state -machine into simpler sub state machines. The EtherCAT master uses -serveral state machines, that are executed hierarchically and so serve -as sub state machines. These are also described below. - -%------------------------------------------------------------------------------ - -\subsection{The Master's State Model} +There is a phenomenon called ``state explosion'', that is often taken as a +counter-argument against general use of state machines in complex environments. +It has to be mentioned, that this point is misleading~\cite{fsmmis}. State +explosions happen usually as a result of a bad state machine design: Common +mistakes are storing the present values of all inputs in a state, or not +dividing a complex state machine into simpler sub state machines. The EtherCAT +master uses several state machines, that are executed hierarchically and so +serve as sub state machines. These are also described below. + +%------------------------------------------------------------------------------ + +\section{The Master's State Model} \label{sec:statemodel} This section will introduce the techniques used in the master to @@ -2714,7 +2015,7 @@ code. An obvious way is to implement the different states and actions by one big case differentiation: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] enum {STATE_1, STATE_2, STATE_3}; int state = STATE_1; @@ -2746,7 +2047,7 @@ function and to store the current state function with a function pointer: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] void (*state)(void *) = state1; void state_machine_run(void *priv_data) { @@ -2770,13 +2071,12 @@ } \end{lstlisting} -In the master code, state pointers of all state machines\footnote{All - except for the EoE state machine, because multiple EoE slaves have - to be handled in parallel. For this reason each EoE handler object - has its own state pointer.} are gathered in a single object of the -\textit{ec\_fsm\_t} class. This is advantageous, because there is -always one instance of every state machine available and can be -started on demand. +In the master code, state pointers of all state machines\footnote{All except +for the EoE state machine, because multiple EoE slaves have to be handled in +parallel. For this reason each EoE handler object has its own state pointer.} +are gathered in a single object of the \textit{ec\_fsm\_t} class. This is +advantageous, because there is always one instance of every state machine +available and can be started on demand. \paragraph{Mealy and Moore} @@ -2787,7 +2087,7 @@ model offers a higher flexibility, which can be seen in the listing below: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] void state7(void *priv_data) { if (some_condition) { action_7a(); @@ -2801,7 +2101,7 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 3} + \textcircled{\tiny 7}] The +\item[\linenum{3} + \linenum{7}] The state function executes the actions depending on the state transition, that is about to be done. \end{description} @@ -2810,7 +2110,7 @@ on the state, followed by some actions dependent on the state transition: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] void state9(void *priv_data) { action_9(); if (some_condition) { @@ -2829,13 +2129,12 @@ \paragraph{Using Sub State Machines} -To avoid having too much states, certain functions of the EtherCAT -master state machine have been sourced out into sub state machines. -This helps to encapsule the related workflows and moreover avoids the -``state explosion'' phenomenon described in -section~\ref{sec:fsmtheory}. If the master would instead use one big -state machine, the number of states would be a multiple of the actual -number. This would increase the level of complexity to a +To avoid having too much states, certain functions of the EtherCAT master state +machine have been sourced out into sub state machines. This helps to +encapsulate the related workflows and moreover avoids the ``state explosion'' +phenomenon described in section~\ref{sec:fsmtheory}. If the master would +instead use one big state machine, the number of states would be a multiple of +the actual number. This would increase the level of complexity to a non-manageable grade. \paragraph{Executing Sub State Machines} @@ -2845,7 +2144,7 @@ usually done like in the listing below, which is taken out of the slave configuration state machine code: -\begin{lstlisting}[language=C,numbers=left] +\begin{lstlisting}[gobble=2,language=C,numbers=left] void ec_fsm_slaveconf_safeop(ec_fsm_t *fsm) { fsm->change_state(fsm); // execute state change @@ -2863,12 +2162,12 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 3}] \textit{change\_state} is the +\item[\linenum{3}] \textit{change\_state} is the state pointer of the state change state machine. The state function, the pointer points on, is executed\ldots -\item[\normalfont\textcircled{\tiny 6}] \ldots either until the state +\item[\linenum{6}] \ldots either until the state machine terminates with the error state \ldots -\item[\normalfont\textcircled{\tiny 11}] \ldots or until the state +\item[\linenum{11}] \ldots or until the state machine terminates in the end state. Until then, the ``higher'' state machine remains in the current state and executes the sub state machine again in the next cycle. @@ -2886,7 +2185,7 @@ %------------------------------------------------------------------------------ -\subsection{The Operation State Machine} +\section{The Operation State Machine} \label{sec:fsm-op} \index{FSM!Operation} @@ -2910,21 +2209,20 @@ broadcast. In this way, all slave states and the number of slaves responding can be determined. $\rightarrow$~BROADCAST -\item[BROADCAST] The broadcast datagram is evaluated. A change in the - number of responding slaves is treates as a topology change. If the - number of slaves is not as expected, the bus is marked as - ``tainted''. In this state, no slave reconfiguration is possible, - because the assignment of known slaves and those present on the bus - is ambiguous. If the number of slaves is considered as right, the - bus is marked for validation, because it turned from tainted to - normal state and it has to be checked, if all slaves are valid. Now, - the state of every single slave has to be determined. For that, a - (unicast) datagram is issued, that queries the first slave's ``AL - Control Response'' attribute. $\rightarrow$~READ STATES - -\item[READ STATES] If the current slave did not respond to its - configured station address, it is marked as offline, and the next - slave is queried. $\rightarrow$~READ STATES +\item[BROADCAST] The broadcast datagram is evaluated. A change in the number of +responding slaves is treated as a topology change. If the number of slaves is +not as expected, the bus is marked as ``tainted''. In this state, no slave +reconfiguration is possible, because the assignment of known slaves and those +present on the bus is ambiguous. If the number of slaves is considered as +right, the bus is marked for validation, because it turned from tainted to +normal state and it has to be checked, if all slaves are valid. Now, the state +of every single slave has to be determined. For that, a (unicast) datagram is +issued, that queries the first slave's ``AL Control Response'' attribute. +$\rightarrow$~READ STATES + +\item[READ STATES] If the current slave did not respond to its configured +station address, it is marked as offline, and the next slave is queried. +$\rightarrow$~READ STATES If the slave responded, it is marked as online and its current state is stored. The next slave is queried. $\rightarrow$~READ STATES @@ -2981,15 +2279,14 @@ %------------------------------------------------------------------------------ -\subsection{The Idle State Machine} +\section{The Idle State Machine} \label{sec:fsm-idle} \index{FSM!Idle} -The Idle state machine is executed by a kernel workqueue, if no -realtime module is connected. Its purpose is to make slave information -available to user space, operate EoE-capable slaves, read and write -E$^2$PROM contents and test slave functionality. -Figure~\ref{fig:fsm-idle} shows its transition diagram. +The Idle state machine is executed by a kernel thread, if no application is +connected. Its purpose is to make slave information available to user space, +operate EoE-capable slaves, read and write SII contents and test slave +functionality. Figure~\ref{fig:fsm-idle} shows its transition diagram. \begin{figure}[htbp] \centering @@ -3073,7 +2370,7 @@ %------------------------------------------------------------------------------ -\subsection{The Slave Scan State Machine} +\section{The Slave Scan State Machine} \label{sec:fsm-scan} \index{FSM!Slave Scan} @@ -3154,7 +2451,7 @@ %------------------------------------------------------------------------------ -\subsection{The Slave Configuration State Machine} +\section{The Slave Configuration State Machine} \label{sec:fsm-conf} \index{FSM!Slave Configuration} @@ -3261,7 +2558,7 @@ %------------------------------------------------------------------------------ -\subsection{The State Change State Machine} +\section{The State Change State Machine} \label{sec:fsm-change} \index{FSM!State Change} @@ -3301,7 +2598,7 @@ querying the \textit{AL Status Code} parameter. $\rightarrow$~CODE -\item[END] If the state machine ends in this state, the slaves's state +\item[END] If the state machine ends in this state, the slave's state change has been successful. \item[CODE] The status code query has been sent. Reading the @@ -3334,7 +2631,7 @@ %------------------------------------------------------------------------------ -\subsection{The SII State Machine} +\section{The SII State Machine} \label{sec:fsm-sii} \index{FSM!SII} @@ -3401,7 +2698,7 @@ %------------------------------------------------------------------------------ -\section{Mailbox Protocol Implementations} +\chapter{Mailbox Protocol Implementations} \index{Mailbox} The EtherCAT master implements the EoE and the CoE mailbox @@ -3409,7 +2706,7 @@ %------------------------------------------------------------------------------ -\subsection{Ethernet-over-EtherCAT (EoE)} +\section{Ethernet-over-EtherCAT (EoE)} \label{sec:eoeimp} \index{EoE} @@ -3444,17 +2741,16 @@ \paragraph{EoE Handlers} -The virtual EoE interfaces and the related functionality is encapsuled -in the \textit{ec\_eoe\_t} class (see section~\ref{sec:class-eoe}). -So the master does not create the network interfaces directly: This is -done inside the constructor of the \textit{ec\_eoe\_t} class. An -object of this class is called ``EoE handler'' below. An EoE handler -additionaly contains a frame queue. Each time, the kernel passes a new -socket buffer for sending via the interface's +The virtual EoE interfaces and the related functionality is encapsulated in the +\textit{ec\_eoe\_t} class (see section~\ref{sec:class-eoe}). So the master +does not create the network interfaces directly: This is done inside the +constructor of the \textit{ec\_eoe\_t} class. An object of this class is called +``EoE handler'' below. An EoE handler additionally contains a frame queue. Each +time, the kernel passes a new socket buffer for sending via the interface's \textit{hard\_start\_xmit()} callback, the socket buffer is queued for -transmittion by the EoE state machine (see below). If the queue gets -filled up, the passing of new socket buffers is suspended with a call -to \textit{netif\_stop\_queue()}. +transmission by the EoE state machine (see below). If the queue gets filled up, +the passing of new socket buffers is suspended with a call to +\textit{netif\_stop\_queue()}. \paragraph{Static Handler Creation} @@ -3463,7 +2759,7 @@ network interfaces is equal to the lifetime of the master module. This approach is opposed to creating the virtual network interfaces on demand (i.~e. on running across a new EoE-capable slave). The latter -approach was considered as difficult, because of serveral reasons: +approach was considered as difficult, because of several reasons: \begin{itemize} \item The \textit{alloc\_netdev()} function can sleep and must be @@ -3489,7 +2785,7 @@ section~\ref{sec:sysconfig}). Upon loading of the master module, the virtual interfaces become available: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] # `\textbf{ifconfig -a}` eoe0 Link encap:Ethernet HWaddr 00:11:22:33:44:06 BROADCAST MULTICAST MTU:1500 Metric:1 @@ -3563,7 +2859,7 @@ fragment. $\rightarrow$~RX\_\-START \item[TX\_START] The beginning state of a transmit sequence. It is - checked, if the transmittion queue contains a frame to send. If not, + checked, if the transmission queue contains a frame to send. If not, a receive sequence is started. $\rightarrow$~RX\_START If there is a frame to send, it is dequeued. If the queue was @@ -3588,15 +2884,17 @@ the following disadvantages: \begin{itemize} -\item Only one EoE fragment can be sent or received every few cycles. - This causes the data rate to be very low, because the EoE state - machines are not executed in the time between the realtime - cycles. Moreover, the data rate would be dependent on the frequency - of the realtime process. -\item The receiving and forwarding of frames to the kernel requires - the dynamic allocation of frames. Some realtime extensions do not - support calling memory allocation functions in realtime context, so - the EoE state machine may not be executed with each realtime cycle. + +\item Only one EoE fragment can be sent or received every few cycles. This +causes the data rate to be very low, because the EoE state machines are not +executed in the time between the application cycles. Moreover, the data rate +would be dependent on the period of the application task. + +\item The receiving and forwarding of frames to the kernel requires the dynamic +allocation of frames. Some realtime extensions do not support calling memory +allocation functions in realtime context, so the EoE state machine may not be +executed with each application cycle. + \end{itemize} To overcome these problems, an own cyclic process is needed to @@ -3607,17 +2905,15 @@ this are introduced in section~\ref{sec:concurr}. Section~\ref{sec:concurrency} gives practical implementation examples. -\paragraph{Idle Mode} - -EoE data must also be exchanged idle mode, to guarantee the continuous -availability of the connection to the EoE-capable slaves. Although -there is no realtime module connected in this case, the master is -still accessed by the idle state machine (see -section~\ref{sec:fsm-idle}), that is executed by the master's -workqueue. With the EoE timer running in addition, there is still -concurrency, that has to be protected by a lock. Therefore the master -owns an internal spinlock that is used protect master access during -idle mode. +\paragraph{Idle phase} + +EoE data must also be exchanged in idle phase, to guarantee the continuous +availability of the connection to the EoE-capable slaves. Although there is no +application connected in this case, the master is still accessed by the master +state machine (see section~\ref{sec:fsm-master}). With the EoE timer running in +addition, there is still concurrency, that has to be protected by a lock. +Therefore the master owns an internal spinlock that is used protect master +access during idle phase. \paragraph{Automatic Configuration} @@ -3629,7 +2925,7 @@ %------------------------------------------------------------------------------ -\subsection{CANopen-over-EtherCAT (CoE)} +\section{CANopen-over-EtherCAT (CoE)} \label{sec:coeimp} \index{CoE} @@ -3639,11 +2935,11 @@ \paragraph{Sdo Configuration} -The Sdo configurations have to be provided by the realtime module. -This is done via the \textit{ecrt\_slave\_conf\_sdo*()} methods (see -section~\ref{sec:ecrt-slave}), that are part of the realtime -interface. The slave stores the Sdo configurations in a linked list, -but does not apply them at once. +The Sdo configurations have to be provided by the application. This is done +via the \textit{ecrt\_slave\_conf\_sdo*()} methods (see +section~\ref{sec:ecrt-slave}), that are part of the realtime interface. The +slave stores the Sdo configurations in a linked list, but does not apply them +at once. \paragraph{Sdo Download State Machine} @@ -3703,12 +2999,12 @@ %------------------------------------------------------------------------------ -\section{User Space} +\chapter{User Space} \label{sec:user} \index{User space} For the master runs as a kernel module, accessing it is natively -limited to analyzing syslog messages and controlling using modutils. +limited to analyzing Syslog messages and controlling using modutils. It is necessary to implement further interfaces, that make it easier to access the master from user space and allow a finer influence. It @@ -3732,7 +3028,7 @@ %------------------------------------------------------------------------------ -\subsection{The Sysfs Interface} +\section{The Sysfs Interface} \label{sec:sysfs} The system filesystem (Sysfs\index{Sysfs}) was introduced with Linux @@ -3741,7 +3037,7 @@ filesystem (Procfs), where over the years much non-process information was concentrated. -Sysfs exports information about devices, classes and busses via a +Sysfs exports information about devices, classes and buses via a virtual filesystem, usually mounted to \textit{/sys}. The EtherCAT master slightly differs from this concept, because the only physical device is the network adapter it uses for bus communication, which is @@ -3768,13 +3064,13 @@ directory. Callback functions have to be provided for reading (and perhaps writing) access. -\subsubsection{Master Attributes} +\subsection{Master Attributes} \label{sec:sysfs-master} Below is a typical listing of the masters Sysfs directory (that is a file system representation of the master's kobject): -\begin{lstlisting} +\begin{lstlisting}[gobble=2] `\$` `\textbf{ls /sys/ethercat0}` debug_level slave000 slave003 slave006 eeprom_write_enable slave001 slave004 slave007 @@ -3786,7 +3082,7 @@ \begin{description} \item[debug\_level] (read/write) This attribute contains the master's debug level, which controls, how much information is printed into - syslog. The values 0 (no additional debug messages), 1 (a few + Syslog. The values 0 (no additional debug messages), 1 (a few additional debug messages) and 2 (all additional debug messages) are defined. Writing is done with command like @@ -3832,7 +3128,7 @@ \textit{domainX}, where X is the domain index. Below is a listing of the domain directory contents: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] `\$` `\textbf{ls /sys/ethercat0/domain0}` image_size \end{lstlisting} @@ -3848,7 +3144,7 @@ \textit{slaveXXX}, where XXX is the slave's 3-digit ring position in the EtherCAT bus. Below is a listing of a slave directory: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] `\$` `\textbf{ls /sys/ethercat0/slave003}` eeprom info state \end{lstlisting} @@ -3930,9 +3226,9 @@ %------------------------------------------------------------------------------ -\subsubsection{E$^2$PROM Access} -\label{sec:eepromaccess} -\index{E$^2$PROM!Access} +\subsection{SII Access} +\label{sec:siiaccess} +\index{SII!Access} It is possible to directly read or write the complete E$^2$PROM contents of the slaves. This was introduced for the reasons below: @@ -3947,11 +3243,11 @@ user space. \end{itemize} -Reading out E$^2$PROM data is as easy as reading other -attributes. Though the data are in binary format, analyzation is -easier with a tool like \textit{hexdump}: - -\begin{lstlisting} +Reading out E$^2$PROM data is as easy as reading other attributes. Though the +data are in binary format, analysis is easier with a tool like +\textit{hexdump}: + +\begin{lstlisting}[gobble=2] `\$` `\textbf{cat /sys/ethercat0/slave003/eeprom | hexdump}` 0000000 0103 0000 0000 0000 0000 0000 0000 008c 0000010 0002 0000 3052 07f0 0000 0000 0000 0000 @@ -3961,7 +3257,7 @@ Backing up E$^2$PROM contents gets as easy as copying a file: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] `\$` `\textbf{cp /sys/ethercat0/slave003/eeprom slave003.eep}` \end{lstlisting} @@ -3973,13 +3269,13 @@ E$^2$PROM writing is enabled with the command below: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] # `\textbf{echo 1 > /sys/ethercat0/eeprom\_write\_enable}` \end{lstlisting} -The success can be seen in the syslog messages again: - -\begin{lstlisting} +The success can be seen in the Syslog messages again: + +\begin{lstlisting}[gobble=2] EtherCAT: Slave EEPROM writing enabled. \end{lstlisting} @@ -3988,13 +3284,13 @@ short validation of the contents, before starting the write operation. This validation checks the complete size and the category headers. -\begin{lstlisting} +\begin{lstlisting}[gobble=2] # `\textbf{cat slave003.eep > /sys/ethercat0/slave003/eeprom}` \end{lstlisting} The write operation can take a few seconds. -\begin{lstlisting} +\begin{lstlisting}[gobble=2] EtherCAT: EEPROM writing scheduled for slave 3, 88 words. EtherCAT: Writing EEPROM of slave 3... EtherCAT: Finished writing EEPROM of slave 3. @@ -4002,14 +3298,14 @@ %------------------------------------------------------------------------------ -\subsection{User Space Tools} +\section{User Space Tools} \index{User space!Tools} There is a user space tool called \textit{lsec}\index{lsec} (``List EtherCAT'') to visualize the EtherCAT bus. Running it usually results in an output like this: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] `\$` `\textbf{lsec}` EtherCAT bus listing for master 0: 0 1:0 OP EK1100 Ethernet Kopplerklemme (2A E-Bus) @@ -4034,7 +3330,7 @@ section~\ref{sec:sysfs-slave}). This is done for master $0$ by default, but the master index can be specified via command line: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] `\$` `\textbf{lsec -h}` Usage: ec_list [OPTIONS] -m Query master . @@ -4049,7 +3345,7 @@ %------------------------------------------------------------------------------ -\subsection{System Integration} +\section{System Integration} \label{sec:system} To integrate the EtherCAT master into a running system, it has to be @@ -4076,7 +3372,7 @@ insert the EtherCAT init script at the correct place in the startup sequence: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] ### BEGIN INIT INFO # Provides: ethercat # Required-Start: $local_fs $syslog $network @@ -4094,13 +3390,13 @@ the EtherCAT master. It has to be executed with one of the parameters \texttt{start}, \texttt{stop}, \texttt{restart} or \texttt{status}. -\begin{lstlisting} +\begin{lstlisting}[gobble=2] # `\textbf{/etc/init.d/ethercat restart}` Shutting down EtherCAT master done Starting EtherCAT master done \end{lstlisting} -\subsubsection{The EtherCAT Sysconfig File} +\subsubsection{Sysconfig} % FIXME \label{sec:sysconfig} \index{Sysconfig file} @@ -4141,21 +3437,22 @@ %------------------------------------------------------------------------------ -\subsection{Monitoring and Debugging} +\section{Monitoring and Debugging} \label{sec:debug} \index{Monitoring} -For debugging purposes, every EtherCAT master registeres a read-only -network interface \textit{ecX}, where X is a number, provided by the -kernel on device registration. While it is ``up'', the master forwards -every frame sent and received to this interface. - -This makes it possible to connect an network monitor (like Wireshark -or tcpdump) to the debug interface and monitor the EtherCAT frames. - -It has to be considered, that can be frame rate can be very high. The -idle state machine usually runs every kernel timer interrupt (up to -$1$~kHz) and with a connected realtime module, the rate can be even +For debugging purposes, every EtherCAT master registers a read-only network +interface \textit{ecX}, where X is a number, provided by the kernel on device +registration. While it is ``up'', the master forwards every frame sent and +received to this interface. + +This makes it possible to connect an network monitor (like Wireshark or +tcpdump) to the debug interface and monitor the EtherCAT frames. + +% FIXME schedule() +It has to be considered, that can be frame rate can be very high. The master +state machine usually runs every kernel timer interrupt (usually up to +\unit{1}{\kilo\hertz}) and with a connected application, the rate can be even higher. \paragraph{Attention:} The socket buffers needed for the operation of @@ -4164,12 +3461,11 @@ %------------------------------------------------------------------------------ -\section{Timing Aspects} +\chapter{Timing Aspects} \label{sec:timing} -Although EtherCAT's timing is highly deterministic and therefore -timing issues are rare, there are a few aspects that can (and should -be) dealt with. +Although EtherCAT's timing is highly deterministic and therefore timing issues +are rare, there are a few aspects that can (and should be) dealt with. %------------------------------------------------------------------------------ @@ -4177,11 +3473,10 @@ \label{sec:timing-profile} \index{Realtime!Profiling} -One of the most important timing aspects are the runtimes of the +One of the most important timing aspects are the execution times of the realtime interface functions, that are called in cyclic context. These -functions make up an important part of the overall timing of the -realtime module. To measure the timing of the functions, the following -code was used: +functions make up an important part of the overall timing of the application. +To measure the timing of the functions, the following code was used: \begin{lstlisting}[gobble=2,language=C] c0 = get_cycles(); @@ -4195,23 +3490,24 @@ c4 = get_cycles(); \end{lstlisting} -Between each call of an interface function, the CPU timestamp counter -is read. The counter differences are converted to microseconds with -help of the \textit{cpu\_khz} variable, that contains the number of -increments per millisecond. - -For the actual measuring, a system with a $2.0$~GHz CPU was used, that -ran the above code in an RTAI thread with a cycle time of $100$ -\textmu s. The measuring was repeated $n = 100$ times and the results -were averaged. These can be seen in table~\ref{tab:profile}. +Between each call of an interface function, the CPU timestamp counter is read. +The counter differences are converted to \micro\second\ with help of the +\lstinline+cpu_khz+ variable, that contains the number of increments per +\milli\second. + +For the actual measuring, a system with a \unit{2.0}{\giga\hertz} CPU was used, +that ran the above code in an RTAI thread with a period of +\unit{100}{\micro\second}. The measuring was repeated $n = 100$ times and the +results were averaged. These can be seen in table~\ref{tab:profile}. \begin{table}[htpb] \centering - \caption{Profiling of a Realtime Cycle on a $2.0$~GHz Processor} + \caption{Profiling of a Realtime Cycle on a \unit{2.0}{\giga\hertz} + Processor} \label{tab:profile} \vspace{2mm} \begin{tabular}{l|r|r} - Element & Mean Duration [\textmu s] & Standard Deviancy [\textmu s] \\ + Element & Mean Duration [\second] & Standard Deviancy [\micro\second] \\ \hline \textit{ecrt\_master\_receive()} & 8.04 & 0.48\\ \textit{ecrt\_domain\_process()} & 0.14 & 0.03\\ @@ -4221,7 +3517,7 @@ \end{tabular} \end{table} -It is obvious, that the the functions accessing hardware make up the +It is obvious, that the functions accessing hardware make up the lion's share. The \textit{ec\_master\_receive()} executes the ISR of the Ethernet device, analyzes datagrams and copies their contents into the memory of the datagram objects. The \textit{ec\_master\_send()} @@ -4229,24 +3525,27 @@ hardware buffers. Interestingly, this makes up only a quarter of the receiving time. -The functions that only operate on the masters internal data -structures are very fast ($\Delta t < 1$~\textmu s). Interestingly the -runtime of \textit{ec\_domain\_process()} has a small standard -deviancy relative to the mean value, while this ratio is about twice -as big for \textit{ec\_master\_run()}: This probably results from the -latter function having to execute code depending on the current state -and the different state functions are more or less complex. - -For a realtime cycle makes up about $10$~\textmu s, the theoretical -frequency can be up to $100$~kHz. For two reasons, this frequency +The functions that only operate on the masters internal data structures are +very fast ($\Delta t < \unit{1}{\micro\second}$). Interestingly the runtime of +\textit{ec\_domain\_process()} has a small standard deviancy relative to the +mean value, while this ratio is about twice as big for +\textit{ec\_master\_run()}: This probably results from the latter function +having to execute code depending on the current state and the different state +functions are more or less complex. + +For a realtime cycle makes up about \unit{10}{\micro\second}, the theoretical +frequency can be up to \unit{100}{\kilo\hertz}. For two reasons, this frequency keeps being theoretical: \begin{enumerate} -\item The processor must still be able to run the operating system - between the realtime cycles. -\item The EtherCAT frame must be sent and received, before the next - realtime cycle begins. The determination of the bus cycle time is - difficult and covered in section~\ref{sec:timing-bus}. + +\item The processor must still be able to run the operating system between the +realtime cycles. + +\item The EtherCAT frame must be sent and received, before the next realtime +cycle begins. The determination of the bus cycle time is difficult and covered +in section~\ref{sec:timing-bus}. + \end{enumerate} %------------------------------------------------------------------------------ @@ -4272,58 +3571,44 @@ to the notification is unknown. Therefore the only way to confidently determine the bus cycle time is an electrical measuring. -Anyway, the bus cycle time is an important factor when designing -realtime code, because it limits the maximum frequency for the cyclic -part of the realtime module. In practice, these timing parameters are -highly dependent on the hardware and often a trial and error method -must be used to determine the limits of the system. - -The central question is: What happens, if the cycle frequency is too -high? The answer is, that the EtherCAT frames that have been sent at -the end of the cycle are not yet received, when the next cycle starts. -First this is noticed by \textit{ecrt\_domain\_process()}, because the -working counter of the process data datagrams were not increased. The -function will notify the user via syslog\footnote{To limit syslog - output, a mechanism has been implementet, that outputs a summarized - notification at maximum once a second.}. In this case, the process -data keeps being the same as in the last cycle, because it is not -erased by the domain. When the domain datagrams are queued again, the -master notices, that they are already queued (and marked as sent). The -master will mark them as unsent again and output a warning, that -datagrams were ``skipped''. - -On the mentioned $2.0$~GHz system, the possible cycle frequency can be -up to $25$~kHz without skipped frames. This value can surely be -increased by choosing faster hardware. Especially the RealTek network -hardware could be replaced by a faster one. Besides, implementing a -dedicated ISR for EtherCAT devices would also contribute to increasing -the latency. These are two points on the author's to-do list. - -%------------------------------------------------------------------------------ - -\chapter{Using the EtherCAT Master} -\label{chapter:usage} -\index{Master!Usage} - -This chapter will give practical examples of how to use the EtherCAT -master via the realtime interface by writing a realtime module. - -Section~\ref{sec:make} shows how to compile and install the master, -while the sections~\ref{sec:mini} to~\ref{sec:concurrency} give -examples for different realtime modules. - -%------------------------------------------------------------------------------ - -\section{Compiling and Installing} -\label{sec:make} -\index{Master!Compilation} +Anyway, the bus cycle time is an important factor when designing realtime code, +because it limits the maximum frequency for the cyclic task of the application. +In practice, these timing parameters are highly dependent on the hardware and +often a trial and error method must be used to determine the limits of the +system. + +The central question is: What happens, if the cycle frequency is too high? The +answer is, that the EtherCAT frames that have been sent at the end of the cycle +are not yet received, when the next cycle starts. First this is noticed by +\textit{ecrt\_domain\_process()}, because the working counter of the process +data datagrams were not increased. The function will notify the user via +Syslog\footnote{To limit Syslog output, a mechanism has been implemented, that +outputs a summarized notification at maximum once a second.}. In this case, the +process data keeps being the same as in the last cycle, because it is not +erased by the domain. When the domain datagrams are queued again, the master +notices, that they are already queued (and marked as sent). The master will +mark them as unsent again and output a warning, that datagrams were +``skipped''. + +On the mentioned \unit{2.0}{\giga\hertz} system, the possible cycle frequency +can be up to \unit{25}{\kilo\hertz} without skipped frames. This value can +surely be increased by choosing faster hardware. Especially the RealTek network +hardware could be replaced by a faster one. Besides, implementing a dedicated +ISR for EtherCAT devices would also contribute to increasing the latency. These +are two points on the author's to-do list. + +%------------------------------------------------------------------------------ + +\chapter{Installation} +\label{sec:installation} +\index{Master!Installation} The current EtherCAT master code is available at~\cite{etherlab} or can be obtained from the EtherLab\textsuperscript{\textregistered} CD. The \textit{tar.bz2} file has to be unpacked with the commands below (or similar): -\begin{lstlisting} +\begin{lstlisting}[gobble=2] `\$` `\textbf{tar xjf ethercat-\masterversion.tar.bz2}` `\$` `\textbf{cd ethercat-\masterversion/}` \end{lstlisting} @@ -4331,32 +3616,79 @@ The tarball was created with GNU Autotools, so the build process follows the below commands: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] `\$` `\textbf{./configure}` + `\$` `\textbf{make}` `\$` `\textbf{make modules}` \end{lstlisting} -The default installation prefix is \textit{/opt/etherlab}. It can be -changed with the \texttt{--prefix} argument. - -Linux kernel sources are needed for compilation\footnote{If a realtime - extension shall to be used, the kernel should be patched before - compiling the EtherCAT master.}. To compile the EtherCAT master -modules for a different kernel than the running kernel, the target -kernel version can be specified with the \texttt{--with-linux} -argument. Example: - -\begin{lstlisting} - `\$` `\textbf{./configure --with-linux="2.6.17-ipipe"}` - `\$` `\textbf{make modules}` -\end{lstlisting} +Table~\ref{tab:config} lists important configuration switches and options. + +\begin{table} + \caption{Configuration options} + \label{tab:config} + \vspace{2mm} + \begin{tabular}{l|p{.3\textwidth}|l} + +\bf Option/Switch & \bf Description & \bf Default\\\hline + +\lstinline+--prefix+ & Installation prefix & \textit{/opt/etherlab}\\ + +\lstinline+--with-linux-dir+ & Linux kernel sources & Use running kernel\\ + +\lstinline+--with-rtai-dir+ & RTAI path (only for RTAI example) & \\ + +\hline + +\lstinline+--enable-eoe+ & Enable EoE support & yes\\ + +\lstinline+--enable-cycles+ & Use CPU timestamp counter. Enable this on Intel +architecture to get finer timing calculation. & no\\ + +\lstinline+--enable-debug-if+ & Create a debug interface for each master & no\\ + +\lstinline+--enable-debug-ring+ & Create a debug ring to record frames & no\\ + +\hline + +\lstinline+--enable-8139too+ & Build the 8139too driver & yes\\ + +\lstinline+--with-8139too-kernel+ & 8139too kernel & $\dagger$\\ + +\lstinline+--enable-e100+ & Build the e100 driver & no\\ + +\lstinline+--with-e100-kernel+ & e100 kernel & $\dagger$\\ + +\lstinline+--enable-forcedeth+ & Enable forcedeth driver & no\\ + +\lstinline+--with-forcedeth-kernel+ & forcedeth kernel & $\dagger$\\ + +\lstinline+--enable-e1000+ & Enable e1000 driver & no\\ + +\lstinline+--with-e1000-kernel+ & e1000 kernel & $\dagger$\\ + +\lstinline+--enable-r8169+ & Enable r8169 driver & no\\ + +\lstinline+--with-r8169-kernel+ & r8169 kernel & $\dagger$\\ + + \end{tabular} + \vspace{2mm} + +\begin{description} + +\item[$\dagger$] If this option is not specified, the kernel version to use is +extracted from the Linux kernel sources. + +\end{description} + +\end{table} The below commands have to be entered as \textit{root}: The first one will install the kernel modules to the kernel's modules directory. The second one will install EtherCAT headers, the init script, the sysconfig file and the user space tools to the prefix path. -\begin{lstlisting} +\begin{lstlisting}[gobble=2] # `\textbf{make modules\_install}` # `\textbf{make install}` \end{lstlisting} @@ -4365,122 +3697,108 @@ \textit{/lib/modules}, a different destination directory can be specified with the \textit{DESTDIR} make variable. For example: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] # `\textbf{make DESTDIR=/vol/nfs/root modules\_install}` \end{lstlisting} This command will install the compiled kernel modules to \textit{/vol/nfs/root/lib/modules}, prepended by the kernel release. -If the EtherCAT master shall be run as a service -(recommended\footnote{Even if the EtherCAT master shall not be loaded - on system startup, the use of the init script is recommended for - manual (un-)loading.}), the init script and the sysconfig file have -to be copied to the appropriate locations. The below example is -suitable for SUSE Linux. It may vary for other distributions. - -\begin{lstlisting} +If the EtherCAT master shall be run as a service\footnote{Even if the EtherCAT +master shall not be loaded on system startup, the use of the init script is +recommended for manual (un-)loading.}, the init script and the sysconfig file +have to be copied (or linked) to the appropriate locations. The below example +is suitable for SUSE Linux. It may vary for other distributions. + +\begin{lstlisting}[gobble=2] # `\textbf{cd /opt/etherlab}` # `\textbf{cp etc/sysconfig/ethercat /etc/sysconfig/}` - # `\textbf{cp etc/init.d/ethercat /etc/init.d/}` + # `\textbf{ln -s etc/init.d/ethercat /etc/init.d/}` # `\textbf{insserv ethercat}` \end{lstlisting} Now the sysconfig file \texttt{/etc/sysconfig/ethercat} (see -section~\ref{sec:sysconfig}) has to be customized: This is mainly done -by uncommenting and adjusting the \$DEVICE\_INDEX variable. It has to -be set to the index of the compatible network device to use with -EtherCAT, where the order of devices is dependent on their position in -the PCI bus: - -\begin{lstlisting}[numbers=left,basicstyle=\ttfamily\scriptsize] - # `\textbf{lspci}` - 00:00.0 Host bridge: VIA Technologies, Inc. VT8363/8365 [KT133/KM133] (rev 03) - 00:01.0 PCI bridge: VIA Technologies, Inc. VT8363/8365 [KT133/KM133 AGP] - 00:04.0 ISA bridge: VIA Technologies, Inc. VT82C686 [Apollo Super South] (rev 40) - 00:04.1 IDE interface: VIA Technologies, Inc. VT82C586A/B/VT82C686/A/B/VT823x/A/C... - 00:04.2 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1 Controller... - 00:04.3 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1 Controller... - 00:04.4 Bridge: VIA Technologies, Inc. VT82C686 [Apollo Super ACPI] (rev 40) - 00:09.0 Ethernet controller: D-Link System Inc RTL8139 Ethernet (rev 10) - 00:0a.0 Ethernet controller: Intel Corporation 82557/8/9 [Ethernet Pro 100] (rev 08) - 00:0b.0 Ethernet controller: D-Link System Inc RTL8139 Ethernet (rev 10) - 00:0c.0 VGA compatible controller: ATI Technologies Inc Rage XL (rev 27) - 00:11.0 Unknown mass storage controller: Promise Technology, Inc. PDC20265... -\end{lstlisting} - -In the above output of the \textit{lspci} command, two compatible -network devices can be found in lines~\textcircled{\tiny 9} and -\textcircled{\tiny 11}. The \$DEVICE\_INDEX variable should be set to -$0$ or $1$, respectively. +section~\ref{sec:sysconfig}) has to be customized. The minimal customization +is to set the \lstinline+MASTER0_DEVICE+ variable to the MAC address of the +Ethernet device to use (or \lstinline+ff:ff:ff:ff:ff:ff+ to use the first +device offered) and selecting the driver(s) to load via the +\lstinline+DEVICE_MODULES+ variable. After the basic configuration is done, the master can be started with the below command: -\begin{lstlisting} +\begin{lstlisting}[gobble=2] # `\textbf{/etc/init.d/ethercat start}` \end{lstlisting} The operation of the master can be observed by looking at the -syslog\index{syslog} messages, which should look like the ones below. -If EtherCAT slaves are connected to the master's EtherCAT device, the -activity indicators should begin to flash. +Syslog\index{Syslog} messages, which should look like the ones below. If +EtherCAT slaves are connected to the master's EtherCAT device, the activity +indicators should begin to flash. \begin{lstlisting}[numbers=left] - EtherCAT: Master driver, 1.1 (stable) - rev. 513, - compiled by fp at Aug 09 2006 10:23:20 - EtherCAT: Initializing 1 EtherCAT master(s)... - EtherCAT: Initializing master 0. - EtherCAT: Master driver initialized. - ec_8139too Fast Ethernet driver 0.9.27 Revision 513, - compiled by fp at Aug 09 2006 10:23:20 - ec_device_index is 0 - ACPI: PCI Interrupt 0000:01:00.0[A] -> Link [LNKC] - -> GSI 11 (level, low) -> IRQ 11 - ec0: RealTek RTL8139 at 0xd047c000, 00:c0:26:00:c6:aa, IRQ 11 - ec0: Identified 8139 chip type 'RTL-8100B/8139D' - Registering EtherCAT device... - Starting EtherCAT device... - EtherCAT: Link state changed to UP. - EtherCAT: Starting Idle mode. - EtherCAT: 11 slaves responding. - EtherCAT: Slave states: INIT, OP. - EtherCAT: Scanning bus. - EtherCAT: Bus scanning completed. - EtherCAT: No EoE handlers coupled. +EtherCAT: Master driver `\masterversion` +EtherCAT: 1 master waiting for devices. +EtherCAT Intel(R) PRO/1000 Network Driver - version 6.0.60-k2 +Copyright (c) 1999-2005 Intel Corporation. +PCI: Found IRQ 12 for device 0000:01:01.0 +PCI: Sharing IRQ 12 with 0000:00:1d.2 +PCI: Sharing IRQ 12 with 0000:00:1f.1 +EtherCAT: Accepting device 00:0E:0C:DA:A2:20 for master 0. +EtherCAT: Starting master thread. +ec_e1000: ec0: e1000_probe: Intel(R) PRO/1000 Network + Connection +ec_e1000: ec0: e1000_watchdog_task: NIC Link is Up 100 Mbps + Full Duplex +EtherCAT: Link state changed to UP. +EtherCAT: 7 slave(s) responding. +EtherCAT: Slave states: PREOP. +EtherCAT: Scanning bus. +EtherCAT: Bus scanning completed in 431 ms. \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 1}] The master module is loaded, - and one master is initialized. -\item[\normalfont\textcircled{\tiny 6}] The EtherCAT-capable RTL8139 - device driver is loaded. It connects its first network device to the - master. -\item[\normalfont\textcircled{\tiny 16}] The master starts idle mode - and begins scanning the bus for slaves. + +\item[\linenum{1} -- \linenum{2}] The master module is loading, and one master +is initialized. + +\item[\linenum{3} -- \linenum{8}] The EtherCAT-capable e1000 driver is +loading. The master accepts the device with the address +\lstinline+00:0E:0C:DA:A2:20+. + +\item[\linenum{9} -- \linenum{16}] The master goes to idle phase, starts its +state machine and begins scanning the bus. + \end{description} %------------------------------------------------------------------------------ -\section{A Minimal Example Module} +\chapter{Application examples} +\label{chapter:examples} + +This chapter will give practical examples of how to use the EtherCAT master via +the realtime interface by writing an application module. + +%------------------------------------------------------------------------------ + +\section{Minimal Example} \label{sec:mini} \index{Examples!Minimal} -This section will explain the usage of the EtherCAT master from a -minimal kernel module. The complete module code is obtainable as a -part of the EtherCAT master code release (see~\cite{etherlab}, file -\textit{examples/mini/mini.c}). - -The minimal example uses a kernel timer (software interrupt) to handle -cyclic code. After the timer function is executed, it re-adds itself -with a delay of one \textit{jiffy}\index{jiffies}, which results in a -timer frequency of \textit{HZ}\nomenclature{HZ}{Kernel macro - containing the timer interrupt frequency} +This section will explain the use of the EtherCAT master from a minimal kernel +module. The complete module code is obtainable as a part of the EtherCAT master +code release (see~\cite{etherlab}, file \textit{examples/mini/mini.c}). + +The minimal example uses a kernel timer (software interrupt) to generate a +cyclic task. After the timer function is executed, it re-adds itself with a +delay of one \textit{jiffy}\index{jiffies}, which results in a timer frequency +of \textit{HZ}\nomenclature{HZ}{Kernel macro containing the timer interrupt +frequency} The module-global variables, needed to operate the master can be seen in listing~\ref{lst:minivar}. -\begin{lstlisting}[language=C,numbers=left,caption={Minimal +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={Minimal variables},label=lst:minivar] struct timer_list timer; @@ -4497,20 +3815,20 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 1}] There is a timer object +\item[\linenum{1}] There is a timer object declared, that is needed to tell the kernel to install a timer and execute a certain function, if it runs out. This is done by a variable of the \textit{timer\_list} structure. -\item[\normalfont\textcircled{\tiny 3} -- \textcircled{\tiny 4}] There +\item[\linenum{3} -- \linenum{4}] There is a pointer declared, that will later point to a requested EtherCAT master. Additionally there is a pointer to a domain object needed, that will manage process data IO. -\item[\normalfont\textcircled{\tiny 6}] The pointers \textit{r\_*} +\item[\linenum{6}] The pointers \textit{r\_*} will later point to the \underline{r}aw process data values inside the domain memory. The addresses they point to will be set during a call to \textit{ec\_\-master\_\-activate()}, that will create the domain memory and configure the mapped process data image. -\item[\normalfont\textcircled{\tiny 8} -- \textcircled{\tiny 12}] The +\item[\linenum{8} -- \linenum{12}] The configuration of the mapping of certain Pdos in a domain can easily be done with the help of an initialization array of the \textit{ec\_pdo\_reg\_t} type, defined as part of the realtime @@ -4524,10 +3842,10 @@ must end with an empty record (\textit{\{\}})! \end{description} -The initialization of the minimal realtime module is done by the -``Minimal init function'' in listing~\ref{lst:miniinit}. - -\begin{lstlisting}[language=C,numbers=left,caption={Minimal init +The initialization of the minimal application is done by the ``Minimal init +function'' in listing~\ref{lst:miniinit}. + +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={Minimal init function},label={lst:miniinit}] int __init init_mini_module(void) { @@ -4565,24 +3883,24 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 3}] It is tried to request the +\item[\linenum{3}] It is tried to request the first EtherCAT master (index 0). On success, the \textit{ecrt\_\-request\_\-master()} function returns a pointer to the reserved master, that can be used as an object to following functions calls. On failure, the function returns \textit{NULL}. -\item[\normalfont\textcircled{\tiny 7}] In order to exchange process +\item[\linenum{7}] In order to exchange process data, a domain object has to be created. The \textit{ecrt\_\-master\_\-create\_domain()} function also returns a pointer to the created domain, or \textit{NULL} in error case. -\item[\normalfont\textcircled{\tiny 11}] The registration of domain +\item[\linenum{11}] The registration of domain Pdos with an initialization array results in a single function call. Alternatively the data fields could be registered with individual calls of \textit{ecrt\_domain\_register\_pdo()}. -\item[\normalfont\textcircled{\tiny 16}] After the configuration of +\item[\linenum{16}] After the configuration of process data mapping, the master can be activated for cyclic operation. This will configure all slaves and bring them into OP state. -\item[\normalfont\textcircled{\tiny 20}] This call is needed to avoid +\item[\linenum{20}] This call is needed to avoid a case differentiation in cyclic operation: The first operation in cyclic mode is a receive call. Due to the fact, that there is nothing to receive during the first cycle, there had to be an @@ -4590,7 +3908,7 @@ \textit{ec\_master\_prepare()} sends a first datagram containing a process data exchange datagram, so that the first receive call will not fail. -\item[\normalfont\textcircled{\tiny 22} -- \textcircled{\tiny 25}] The +\item[\linenum{22} -- \linenum{25}] The master is now ready for cyclic operation. The kernel timer that cyclically executes the \textit{run()} function is initialized and started. @@ -4599,7 +3917,7 @@ The coding of a cleanup function fo the minimal module can be seen in listing~\ref{lst:miniclean}. -\begin{lstlisting}[language=C,numbers=left,caption={Minimal cleanup +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={Minimal cleanup function},label={lst:miniclean}] void __exit cleanup_mini_module(void) { @@ -4610,15 +3928,15 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 3}] To cleanup the module, it it +\item[\linenum{3}] To cleanup the module, it it necessary to stop the cyclic processing. This is done by a call to \textit{del\_timer\_sync()} which safely removes a queued timer object. It is assured, that no cyclic work will be done after this call returns. -\item[\normalfont\textcircled{\tiny 4}] This call deactivates the +\item[\linenum{4}] This call deactivates the master, which results in all slaves being brought to their INIT state again. -\item[\normalfont\textcircled{\tiny 5}] This call releases the master, +\item[\linenum{5}] This call releases the master, removes any existing configuration and silently starts the idle mode. The value of the master pointer is invalid after this call and the module can be safely unloaded. @@ -4627,7 +3945,7 @@ The final part of the minimal module is that for the cyclic work. Its coding can be seen in listing~\ref{lst:minirun}. -\begin{lstlisting}[language=C,numbers=left,caption={Minimal cyclic +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={Minimal cyclic function},label={lst:minirun}] void run(unsigned long data) { @@ -4648,42 +3966,45 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 5}] The cyclic processing starts - with receiving datagrams, that were sent in the last cycle. The - frames containing these datagrams have to be received by the network - interface card prior to this call. -\item[\normalfont\textcircled{\tiny 6}] The process data of domain 1 - has been automatically copied into domain memory while datagram - reception. This call checks the working counter for changes and - re-queues the domain's datagram for sending. -\item[\normalfont\textcircled{\tiny 8}] This is an example for reading - out a bit-oriented process data value (i.~e. bit 0) via the - \textit{EC\_READ\_BIT()} macro. See section~\ref{sec:macros} for - more information about those macros. -\item[\normalfont\textcircled{\tiny 9}] This line shows how to write a - signed, 16-bit process data value. In this case, the slave is able - to output voltages of $-10$~V to $+10$~V with a resolution of 16 - bit. This write command outputs either $0$~V or $+5$~V, depending - of the value of \textit{dig\_in\_0}. -\item[\normalfont\textcircled{\tiny 11}] This call runs the master's - operation state machine (see section~\ref{sec:fsm-op}). A single - state is processed, and datagrams are queued. Mainly bus observation - is done: The bus state is determined and in case of slaves that lost - their configuration, reconfiguration is tried. -\item[\normalfont\textcircled{\tiny 12}] This method sends all queued - datagrams, in this case the domain's datagram and one of the master - state machine. In best case, all datagrams fit into one frame. -\item[\normalfont\textcircled{\tiny 14} -- \textcircled{\tiny 15}] - Kernel timers are implemented as ``one-shot'' timers, so they have - to be re-added after each execution. The time of the next execution - is specified in \textit{jiffies} and will happen at the time of the - next system timer interrupt. This results in the \textit{run()} - function being executed with a frequency of \textit{HZ}. + +\item[\linenum{5}] The cyclic processing starts with receiving datagrams, that +were sent in the last cycle. The frames containing these datagrams have to be +received by the network interface card prior to this call. + +\item[\linenum{6}] The process data of domain 1 has been automatically copied +into domain memory while datagram reception. This call checks the working +counter for changes and re-queues the domain's datagram for sending. + +\item[\linenum{8}] This is an example for reading out a bit-oriented process +data value (i.~e. bit 0) via the \textit{EC\_READ\_BIT()} macro. See +section~\ref{sec:macros} for more information about those macros. + +\item[\linenum{9}] This line shows how to write a signed, 16-bit process data +value. In this case, the slave is able to output voltages of +\unit{-10--+10}{\volt} with a resolution of \unit{16}{bit}. This write command +outputs either \unit{0}{\volt} or \unit{+5}{\volt}, depending of the value of +\textit{dig\_in\_0}. + +\item[\linenum{11}] This call runs the master's operation state machine (see +section~\ref{sec:fsm-op}). A single state is processed, and datagrams are +queued. Mainly bus observation is done: The bus state is determined and in case +of slaves that lost their configuration, reconfiguration is tried. + +\item[\linenum{12}] This method sends all queued datagrams, in this case the +domain's datagram and one of the master state machine. In best case, all +datagrams fit into one frame. + +\item[\linenum{14} -- \linenum{15}] Kernel timers are implemented as +``one-shot'' timers, so they have to be re-added after each execution. The time +of the next execution is specified in \textit{jiffies} and will happen at the +time of the next system timer interrupt. This results in the \textit{run()} +function being executed with a frequency of \textit{HZ}. + \end{description} %------------------------------------------------------------------------------ -\section{An RTAI Example Module} +\section{RTAI Example} \label{sec:rtai} \index{Examples!RTAI} @@ -4693,7 +4014,7 @@ Listing~\ref{lst:rtaivar} shows the defines and global variables needed for a minimal RTAI module with EtherCAT processing. -\begin{lstlisting}[language=C,numbers=left,caption={RTAI task +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={RTAI task declaration},label={lst:rtaivar}] #define FREQUENCY 10000 #define TIMERTICKS (1000000000 / FREQUENCY) @@ -4702,10 +4023,10 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 1} -- \textcircled{\tiny 2}] RTAI +\item[\linenum{1} -- \linenum{2}] RTAI takes the cycle period as nanoseconds, so the easiest way is to define a frequency and convert it to a cycle time in nanoseconds. -\item[\normalfont\textcircled{\tiny 4}] The \textit{task} variable +\item[\linenum{4}] The \textit{task} variable later contains information about the running RTAI task. \end{description} @@ -4713,7 +4034,7 @@ module. Most lines are the same as in listing~\ref{lst:miniinit}, differences come up when starting the cyclic code. -\begin{lstlisting}[language=C,numbers=left,caption={RTAI module init +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={RTAI module init function},label={lst:rtaiinit}] int __init init_mod(void) { @@ -4767,23 +4088,23 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 24} -- \textcircled{\tiny 25}] The +\item[\linenum{24} -- \linenum{25}] The nanoseconds are converted to RTAI timer ticks and an RTAI timer is started. \textit{tick\_period} will be the ``real'' number of ticks used for the timer period (which can be different to the requested one). -\item[\normalfont\textcircled{\tiny 27}] The RTAI task is initialized +\item[\linenum{27}] The RTAI task is initialized by specifying the cyclic function, the parameter to hand over, the stack size, priority, a flag that tells, if the function will use floating point operations and a signal handler. -\item[\normalfont\textcircled{\tiny 32}] The task is made periodic by +\item[\linenum{32}] The task is made periodic by specifying a start time and a period. \end{description} The cleanup function of the RTAI module in listing~\ref{lst:rtaiclean} is nearly as simple as that of the minimal module. -\begin{lstlisting}[language=C,numbers=left,caption={RTAI module +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={RTAI module cleanup function},label={lst:rtaiclean}] void __exit cleanup_mod(void) { @@ -4796,9 +4117,9 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 2}] The RTAI task will be stopped +\item[\linenum{2}] The RTAI task will be stopped and deleted. -\item[\normalfont\textcircled{\tiny 3}] After that, the RTAI timer can +\item[\linenum{3}] After that, the RTAI timer can be stopped. \end{description} @@ -4810,7 +4131,7 @@ infinite loop in it, that is placed in a waiting state for the rest of each cycle. -\begin{lstlisting}[language=C,numbers=left,caption={RTAI module cyclic +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={RTAI module cyclic function},label={lst:rtairun}] void run(long data) { @@ -4829,9 +4150,9 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 3}] The \textit{while (1)} loop +\item[\linenum{3}] The \textit{while (1)} loop executes for the lifetime of the RTAI task. -\item[\normalfont\textcircled{\tiny 12}] The +\item[\linenum{12}] The \textit{rt\_task\_wait\_period()} function sets the process into a sleeping state until the beginning of the next cycle. It also checks, if the cyclic function has to be terminated. @@ -4843,20 +4164,19 @@ \label{sec:concurrency} \index{Examples!Concurrency} -As mentioned before, there can be concurrent access to the EtherCAT -master. The realtime module and a EoE\index{EoE} process can compete -for master access, for example. In this case, the module has to -provide the locking mechanism, because it depends on the module's -architecture which lock has to be used. The module makes this locking -mechanism available to the master through the master's locking -callbacks. +As mentioned before, there can be concurrent access to the EtherCAT master. The +application and a EoE\index{EoE} process can compete for master access, for +example. In this case, the module has to provide the locking mechanism, because +it depends on the module's architecture which lock has to be used. The module +makes this locking mechanism available to the master through the master's +locking callbacks. In case of RTAI, the lock can be an RTAI semaphore, as shown in -listing~\ref{lst:convar}. A normal linux semaphore would not be -appropriate, because it could not block the RTAI task due to RTAI -running in a higher domain than the linux kernel (see~\cite{rtai}). - -\begin{lstlisting}[language=C,numbers=left,caption={RTAI semaphore for +listing~\ref{lst:convar}. A normal Linux semaphore would not be appropriate, +because it could not block the RTAI task due to RTAI running in a higher domain +than the Linux kernel (see~\cite{rtai}). + +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={RTAI semaphore for concurrent access},label={lst:convar}] SEM master_sem; \end{lstlisting} @@ -4865,7 +4185,7 @@ releasing the master lock. An exemplary coding can be seen in listing~\ref{lst:conlock}. -\begin{lstlisting}[language=C,numbers=left,caption={RTAI locking +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={RTAI locking callbacks for concurrent access},label={lst:conlock}] int request_lock(void *data) { @@ -4880,24 +4200,24 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 1}] The \textit{request\_lock()} +\item[\linenum{1}] The \textit{request\_lock()} function has a data parameter. The master always passes the value, that was specified when registering the callback function. This can be used for handing the master pointer. Notice, that it has an integer return value (see line 4). -\item[\normalfont\textcircled{\tiny 3}] The call to +\item[\linenum{3}] The call to \textit{rt\_sem\_wait()} either returns at once, when the semaphore was free, or blocks until the semaphore is freed again. In any case, the semaphore finally is reserved for the process calling the request function. -\item[\normalfont\textcircled{\tiny 4}] When the lock was requested +\item[\linenum{4}] When the lock was requested successfully, the function should return 0. The module can prohibit requesting the lock by returning non-zero (see paragraph ``Tuning the jitter'' below). -\item[\normalfont\textcircled{\tiny 7}] The \textit{release\_lock()} +\item[\linenum{7}] The \textit{release\_lock()} function gets the same argument passed, but has a void return value, because is always succeeds. -\item[\normalfont\textcircled{\tiny 9}] The \textit{rt\_sem\_signal()} +\item[\linenum{9}] The \textit{rt\_sem\_signal()} function frees the semaphore, that was prior reserved with \textit{rt\_sem\_wait()}. \end{description} @@ -4905,7 +4225,7 @@ In the module's init function, the semaphore must be initialized, and the callbacks must be passed to the EtherCAT master: -\begin{lstlisting}[language=C,numbers=left,caption={Module init +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={Module init function for concurrent access},label={lst:coninit}] int __init init_mod(void) { @@ -4923,11 +4243,11 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 5}] The call to +\item[\linenum{5}] The call to \textit{rt\_sem\_init()} initializes the semaphore and sets its value to 1, meaning that only one process can reserve the semaphore without blocking. -\item[\normalfont\textcircled{\tiny 11}] The callbacks are passed to +\item[\linenum{11}] The callbacks are passed to the master with a call to \textit{ecrt\_master\_callbacks()}. The last parameter is the argument, that the master should pass with each call to a callback function. Here it is not used and set to @@ -4939,7 +4259,7 @@ use the callbacks (which are meant for processes of lower priority), so it can access the semaphore directly: -\begin{lstlisting}[language=C,numbers=left,caption={RTAI cyclic +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={RTAI cyclic function for concurrent access},label={lst:conrun}] void run(long data) { @@ -4961,18 +4281,20 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 4}] Every access to the master has - to be preceeded by a call to \textit{rt\_sem\_wait()}, because - another instance might currently access the master. -\item[\normalfont\textcircled{\tiny 14}] When cyclic processing - finished, the semaphore has to be freed again, so that other - processes have the possibility to access the master. + +\item[\linenum{4}] Every access to the master has to be preceded by a call to +\textit{rt\_sem\_wait()}, because another instance might currently access the +master. + +\item[\linenum{14}] When cyclic processing finished, the semaphore has to be +freed again, so that other processes have the possibility to access the master. + \end{description} A little change has to be made to the cleanup function in case of concurrent master access. -\begin{lstlisting}[language=C,numbers=left,caption={RTAI module +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={RTAI module cleanup function for concurrent access},label={lst:conclean}] void __exit cleanup_mod(void) { @@ -4985,31 +4307,30 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 7}] Upon module cleanup, the +\item[\linenum{7}] Upon module cleanup, the semaphore has to be deleted, so that memory can be freed. \end{description} \paragraph{Tuning the Jitter} \index{Jitter} -Concurrent access leads to higher jitter of the realtime process, -because there are situations, in which the realtime process has to -wait for a process of lower priority to finish accessing the master. -In most cases this is acceptable, because a master access cycle -(receive/process/send) only takes $10$~\textmu s to $20$~\textmu s on -recent systems, what would be the maximum additional jitter. However -some applications demand a minimum jitter. For this reason the master -access can be prohibited by the realtime module: If the time, another -process wants to access the master, is to close to the beginning of -the next realtime cycle, the module can disallow, that the lock is -taken. In this case, the request callback has to return $1$, meaning -that the lock has not been taken. The foreign process must abort its -master access and try again next time. - -This measure helps to significantly reducing the jitter produced by -concurrent master access. Below are exerpts of an example coding: - -\begin{lstlisting}[language=C,numbers=left,caption={Variables for +Concurrent access leads to higher jitter for the application task, because +there are situations, in which the task has to wait for a process of lower +priority to finish accessing the master. In most cases this is acceptable, +because a master access cycle (receive/process/send) only takes +\unit{10-20}{\micro\second} on recent systems, what would be the maximum +additional jitter. However some applications demand a minimum jitter. For this +reason the master access can be prohibited by the application: If the time, +another process wants to access the master, is to close to the beginning of the +next application cycle, the module can disallow, that the lock is taken. In +this case, the request callback has to return $1$, meaning that the lock has +not been taken. The foreign process must abort its master access and try again +next time. + +This measure helps to significantly reducing the jitter produced by concurrent +master access. Below are excerpts of an example coding: + +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={Variables for jitter reduction},label={lst:redvar}] #define FREQUENCY 10000 // RTAI task frequency in Hz // ... @@ -5019,17 +4340,18 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 3}] The variable - \textit{t\_last\_cycle} holds the timer ticks at the beginning of - the last realtime cycle. -\item[\normalfont\textcircled{\tiny 4}] \textit{t\_critical} contains - the number of ticks, that may have passed since the beginning of the - last cycle, until there is no more foreign access possible. It is - calculated by substracting the ticks for $30$~\textmu s from the - ticks for a complete cycle. + +\item[\linenum{3}] The variable \textit{t\_last\_cycle} holds the timer ticks +at the beginning of the last realtime cycle. + +\item[\linenum{4}] \textit{t\_critical} contains the number of ticks, that may +have passed since the beginning of the last cycle, until there is no more +foreign access possible. It is calculated by subtracting the ticks for +\unit{30}{\micro\second} from the ticks for a complete cycle. + \end{description} -\begin{lstlisting}[language=C,numbers=left,caption={Cyclic function +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={Cyclic function with reduced jitter},label={lst:redrun}] void run(long data) { @@ -5040,11 +4362,11 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 4}] The ticks of the beginning of +\item[\linenum{4}] The ticks of the beginning of the current realtime cycle are taken before reserving the semaphore. \end{description} -\begin{lstlisting}[language=C,numbers=left,caption={Request callback +\begin{lstlisting}[gobble=2,language=C,numbers=left,caption={Request callback for reduced jitter},label={lst:redreq}] int request_lock(void *data) { @@ -5059,10 +4381,11 @@ \end{lstlisting} \begin{description} -\item[\normalfont\textcircled{\tiny 4}] If the time of request is too - close to the next realtime cycle (here: \textless~$30$~\textmu s - before the estimated beginning), the locking is denied. The - requesting process must abort its cycle. + +\item[\linenum{4}] If the time of request is too close to the next realtime +cycle (here: \unit{<30}{\micro\second} before the estimated beginning), the +locking is denied. The requesting process must abort its cycle. + \end{description} %------------------------------------------------------------------------------