Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.vscode/
.idea/
__pycache__/
*.egg-info/

Expand Down
10 changes: 8 additions & 2 deletions NetX/inc/u_nx_ethernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,16 @@ ethernet_message_t ethernet_create_message(uint8_t message_id, ethernet_node_t r
uint8_t ethernet_send_message(ethernet_message_t *message);

/**
* @brief Retrieves the time from PTP stack.
* @brief Retrieves the time of day from PTP stack.
* @return The UTC time
*/
NX_PTP_DATE_TIME ethernet_get_time(void);
NX_PTP_DATE_TIME ethernet_get_timeofday(void);

/**
* @brief Retrieves the time from PTP stack.
* @return The Unix epoch time
*/
NX_PTP_TIME ethernet_get_time(void);

// clang-format on
#endif /* u_nx_ethernet.h */
12 changes: 12 additions & 0 deletions NetX/inc/u_rtc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef RTC_H
#define RTC_H

#include "nxd_ptp_client.h"
#include "nx_api.h"

UINT nx_ptp_client_hard_clock_callback(NX_PTP_CLIENT *client_ptr,
UINT operation, NX_PTP_TIME *time_ptr,
NX_PACKET *packet_ptr,
VOID *callback_data);

#endif // RTC_H
4 changes: 2 additions & 2 deletions NetX/src/nxd_ptp_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -6152,6 +6152,6 @@ LONG ns;
/* return result */
time_ptr -> second_high = sec_hi;
time_ptr -> second_low = sec_lo;
time_ptr -> nanosecond = ns;
time_ptr -> nanosecond = ns;
}
// clang-format on
// clang-format on
14 changes: 12 additions & 2 deletions NetX/src/u_nx_ethernet.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// clang-format off
#include "u_nx_ethernet.h"
#include "u_rtc.h"
#include "nx_stm32_eth_driver.h"
#include "nxd_ptp_client.h"
#include "u_nx_debug.h"
Expand Down Expand Up @@ -227,7 +228,7 @@ uint8_t ethernet_init(ethernet_node_t node_id, DriverFunction driver, OnRecieve
/* Create the PTP client instance */
status = nx_ptp_client_create(&device.ptp_client, &device.ip, 0, &device.packet_pool,
_PTP_THREAD_PRIORITY, (UCHAR *)&device.ptp_stack, sizeof(device.ptp_stack),
_nx_ptp_client_soft_clock_callback, NX_NULL);
nx_ptp_client_hard_clock_callback, NX_NULL);
if(status != NX_SUCCESS) {
PRINTLN_ERROR("Failed to create PTP client (Status: %d/%s).", status, nx_status_toString(status));
return status;
Expand Down Expand Up @@ -392,7 +393,7 @@ uint8_t ethernet_send_message(ethernet_message_t *message) {
return U_SUCCESS;
}

NX_PTP_DATE_TIME ethernet_get_time(void) {
NX_PTP_DATE_TIME ethernet_get_timeofday(void) {
NX_PTP_TIME tm;
NX_PTP_DATE_TIME date;
/* read the PTP clock */
Expand All @@ -404,4 +405,13 @@ NX_PTP_DATE_TIME ethernet_get_time(void) {
return date;
}

NX_PTP_TIME ethernet_get_time(void) {
NX_PTP_TIME tm;

/* read the PTP clock */
nx_ptp_client_time_get(&device.ptp_client, &tm);

return tm;
}

// clang-format on
163 changes: 163 additions & 0 deletions NetX/src/u_rtc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#include "nxd_ptp_client.h"
#include "u_rtc.h"
#include "stm32h5xx_hal.h"
#include "u_tx_debug.h"
#include "tx_api.h"

/// This file implements the PTP client callback to manage time for a STM32H563.
/// This is where the interface between the PTP client and the timebase is.
/// This was written using RM0481 and partially using source code from UM3131.
///
/// The timebase for the clock used is listed as clk_ptp_ref_i.
/// The PTP Offload feature is NOT utilized because it is very half-baked.
/// Instead we simply use the internal clock reference and a userspace UDP impl.
///
/// Tuning: The status of this operation can be found by using eth_ptp_pps_out.
/// There may be some register setup to enable PPS.
///
/// Docs: This mostly follows the procedure in page RM0481 2792 57.9.9
/// This uses coarse timestamping digital rollover mode.
///
/// Requirements:
/// 1 billion must be divisible by the frequency value of Pll1_Q.
/// This will turn on Pll1_Q if it is not on already.
///
/// Future improvements:
/// - Use fine update mode to reduce jitter
/// - Use binary rollover mode for sub-ns precision (lol)
///

extern ETH_HandleTypeDef heth;

#define PTP_UTC_OFFSET 0 // UTC 0

UINT nx_ptp_client_hard_clock_callback(NX_PTP_CLIENT *client_ptr,
UINT operation, NX_PTP_TIME *time_ptr,
NX_PACKET *packet_ptr,
VOID *callback_data)
{
TX_INTERRUPT_SAVE_AREA
switch (operation) {
case NX_PTP_CLIENT_CLOCK_INIT:
TX_DISABLE

// see 57.9.9

// Mask the Timestamp Trigger interrupt
CLEAR_BIT(heth.Instance->MACIER, ETH_MACIER_TSIE);
SET_BIT(heth.Instance->MACTSCR, ETH_MACTSCR_TSENA);

SET_BIT(heth.Instance->MACTSCR,
ETH_MACTSCR_TSCTRLSSR); // 1 ns

// each step is 1ns, with a clock of clk_ptp_ref_i
// clk_ptp_ref_i comes from pll1_q_clk (eth clock) (pg 456)
// this cool API gives us the frequency (in hz)

// for some reason we need to enable pll1q output?
SET_BIT(RCC->PLL1CFGR, RCC_PLL1CFGR_PLL1QEN);

PLL1_ClocksTypeDef pll1;
HAL_RCCEx_GetPLL1ClockFreq(&pll1);
if (1000000000 % pll1.PLL1_Q_Frequency != 0) {
PRINTLN_ERROR(
"NOT PERFEECT DIVISOR PTP TIME WILL BE OFF -> CHECK PLL1Q!");
}
uint32_t period_ns = 1000000000 / pll1.PLL1_Q_Frequency;
MODIFY_REG(heth.Instance->MACSSIR,
ETH_MACMACSSIR_SNSINC,
period_ns << ETH_MACMACSSIR_SSINC_Pos);

// placeholder just to get the clock ticking
WRITE_REG(heth.Instance->MACSTNUR, 0);

// September 9th, 2001
WRITE_REG(heth.Instance->MACSTSUR, 1000000000);

SET_BIT(heth.Instance->MACTSCR, ETH_MACTSCR_TSINIT);

while (READ_BIT(heth.Instance->MACTSCR,
ETH_MACTSCR_TSINIT)) {
}
// clear the seconds register now so we dont need to do it for a subsecond update
CLEAR_REG(heth.Instance->MACSTSUR);

TX_RESTORE

break;
case NX_PTP_CLIENT_CLOCK_SET:
/// A large jump in time
TX_DISABLE

// use overwrite, not add
WRITE_REG(heth.Instance->MACSTNUR,
time_ptr->nanosecond);

// WARNING travelers of future: this code suffers from the year 2106 problem
// Use seconds_high to account for this, but note the silicon also has this issue
WRITE_REG(heth.Instance->MACSTSUR,
time_ptr->second_low);

SET_BIT(heth.Instance->MACTSCR, ETH_MACTSCR_TSINIT);

while (READ_BIT(heth.Instance->MACTSCR,
ETH_MACTSCR_TSINIT)) {
}
// clear the seconds register now so we dont need to do it for a subsecond update
CLEAR_REG(heth.Instance->MACSTSUR);

TX_RESTORE

break;
case NX_PTP_CLIENT_CLOCK_PACKET_TS_EXTRACT: // FALL THROUGH
case NX_PTP_CLIENT_CLOCK_GET:
/// Retrieve time, usually for packet timestamping
TX_DISABLE

time_ptr->nanosecond = READ_REG(heth.Instance->MACSTNR);
time_ptr->second_low = READ_REG(heth.Instance->MACSTSR);
time_ptr->second_high = 0;
TX_RESTORE
break;
case NX_PTP_CLIENT_CLOCK_ADJUST:
/// A small adjustment in time (<1 second)
TX_DISABLE
// use add, not overwrite.
// MACTSUR must be 0 at this point, not wasting CPU time though
Comment thread
jr1221 marked this conversation as resolved.
if (time_ptr->nanosecond >= 0) {
// this will automatically clear the ADDSUB so we add
WRITE_REG(heth.Instance->MACSTNUR,
time_ptr->nanosecond);
} else {
// take complement starting from one million
uint32_t complement =
1000000000 - abs(time_ptr->nanosecond);
// with ADDSUB defined it will subtract, but complement must be taken
WRITE_REG(heth.Instance->MACSTNUR, complement);
SET_BIT(heth.Instance->MACSTNUR,
Comment thread
jr1221 marked this conversation as resolved.
ETH_MACSTNUR_ADDSUB);
}

SET_BIT(heth.Instance->MACTSCR, ETH_MACTSCR_TSUPDT);

TX_RESTORE
break;
case NX_PTP_CLIENT_CLOCK_PACKET_TS_PREPARE:
/// Push a packet with a timestamp

time_ptr->nanosecond = READ_REG(heth.Instance->MACSTNR);
time_ptr->second_low = READ_REG(heth.Instance->MACSTSR);
time_ptr->second_high = 0;

nx_ptp_client_packet_timestamp_notify(
client_ptr, packet_ptr, time_ptr);
break;
case NX_PTP_CLIENT_CLOCK_SOFT_TIMER_UPDATE: // do nothing
break;
default:
PRINTLN_ERROR("How Did We Get Here? (rtc)");
break;
}

return NX_SUCCESS;
}
Loading