Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IEEE1588 improvements for PTP #64

Open
wants to merge 7 commits into
base: ieee1588-2
Choose a base branch
from
10 changes: 0 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ files provided with the lwIP release.
6. [`MDNS`](#mdns)
7. [`DNSClient`](#dnsclient)
8. [Print utilities](#print-utilities)
9. [`IPAddress` operators](#ipaddress-operators)
3. [How to run](#how-to-run)
4. [How to write data to connections](#how-to-write-data-to-connections)
1. [Write immediacy](#write-immediacy)
Expand Down Expand Up @@ -394,15 +393,6 @@ interface so that it is easy to print `Printable` objects to `stdout` or
`stderr` without having to worry about buffering and the need to flush any
output before printing a `Printable` directly to, say, `Serial`.

### `IPAddress` operators

The core library version of `IPAddress` is missing `==` and `!=` operators that
can compare `const IPAddress` values. Provided in this library are these two
operators. They are declared as follows in the usual namespace:

1. `bool operator==(const IPAddress &a, const IPAddress &b);`
2. `bool operator!=(const IPAddress &a, const IPAddress &b);`

## How to run

This library works with both PlatformIO and Arduino. To use it with Arduino,
Expand Down
64 changes: 64 additions & 0 deletions examples/PPSIn/PPSIn.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: (c) 2023 Jens Schleusner <[email protected]>
// SPDX-License-Identifier: MIT

// PPSOut generates a Pulse per Second using the IEEE1588-Timer on Pin 24
// We read the pulse back on channels 0 and 2 to measure the timer delay
// Connect Oscilloscope to Pin 24
// Connect Pins 24(out), 15(in), 35(in)
//
// This file is part of the QNEthernet library.

#include <QNEthernet.h>
using namespace qindesign::network;

void setup() {

Serial.begin(2000000);
Serial.println("Setup EthernetIEEE1588");

qindesign::network::Ethernet.begin();
qindesign::network::EthernetIEEE1588.begin();

//PPS-Out on Channel 1
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_12 = 6; //ENET_1588_EVENT1_OUT, IOMUX: ALT6, Teensy Pin: 24
EthernetIEEE1588.setChannelCompareValue(1, 0); //Compare at counter value 0
EthernetIEEE1588.setChannelMode(1, qindesign::network::EthernetIEEE1588.TimerChannelModes::kPulseHighOnCompare); //enable Channel0 positive pulse
EthernetIEEE1588.setChannelOutputPulseWidth(1, 25); //Generate a Pulse width of 25 25MHz clock cycles (1us)

//PPS-IN
attachInterruptVector(IRQ_ENET_TIMER, interrupt_1588_timer); //Configure Interrupt Handler
NVIC_ENABLE_IRQ(IRQ_ENET_TIMER); //Enable Interrupt Handling

//PPS-In on Channel 2
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 4; //ENET_1588_EVENT2_IN, IOMUX: ALT4, Teensy Pin: 15
EthernetIEEE1588.setChannelMode(2, qindesign::network::EthernetIEEE1588.TimerChannelModes::kCaptureOnRising); //enable Channel2 rising edge trigger
EthernetIEEE1588.setChannelInterruptEnable(2, true); //Configure Interrupt generation

//PPS-In on Channel 0
IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_12 = 3; //ENET_1588_EVENT0_IN, IOMUX: ALT3, Teensy Pin: 35
IOMUXC_ENET0_TIMER_SELECT_INPUT = 0b10; // route B1_12 to 1588 timer (pg 796, Rev. 3)
EthernetIEEE1588.setChannelMode(0, qindesign::network::EthernetIEEE1588.TimerChannelModes::kCaptureOnFalling);
EthernetIEEE1588.setChannelInterruptEnable(0, true);


Serial.printf("TCSR Register state: ENET_TCSR0 %08" PRIX32 "h ENET_TCSR1 %08" PRIX32 "h ENET_TCSR2 %08" PRIX32 "h\n", ENET_TCSR0, ENET_TCSR1, ENET_TCSR2); // (pg 2247, Rev. 3)
}

void loop() {
// put your main code here, to run repeatedly:

}

static void interrupt_1588_timer() {
uint32_t t;
if(EthernetIEEE1588.getAndClearChannelStatus(0)){
EthernetIEEE1588.getChannelCompareValue(0,t);
Serial.printf("Timer0 Falling Edge: %d\n\n", t);
}
if (EthernetIEEE1588.getAndClearChannelStatus(2)) {
EthernetIEEE1588.getChannelCompareValue(2,t);
Serial.printf("Timer2 Rising Edge: %d\n", t);
}
asm("dsb"); // allow write to complete so the interrupt doesn't fire twice
}

41 changes: 41 additions & 0 deletions examples/PPSOut/PPSOut.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: (c) 2023 Jens Schleusner <[email protected]>
// SPDX-License-Identifier: MIT

// PPSOut generates a Pulse per Second using the IEEE1588-Timer
// Connect Oscilloscope to Pins 14,24,34
// Connect LED to Pin 14
//
// This file is part of the QNEthernet library.

#include <QNEthernet.h>
using namespace qindesign::network;

void setup() {

Serial.begin(2000000);
Serial.println("Setup EthernetIEEE1588");

qindesign::network::Ethernet.begin();
qindesign::network::EthernetIEEE1588.begin();

IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_13 = 3; //ENET_1588_EVENT0_OUT, IOMUX: ALT3, Teensy Pin: 34
EthernetIEEE1588.setChannelCompareValue(0, 0); //Compare at counter value 0
EthernetIEEE1588.setChannelMode(0, qindesign::network::EthernetIEEE1588.TimerChannelModes::kPulseHighOnCompare); //enable Channel0 positive pulse
EthernetIEEE1588.setChannelOutputPulseWidth(0, 25); //Generate a Pulse width of 25 25MHz clock cycles (1us)

IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_12 = 6; //ENET_1588_EVENT1_OUT, IOMUX: ALT6, Teensy Pin: 24
EthernetIEEE1588.setChannelCompareValue(1, 1000); //Compare at counter value 1000
EthernetIEEE1588.setChannelOutputPulseWidth(1, 10); //Generate a Pulse width of 10 25MHz clock cycles (400ns)
EthernetIEEE1588.setChannelMode(1, qindesign::network::EthernetIEEE1588.TimerChannelModes::kPulseLowOnCompare); //enable Channel1 negative pulse

IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_02 = 4; //ENET_1588_EVENT2_OUT, IOMUX: ALT4, Teensy Pin: 14
EthernetIEEE1588.setChannelCompareValue(2, 500 * 1000 * 1000); //Compare at counter 500ms
EthernetIEEE1588.setChannelMode(2, qindesign::network::EthernetIEEE1588.TimerChannelModes::kClearOnCompareSetOnOverflow); //enable Channel2 for 50/50 On-Off Signal

Serial.printf("TCSR Register state: ENET_TCSR0 %08" PRIX32 "h ENET_TCSR1 %08" PRIX32 "h ENET_TCSR2 %08" PRIX32 "h\n", ENET_TCSR0, ENET_TCSR1, ENET_TCSR2); // (pg 2247, Rev. 3)
}

void loop() {
// put your main code here, to run repeatedly:

}
46 changes: 46 additions & 0 deletions examples/TimerAdjustment/TimerAdjustment.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: (c) 2023 Jens Schleusner <[email protected]>
// SPDX-License-Identifier: MIT
//
// This file is part of the QNEthernet library.

#include <QNEthernet.h>
using namespace qindesign::network;

IntervalTimer myTimer;

int adjustment = 0;
timespec tmlast;

void setup() {

Serial.begin(2000000);
Serial.println("Setup EthernetIEEE1588");

qindesign::network::Ethernet.begin();
qindesign::network::EthernetIEEE1588.begin();

myTimer.begin(timerInterrupt, 1000000);
EthernetIEEE1588.readTimer(tmlast);

}

void timerInterrupt() {
timespec tm;
EthernetIEEE1588.readTimer(tm);//read current timer value
int lastadjustment=adjustment;
adjustment += 100; //increase timer spped by 100ns per second
EthernetIEEE1588.adjustFreq(adjustment);

int diff = (static_cast<int64_t>(tm.tv_sec) - static_cast<int64_t>(tmlast.tv_sec)) * (1000 * 1000 * 1000) + (static_cast<int64_t>(tm.tv_nsec) - static_cast<int64_t>(tmlast.tv_nsec));
diff -= (1000 * 1000 * 1000);

Serial.printf("Adjustment:%d nsps ATINC %08" PRIX32 "h ATCOR %d Diff %d\n",lastadjustment,ENET_ATINC,ENET_ATCOR,diff);
//Serial.printf("%d %d\n", lastadjustment, diff);

tmlast = tm;

}

void loop() {

}
1 change: 0 additions & 1 deletion src/QNEthernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#include "lwip/opt.h"
#include "lwip_t41.h"
#include "util/PrintUtils.h"
#include "util/ip_tools.h"

namespace qindesign {
namespace network {
Expand Down
17 changes: 14 additions & 3 deletions src/QNEthernetIEEE1588.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ bool EthernetIEEE1588Class::writeTimer(const timespec &t) const {
return enet_ieee1588_write_timer(&t);
}

bool EthernetIEEE1588Class::offsetTimer(int64_t ns) const{
return enet_ieee1588_offset_timer(ns);
}

void EthernetIEEE1588Class::timestampNextFrame() const {
enet_ieee1588_timestamp_next_frame();
}
Expand All @@ -47,7 +51,7 @@ bool EthernetIEEE1588Class::adjustTimer(uint32_t corrInc,
return enet_ieee1588_adjust_timer(corrInc, corrPeriod);
}

bool EthernetIEEE1588Class::adjustFreq(int nsps) const {
bool EthernetIEEE1588Class::adjustFreq(double nsps) const {
return enet_ieee1588_adjust_freq(nsps);
}

Expand All @@ -57,10 +61,8 @@ bool EthernetIEEE1588Class::setChannelMode(int channel,
}

bool EthernetIEEE1588Class::setChannelOutputPulseWidth(int channel,
TimerChannelModes mode,
int pulseWidth) const {
return enet_ieee1588_set_channel_output_pulse_width(channel,
static_cast<int>(mode),
pulseWidth);
}

Expand All @@ -69,10 +71,19 @@ bool EthernetIEEE1588Class::setChannelCompareValue(int channel,
return enet_ieee1588_set_channel_compare_value(channel, value);
}

bool EthernetIEEE1588Class::getChannelCompareValue(int channel,
uint32_t &value) const {
return enet_ieee1588_get_channel_compare_value(channel, &value);
}

bool EthernetIEEE1588Class::getAndClearChannelStatus(int channel) const {
return enet_ieee1588_get_and_clear_channel_status(channel);
}

bool EthernetIEEE1588Class::setChannelInterruptEnable(int channel, bool enable) const {
return enet_ieee1588_set_channel_interrupt_enable(channel, enable);
}

EthernetIEEE1588Class::operator bool() const {
return enet_ieee1588_is_enabled();
}
Expand Down
18 changes: 13 additions & 5 deletions src/QNEthernetIEEE1588.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class EthernetIEEE1588Class final {
// Writes the current IEEE 1588 timer value. This returns whether successful.
bool writeTimer(const timespec &t) const;

// Adds an offset to the current IEEE 1588 timer value. This returns whether successful.
bool offsetTimer(int64_t ns) const;

// Tells the driver to timestamp the next transmitted frame. This should be
// called before functions like `EthernetUDP::endPacket()`,
// `EthernetUDP::send()`, and any of the `EthernetFrame` send functions.
Expand All @@ -75,7 +78,7 @@ class EthernetIEEE1588Class final {
// Adjusts the correction frequency in nanoseconds per second. To slow down
// the timer, specify a negative value. To speed it up, specify a positive
// value. This returns whether successful.
bool adjustFreq(int nsps) const;
bool adjustFreq(double nsps) const;

// Sets the channel mode for the given channel. This does not set the output
// compare pulse modes. This returns whether successful.
Expand All @@ -84,20 +87,25 @@ class EthernetIEEE1588Class final {
// output compare pulse modes.
bool setChannelMode(int channel, TimerChannelModes mode) const;

// Sets the output compare pulse mode and pulse width for the given channel.
// The pulse width must be in the range 1-32. This only sets the output
// compare pulse modes. This returns whether successful.
// Sets the output compare pulse width for the given channel.
// The pulse width must be in the range 1-32. This returns whether successful.
bool setChannelOutputPulseWidth(int channel,
TimerChannelModes mode,
int pulseWidth) const;

// Sets the channel compare value. This returns whether successful.
bool setChannelCompareValue(int channel, uint32_t value) const;

// Gets the channel compare value. This returns whether successful.
bool getChannelCompareValue(int channel, uint32_t &value) const;

// Retrieves and then clears the status for the given channel. This will
// return false for an unknown channel.
bool getAndClearChannelStatus(int channel) const;

// Enables or disables timer interrupt generation for a channel. This will
// return false for an unknown channel.
bool setChannelInterruptEnable(int channel, bool enable) const;

// Tests if the IEEE 1588 timer has been started.
operator bool() const;

Expand Down
Loading