![]() |
flexPTP 1.0
An IEEE 1588 PTP implementation designed for microcontrollers
|
In the Porting section a guide is presented to help porting flexPTP to a new platform. In the Configuration part basic and initial settings are listed.
We have included numerous examples into the basic flexPTP package with the intent to clarify purpose and structure of each porting file. The flexPTP accesses the target system using the following modules:
flexptp_options.h
configuration file, that defines settings for hardware clock operation, provides handles to the servo, connects flexPTP to the standard output and passes common includes to all flexPTP modules.In the sections below you'll see samples for all three configuration module types.
Each project that includes flexPTP must provide a flexptp_options.h
header file. This file has the purpose to tell flexPTP the basic hardware features (e.g. oscillator frequency), and to define bindings to hardware clock and servo management routines.
Our experience with embedded development shows that a newcomer might run into difficulties on creating a port to a software to be learned. We recommend you to open an example flexptp_options_XXX.h
file from the port/example_options
location before reading the following. Taking a quick look into a pre-made configuration file might make the interpretation of the section below much easier.
The assembling of a configuration file can be broken down into the following major steps:
Choose an OS interface:
FLEXPTP_CMSIS_OS2
macro to use the CMSIS OS2 bindings ORFLEXPTP_FREERTOS
macro to let the library call the FreeRTOS API directly ORFLEXPTP_LINUX
macro to use the standard Linux API (experimental)FLEXPTP_OSLESS
macro to enable the no-OS operation modeFLEXPTP_OSLESS_LOCK
macro with the type FifoLockFn. The simplest locking is to globally disable/enable interrupts.task_ptp()
and ptp_heartbeat_tmr_cb()
are exposed in this mode. They should be invoked periodically to run the library. Learn more at the functions' documentations.OS headers must be available to the library (e.g. cmsis_os2.h, FreeRTOS.h, etc.).
MSG(...)
: a basic formatted printing function that mimics printf()
functionality (called with printf()
-fashioned parameters). flexPTP uses the following formatting marks: %d
, %i
, %u
, %lu
, %f
, %x
, %X
, %s
, %c
, %%
.CLILOG(en,...)
: a maskable printing function: if en
is true
, it behaves like MSG(...)
SPRINTF(str,n,...)
: a basic snprintf()
implementation, that supports at least the same set of formatting marks as MSG(...)
doesPTP_ADDEND_INTERFACE
macro to select this interfacePTP_HW_INIT(increment, addend)
: a method that initializes the hardware clock. increment
: clock increment, addend
: initial frequency tuningPTP_SET_CLOCK(s, ns)
: a method that sets the hardware clock. s
: seconds part of the UNIX time, ns
: nanoseconds of the UNIX timePTP_SET_ADDEND(addend)
: a method that sets the hardware clock frequency tuning word. addend
: 32-bit tuning value (0x00000000..0xFFFFFFFF)PTP_HW_GET_TIME(pt)
: a method that fetches the time right from the hardware clock. pt
: time of type TimestampI *
; time is stored to *pt
PTP_MAIN_OSCILLATOR_FREQ_HZ
: clock frequency that drives the hardware clock in HzPTP_INCREMENT_NSEC
: amount of time the clock gets incremented each tick expressed in nanosecondsPTP_HLT_INTERFACE
macro to select this interfacePTP_HW_INIT()
: a method that initializes the hardware clock.PTP_SET_CLOCK(s, ns)
: a method that sets the hardware clock. s
: seconds part of the UNIX time, ns
: nanoseconds of the UNIX timePTP_SET_TUNING(tuning)
: a method that sets the hardware clock tuning. tuning
: tuning in PPBPTP_HW_GET_TIME(pt)
: a method that fetches the time right from the hardware clock. pt
: time of type TimestampI *
; time is stored to *pt
PTP_SERVO_INIT()
: a function that initializes the controller algorithmPTP_SERVO_DEINIT()
: a function that de-initializes the controller algorithmPTP_SERVO_RESET()
: a function that resets the controller algorithmPTP_SERVO_RUN(d, pscd)
: a function that invokes the controller and returns with a tuning value in PPB. d
: time error in nanoseconds, pscd
: pointer to synchronization cycle auxiliary context data of type PtpServoAuxInput *
. (refer to: Clock servo)CLI_REG_CMD(cmd_hintline,n_cmd,n_min_arg,cb)
: for parameter meanings and types refer to cli_cmds.cPTP_CONFIG_PTR()
: a macro that evaluates to a const void *
pointer to the area where the flexPTP config was stored previously. flexPTP expects to find a populated PtpConfig on address returned by PTP_CONFIG_PTR()
, that was previously generated by ptp_store_config()
.PTP_USER_EVENT_CALLBACK
: a function pointer of the PtpUserEventCallback typePTP_ENABLE_MASTER_OPERATION
to 1
We emphasize, that many examples can be found on configuration files in the port/example_options
directory.
Throughout the assembling of a new the options file you might find that the Ethernet driver, that came along the target platform lacks routines handling PTP functionality. In that case you it's your duty to extend the driver with the proper features. Many examples on such extensions can be found in the port/example_ports
directory.
flexptp_options_stm32f407_etherlib.h, flexptp_options_stm32h743_etherlib.h, flexptp_options_stm32h743.h, flexptp_options_tm4c1294.h, flexptp_options_mk64f.h
The flexPTP library expects (only!) the below message transception related functions defined. These are the functions, that are declared in network_stack_driver.h. During the porting work, these functions must be implemented.
void ptp_nsd_init(PtpTransportType tp, PtpDelayMechanism dm)
: This function initializes (opens and closes) the network connections based on the profile settings passed in the tp
and dm
parameters. tp
and dm
can take on any value from PtpTransportType
and PtpDelayMechanism
, respectively. Passing -1
in either parameter signals that the flexPTP wants the network layer to close all connections. In other words, by passing -1
the flexPTP does not defined a valid profile. It is expected that this function gets called multiple times. On subsequent calls, the function first informs the network that we are leaving the IGMP-group of the profile we abandon and closes connection associated with the profile we are leaving. Then, it takes on the new profile, opens the new connection and joins the new IGMP-groups. Joining and leaving of the IGMP-groups is performed by invoking the ptp_nsd_igmp_join_leave()
method.void ptp_nsd_transmit_msg(RawPtpMessage *pMsg, uint32_t uid)
1: The flexPTP engine calls this function to dispatch a PTP message. The NSD can safely anticipate that fields of the message passed from the PTP engine carry fields reflecting the profile that was set by the latest ptp_nsd_init()
call. The function must only fetch the PTP message class from the message passed to determine through which connection it has to be sent. The outbound messages are identified by unique IDs (UIDs). The message UID must be used to identify messages upon feeding back transmit timestamps using the ptp_transmit_timestamp_cb()
function. The former function is 'thread safe', it can be called from an interrupt context as well.void ptp_nsd_igmp_join_leave(bool join)
: The flexPTP engine might intend to inform the network about the joining or leaving of the IGMP-group associated with the operating profile (for example upon link recovery). Besides, ptp_nsd_init()
references this function as well.void ptp_nsd_get_interface_address(uint8_t * hwa)
: This function returns with the hardware address of the associated Ethernet interface. Parameter hwa
is expected to be able to hold (at least) 6-bytes (the size of an Ethernet Hardware Address).Finally, it's also the job of the NSD module to make the received messages available to the flexPTP core. This is done by calling the ptp_receive_enqueue()
function with the proper parameters: data, size and ingress timestamp split into seconds and nanoseconds field.
Inherently, the fetching and exchanging of the ingress and egress timestamps with the flexPTP core fall also in the scope of the NSD module.
1 This function signature has changed.
nsd_lwip.c, nsd_etherlib.c : Sample NSD implementations for lwIP and EtherLib network stacks.
The library supports two different, mutually exclusive clock management interfaces: the old-style ADDEND-based tuning interface and the newly introduced High-Level Tuning (HLT) interface. The user should implement the one better matched to the underlying hardware.
This interface assumes the above hardware clock model. In the majority of the microcontrollers with PTP support the structure of the PTP hardware clock follows this scheme.
Such hardware clocks can be tuned by altering a so called frequency tuning code word. The actual tuning value, a code word is an addend of a high-precision frequency divider in the clock's core. The code word is directly proportional with the output frequency. That's why we decided to represent 0 frequency with a zero and the maximum frequency with a 0xFFFFFFFF
( \(2^{32}-1\)) 32 bits code word. The former phrase in the form of a function:
\[ f_\text{clock} = f_\text{osc} \frac{\texttt{CODE WORD}}{2^{32}} \]
Hardware clocks keep time by increasing their stored time value with an increment
in every clock cycle (i.e. clock cycle of the divided clock). The increment
is usually constant and is set during the initialization. (It is usually expressed in nanoseconds.)
Addend and increment are the two basic idea that are supported by all such hardware clocks. The hardware clock driver must be able to control at least these two fields. By nature, clock drivers implementing the ADDEND-interface are low-level drivers.
More general, the hardware clock driver must provide solutions for:
PTP_HW_INIT(increment, addend)
),PTP_SET_CLOCK(s, ns)
),PTP_SET_ADDEND(addend)
),PTP_HW_GET_TIME(pt)
).To maintain backward-compatibility this interface is auto-selected if no interface selection macro was defined. The best practice is to define the PTP_ADDEND_INTERFACE
macro to explicitly select this interface.
Additionally, the frequency of the PTP clock input and the increment must also be defined: PTP_MAIN_OSCILLATOR_FREQ_HZ
, PTP_INCREMENT_NSEC
Usually the hardware clock driver also implements further miscellaneous functionality, like the controlling of the PPS output signal.
flexptp_options_stm32f407_etherlib.h, flexptp_options_stm32h743_etherlib.h, flexptp_options_stm32h743.h, flexptp_options_tm4c1294.h
ptp_port_stm32f407_etherlib.c, ptp_port_stm32f407_lwip.c, ptp_port_stm32h743_etherlib.c, ptp_port_stm32h743_lwip.c, ptp_port_tiva_tm4c1294.c
This interface enables flexPTP to operate hardware clocks regardless of the clock's inner structure considering the clock as a black-box device. This interface is provided to extend flexPTP support to devices with hardware clocks differing from the formerly introduced one.
The interface consists of the following few methods:
PTP_HW_INIT()
),PTP_SET_CLOCK(s, ns)
),PTP_SET_TUNING(tuning)
),PTP_HW_GET_TIME(pt)
).To select this interface, defined the PTP_HLT_INTERFACE
macro.
Usually the hardware clock driver also implements further miscellaneous functionality, like the controlling of the PPS output signal.
List of definitions, part of the initial configuration, with default values. Default values are used if macros are not defined in flexptp_options.h
.
Macros controlling basic internal operation.
Macro | Default value | Description |
---|---|---|
PTP_HEARTBEAT_TICKRATE_MS | 62 | Internal core scheduler period (ms). It should be less than the half of the shortest messaging period. |
PTP_ACCURACY_LIMIT_NS | 100 | Threshold of the LOCKED state (ns) |
PTP_DEFAULT_SERVO_OFFSET_NS | 0 | Initial servo offset (ns) (can be changed in runtime) |
PTP_DEFAULT_COARSE_TRIGGER_NS | 20000000 | Coarse correction kick-in threshold (ns) (can be changed in runtime) |
Macro | Default value | Description |
---|---|---|
PTP_PORT_ID | 1 | ID of the Ethernet interface assigned to flexPTP |
Macro | Default value | Description |
---|---|---|
PTP_BMCA_LISTENING_TIMEOUT_MS | 3000 | Timeout of the LISTENING BMCA-state (ms) |
PTP_MASTER_QUALIFICATION_TIMEOUT | 4 | Timeout of PRE_MASTER state (Announce-intervals) |
PTP_ANNOUNCE_RECEIPT_TIMEOUT | 3 | Number of tolerated consecutive lost Announce messages |
Macro | Default value | Description |
---|---|---|
PTP_ENABLE_MASTER_OPERATION | 0 (disabled) | Enable/disable master operation (once disabled here CANNOT be enabled in runtime) |
PTP_FALLBACK_UTC_OFFSET | 37 | Initial UTC offset caused by the accumulated leap seconds (s) |
PTP_PDELAY_SLAVE_QUALIFICATION | 3 | Number of consecutive PDelReq-PDelResp iterations after the SLAVE is considered stable |
PTP_PDELAY_DROPOUT | PTP_PDELAY_SLAVE_QUALIFICATION | Maximum number of failed PDelReq-PDelResp cycles before the MASTER drops the SLAVE |
Macro | Default value | Description |
---|---|---|
PTP_CLOCK_PRIORITY1 | 128 | Priority 1 field |
PTP_CLOCK_PRIORITY2 | 128 | Priority 2 field |
PTP_BEST_CLOCK_CLASS | PTP_CC_DEFAULT | Best clock class (PtpClockClass) |
PTP_WORST_ACCURACY | PTP_CA_PTP_CA_UNKNOWN | Worst clock accuracy (PtpClockAccuracy) |
PTP_TIME_SOURCE | PTP_TSRC_INTERNAL_OSCILLATOR | Time source of this device (PtpTimeSource) |
Runtime configuration is done through the Settings interface (settings_interface.h).
Also, the same configuration options are available through the CLI interface.