📄 enet_ptpd.c
字号:
//
//*****************************************************************************
int
main(void)
{
unsigned long ulUser0, ulUser1;
unsigned char pucMACArray[8];
//
// Set the system clocking as defined above in SYSDIV and CLKUSE.
//
SysCtlClockSet(SYSDIV | CLKUSE | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ);
//
// Set up for debug output to the UART.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTStdioInit(0);
//
// Initialize the OLED display.
//
RIT128x96x4Init(1000000);
RIT128x96x4StringDraw("PTPd with lwIP", 24, 0, 15);
//
// Enable and Reset the Ethernet Controller.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
IntPrioritySet(INT_ETH, ETHERNET_INT_PRIORITY);
//
// Enable Port F for Ethernet LEDs.
// LED0 Bit 3 Output
// LED1 Bit 2 Output
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3, GPIO_DIR_MODE_HW);
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3,
GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
//
// Configure the defined PPS GPIO for output.
//
SysCtlPeripheralEnable(PPS_GPIO_PERIPHERAL);
GPIOPinTypeGPIOOutput(PPS_GPIO_BASE, PPS_GPIO_PIN);
GPIOPinWrite(PPS_GPIO_BASE, PPS_GPIO_PIN, 0);
//
// Configure SysTick for a periodic interrupt in PTPd system.
//
ptpd_systick_init();
//
// Enable processor interrupts.
//
IntMasterEnable();
//
// Configure the hardware MAC address for Ethernet Controller filtering of
// incoming packets.
//
// For the Luminary Micro Evaluation Kits, the MAC address will be stored
// in the non-volatile USER0 and USER1 registers. These registers can be
// read using the FlashUserGet function, as illustrated below.
//
FlashUserGet(&ulUser0, &ulUser1);
if((ulUser0 == 0xffffffff) || (ulUser1 == 0xffffffff))
{
//
// We should never get here. This is an error if the MAC address has
// not been programmed into the device. Exit the program.
//
RIT128x96x4StringDraw("MAC Address", 0, 16, 15);
RIT128x96x4StringDraw("Not Programmed!", 0, 24, 15);
DiagExit(2);
}
//
// Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC
// address needed to program the hardware registers, then program the MAC
// address into the Ethernet Controller registers.
//
pucMACArray[0] = ((ulUser0 >> 0) & 0xff);
pucMACArray[1] = ((ulUser0 >> 8) & 0xff);
pucMACArray[2] = ((ulUser0 >> 16) & 0xff);
pucMACArray[3] = ((ulUser1 >> 0) & 0xff);
pucMACArray[4] = ((ulUser1 >> 8) & 0xff);
pucMACArray[5] = ((ulUser1 >> 16) & 0xff);
//
// Program the hardware with it's MAC address (for filtering).
//
EthernetMACAddrSet(ETH_BASE, pucMACArray);
//
// Initialize the file system.
//
fs_init();
//
// Initialize the Random Number Generator.
//
RandomSeed();
//
// Initialize all of the lwIP code, as needed, which will also initialize
// the low-level Ethernet code.
//
lwip_init();
//
// Initialize a sample web server application.
//
httpd_init();
//
// Main Application Loop (for systems with no RTOS). Run every SYSTICK.
//
while(true)
{
//
// Wait for an event to occur.
//
while(!(g_ulFlags & MODE_FLAG_MASK))
{
}
//
// Check if a SYSTICK has occurred.
//
if(HWREGBITW(&g_ulFlags, FLAG_SYSTICK))
{
//
// Clear the SysTick interrupt flag.
//
HWREGBITW(&g_ulFlags, FLAG_SYSTICK) = 0;
//
// Run the Luminary lwIP system tick.
//
lwip_tick(SYSTICKMS);
//
// Clear PPS output when needed and display time of day.
//
if(HWREGBITW(&g_ulFlags, FLAG_PPSOFF))
{
//
// Negate the PPS output.
//
GPIOPinWrite(PPS_GPIO_BASE, PPS_GPIO_PIN, 0);
//
// Indicate that we have negated the PPS output.
//
HWREGBITW(&g_ulFlags, FLAG_PPSOFF) = 0;
//
// Display Date and Time.
//
DisplayDate(g_ulSystemTimeSeconds, 48);
DisplayTime(g_ulSystemTimeSeconds, 56);
}
//
// Setup to disable the PPS output on the next pass.
//
if(HWREGBITW(&g_ulFlags, FLAG_PPSOUT))
{
//
// Setup to turn off the PPS output.
//
HWREGBITW(&g_ulFlags, FLAG_PPSOUT) = 0;
HWREGBITW(&g_ulFlags, FLAG_PPSOFF) = 1;
}
}
//
// Check if an RX Packet was received.
//
if(HWREGBITW(&g_ulFlags, FLAG_RXPKT))
{
//
// Clear the Rx Packet interrupt flag.
//
HWREGBITW(&g_ulFlags, FLAG_RXPKT) = 0;
//
// Run the Luminary lwIP system tick, but with no time, to indicate
// an RX or TX packet has occurred.
//
lwip_tick(0);
}
//
// Check if a TX Packet was sent.
//
if(HWREGBITW(&g_ulFlags, FLAG_TXPKT))
{
//
// Clear the Tx Packet interrupt flag.
//
HWREGBITW(&g_ulFlags, FLAG_TXPKT) = 0;
//
// Run the Luminary lwIP system tick, but with no time, to indicate
// an RX or TX packet has occurred.
//
lwip_tick(0);
//
// Enable Ethernet TX Packet Interrupts.
//
EthernetIntEnable(ETH_BASE, ETH_INT_TX);
}
//
// If IP address has been assigned, initialize the PTPD software (if
// not already initialized).
//
if(HWREGBITW(&g_ulFlags, FLAG_IPADDR) &&
!HWREGBITW(&g_ulFlags, FLAG_PTPDINIT))
{
ptpd_init();
HWREGBITW(&g_ulFlags, FLAG_PTPDINIT) = 1;
}
//
// If PTPD software has been initialized, run the ptpd tick.
//
if(HWREGBITW(&g_ulFlags, FLAG_PTPDINIT))
{
ptpd_tick();
}
}
}
//*****************************************************************************
//
// The following set of functions are LMI Board/Chip Specific implementations
// of functions required by PTPd software. Prototypes are defined in ptpd.h,
// or one of its included files.
//
//*****************************************************************************
//*****************************************************************************
//
// Display Statistics. For now, do nothing, but this could be used to either
// update a web page, send data to the serial port, or to the OLED display.
//
// Refer to the ptpd software "src/dep/sys.c" for example code.
//
//*****************************************************************************
void
displayStats(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
}
//*****************************************************************************
//
// This function returns the local time (in PTPd internal time format). This
// time is maintained by the SysTick interrupt.
//
// Note: It is very important to ensure that we detect cases where the system
// tick rolls over during this function. If we don't do this, there is a race
// condition that will cause the reported time to be off by a second or so
// once in a blue moon. This, in turn, causes large perturbations in the
// 1588 time controller resulting in large deltas for many seconds as the
// controller tries to compensate.
//
//*****************************************************************************
void
getTime(TimeInternal *time)
{
unsigned long ulTime1;
unsigned long ulTime2;
unsigned long ulSeconds;
unsigned long ulPeriod;
unsigned long ulNanoseconds;
//
// We read the SysTick value twice, sandwiching taking snapshots of
// the seconds, nanoseconds and period values. If the second SysTick read
// gives us a higher number than the first read, we know that it wrapped
// somewhere between the two reads so our seconds and nanoseconds
// snapshots are suspect. If this occurs, we go round again. Note that
// it is not sufficient merely to read the values with interrupts disabled
// since the SysTick counter keeps counting regardless of whether or not
// the wrap interrupt has been serviced.
//
do
{
ulTime1 = SysTickValueGet();
ulSeconds = g_ulSystemTimeSeconds;
ulNanoseconds = g_ulSystemTimeNanoSeconds;
ulPeriod = SysTickPeriodGet();
ulTime2 = SysTickValueGet();
#ifdef DEBUG
//
// In debug builds, keep track of the number of times this function was
// called just as the SysTick wrapped.
//
if(ulTime2 > ulTime1)
{
g_ulSysTickWrapDetect++;
g_ulSysTickWrapTime = ulSeconds;
}
#endif
}
while(ulTime2 > ulTime1);
//
// Fill in the seconds field from the snapshot we just took.
//
time->seconds = ulSeconds;
//
// Fill in the nanoseconds field from the snapshots.
//
time->nanoseconds = (ulNanoseconds + (ulPeriod - ulTime2) * TICKNS);
//
// Adjust for any case where we accumulate more than 1 second's worth of
// nanoseconds.
//
if(time->nanoseconds >= 1000000000)
{
#ifdef DEBUG
g_ulGetTimeWrapCount++;
#endif
time->seconds++;
time->nanoseconds -= 1000000000;
}
}
//*****************************************************************************
//
// This function will set the local time (provided in PTPd internal time
// format). This time is maintained by the SysTick interrupt.
//
//*****************************************************************************
void
setTime(TimeInternal *time)
{
sys_prot_t sProt;
//
// Update the System Tick Handler time values from the given PTPd time
// (fine-tuning is handled in the System Tick handler). We need to update
// these variables with interrupts disabled since the update must be
// atomic.
//
#ifdef DEBUG
UARTprintf("Setting time %d.%09d\n", time->seconds, time->nanoseconds);
#endif
sProt = sys_arch_protect();
g_ulSystemTimeSeconds = time->seconds;
g_ulSystemTimeNanoSeconds = time->nanoseconds;
sys_arch_unprotect(sProt);
}
//*****************************************************************************
//
// Get the RX Timestamp. This is called from the lwIP low_level_input function
// when configured to include PTPd support.
//
//*****************************************************************************
void
getRxTime(TimeInternal *psRxTime)
{
//
// Get the current IEEE1588 time.
//
getTime(psRxTime);
return;
}
//*****************************************************************************
//
// This function returns a random number, using the functions in random.c.
//
//*****************************************************************************
UInteger16
getRand(UInteger32 *seed)
{
unsigned long ulTemp;
UInteger16 uiTemp;
//
// Re-seed the random number generator.
//
RandomAddEntropy(*seed);
RandomSeed();
//
// Get a random number and return a 16-bit, truncated version.
//
ulTemp = RandomNumber();
uiTemp = (UInteger16)(ulTemp & 0xFFFF);
return(uiTemp);
}
//*****************************************************************************
//
// Based on the value (adj) provided by the PTPd Clock Servo routine, this
// function will adjust the SysTick periodic interval to allow fine-tuning of
// the PTP Clock.
//
//*****************************************************************************
Boolean
adjFreq(Integer32 adj)
{
unsigned long ulTemp;
//
// Check for max/min value of adjustment.
//
if(adj > ADJ_MAX)
{
adj = ADJ_MAX;
}
else if(adj < -ADJ_MAX)
{
adj = -ADJ_MAX;
}
//
// Convert input to nanoseconds / systick.
//
adj = adj / SYSTICKHZ;
//
// Get the nominal tick reload value and convert to nano seconds.
//
ulTemp = (SysCtlClockGet() / SYSTICKHZ) * TICKNS;
//
// Factor in the adjustment.
//
ulTemp -= adj;
//
// Get a modulo count of nanoseconds for fine tuning.
//
g_ulSystemTickHigh = ulTemp % TICKNS;
//
// Set the reload value.
//
g_ulNewSystemTickReload = ulTemp / TICKNS;
//
// Return.
//
return(TRUE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -