/** * * This function sets the alarm value of RTC device. * * @param InstancePtr is a pointer to the XRtcPsu instance * @param Alarm is the desired alarm time for RTC. * @param Periodic says whether the alarm need to set at periodic * Intervals or a one-time alarm. * * @return None. * * @note None. * *****************************************************************************/ void XRtcPsu_SetAlarm(XRtcPsu *InstancePtr, u32 Alarm, u32 Periodic) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(Alarm != 0U); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid((Alarm - XRtcPsu_GetCurrentTime(InstancePtr)) > (u32)0); XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr+XRTC_ALRM_OFFSET, Alarm); if(Periodic != 0U) { InstancePtr->IsPeriodicAlarm = 1U; InstancePtr->PeriodicAlarmTime = Alarm - XRtcPsu_GetCurrentTime(InstancePtr); } }
/** * * This function does a minimal Alarm test on the XRtcPsu device in polled mode. * * This function sets one time alarm from the current time to a specified time. * * @param DeviceId is the unique device id from hardware build. * * @return XST_SUCCESS if successful, XST_FAILURE if unsuccessful * * @note * This function polls the RTC, it may hang if the hardware is not * working correctly. * ****************************************************************************/ int RtcPsuAlarmPolledExample(u16 DeviceId) { int Status; XRtcPsu_Config *Config; u32 CurrentTime, AlarmTime; XRtcPsu_DT dt0; /* * Initialize the RTC driver so that it's ready to use. * Look up the configuration in the config table, then initialize it. */ Config = XRtcPsu_LookupConfig(DeviceId); if (NULL == Config) { return XST_FAILURE; } Status = XRtcPsu_CfgInitialize(&Rtc_Psu, Config, Config->BaseAddr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* Check hardware build. */ Status = XRtcPsu_SelfTest(&Rtc_Psu); if (Status != XST_SUCCESS) { return XST_FAILURE; } xil_printf("\n\rDay Convention : 0-Fri, 1-Sat, 2-Sun, 3-Mon, 4-Tue, 5-Wed, 6-Thur\n\r"); xil_printf("Current RTC time is..\n\r"); CurrentTime = XRtcPsu_GetCurrentTime(&Rtc_Psu); XRtcPsu_SecToDateTime(CurrentTime,&dt0); xil_printf("YEAR:MM:DD HR:MM:SS \t %04d:%02d:%02d %02d:%02d:%02d\t Day = %d\n\r", dt0.Year,dt0.Month,dt0.Day,dt0.Hour,dt0.Min,dt0.Sec,dt0.WeekDay); CurrentTime = XRtcPsu_GetCurrentTime(&Rtc_Psu); AlarmTime = CurrentTime + ALARM_PERIOD; XRtcPsu_SetAlarm(&Rtc_Psu,AlarmTime,0U); /* * If Alarm was not generated, then the processor goes into an infinite * loop. This represents a failure case of alarm example. */ while (!XRtcPsu_IsAlarmEventGenerated(&Rtc_Psu)); xil_printf("Alarm generated.\n\r"); return XST_SUCCESS; }
/** * * This function calculates the calibration value depending on the actual * realworld time and also helps in deriving new calibration value if * the user wishes to change his oscillator frequency.TimeReal is generally the * internet time with EPOCH time as reference i.e.,1/1/1970 1st second. * But this RTC driver assumes start time from 1/1/2000 1st second. Hence,if * the user maps the internet time InternetTimeInSecs, then he has to use * XRtcPsu_SecToDateTime(InternetTimeInSecs,&InternetTime), * TimeReal = XRtcPsu_DateTimeToSec(InternetTime) * consecutively to arrive at TimeReal value. * * @param InstancePtr is a pointer to the XRtcPsu instance. * @param TimeReal is the actual realworld time generally an * network time / Internet time in seconds. * * @param CrystalOscFreq is the Oscillator new frequency. Say, If the user * is going with the typical 32768Hz, then he inputs the same * frequency value. * * @return None. * * @note After Calculating the calibration register, user / application has to * call again CfgInitialize API to bring the new calibration into effect. * *****************************************************************************/ void XRtcPsu_CalculateCalibration(XRtcPsu *InstancePtr,u32 TimeReal, u32 CrystalOscFreq) { u32 ReadTime, SetTime; u32 Cprev,Fprev,Cnew,Fnew,Xf,Calibration; Xil_AssertVoid(TimeReal != 0U); Xil_AssertVoid(CrystalOscFreq != 0U); ReadTime = XRtcPsu_GetCurrentTime(InstancePtr); SetTime = XRtcPsu_GetLastSetTime(InstancePtr); Calibration = XRtcPsu_GetCalibration(InstancePtr); /* * When board gets reseted, Calibration value is zero * and Last setTime will be marked as 1st second. This implies * CurrentTime to be in few seconds say something in tens. TimeReal will * be huge, say something in thousands. So to prevent such reset case, Cnew * and Fnew will not be calculated. */ if((Calibration == 0U) || (CrystalOscFreq != InstancePtr->OscillatorFreq)) { Cnew = CrystalOscFreq - (u32)1; Fnew = 0U; } else { Cprev = Calibration & XRTC_CALIB_RD_FRACTN_DATA_MASK; Fprev = Calibration & XRTC_CALIB_RD_MAX_TCK_MASK; Xf = ((ReadTime - SetTime) * ((Cprev+1U) + ((Fprev+1U)/16U))) / (TimeReal - SetTime); Cnew = (u32)(Xf) - (u32)1; Fnew = XRtcPsu_RoundOff((Xf - Cnew) * 16U) - (u32)1; } Calibration = (Fnew << XRTC_CALIB_RD_FRACTN_DATA_SHIFT) + Cnew; Calibration |= XRTC_CALIB_RD_FRACTN_EN_MASK; InstancePtr->CalibrationValue = Calibration; InstancePtr->OscillatorFreq = CrystalOscFreq; }
/** * * This function is the interrupt handler for the driver. * It must be connected to an interrupt system by the application such that it * can be called when an interrupt occurs. * * @param InstancePtr contains a pointer to the driver instance * * @return None. * * @note None. * ******************************************************************************/ void XRtcPsu_InterruptHandler(XRtcPsu *InstancePtr) { u32 IsrStatus; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Read the interrupt ID register to determine which * interrupt is active. */ IsrStatus = ~(XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_MSK_OFFSET)); IsrStatus &= XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET); /* * Clear the interrupt status to allow future * interrupts before this generated interrupt is serviced. */ XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET, IsrStatus); /* Handle the generated interrupts appropriately. */ /* Alarm interrupt */ if((IsrStatus & XRTC_INT_STS_ALRM_MASK) != (u32)0) { if(InstancePtr->IsPeriodicAlarm != 0U) { XRtcPsu_SetAlarm(InstancePtr, (XRtcPsu_GetCurrentTime(InstancePtr)+InstancePtr->PeriodicAlarmTime),1U); } /* * Call the application handler to indicate that there is an * alarm interrupt. If the application cares about this alarm, * it will act accordingly through its own handler. */ InstancePtr->Handler(InstancePtr->CallBackRef, XRTCPSU_EVENT_ALARM_GEN); } /* Seconds interrupt */ if((IsrStatus & XRTC_INT_STS_SECS_MASK) != (u32)0) { /* Set the CurrTimeUpdated flag to 1 */ InstancePtr->CurrTimeUpdated = 1; if(InstancePtr->TimeUpdated == (u32)1) { /* Clear the TimeUpdated */ InstancePtr->TimeUpdated = (u32)0; } /* * Call the application handler to indicate that there is an * seconds interrupt. If the application cares about this seconds * interrupt, it will act accordingly through its own handler. */ InstancePtr->Handler(InstancePtr->CallBackRef, XRTCPSU_EVENT_SECS_GEN); } }
/** * * This function does a minimal test on the Rtc device and driver as a * design example. The purpose of this function is to illustrate * how to use alarm feature in the XRtcPsu driver. * * This function sets alarm for a specified time from the current time. * * @param IntcInstPtr is a pointer to the instance of the ScuGic driver. * @param RtcInstPtr is a pointer to the instance of the RTC driver * which is going to be connected to the interrupt controller. * @param DeviceId is the device Id of the RTC device and is typically * XPAR_<RTCPSU_instance>_DEVICE_ID value from xparameters.h. * @param RtcIntrId is the interrupt Id and is typically * XPAR_<RTCPSU_instance>_INTR value from xparameters.h. * * @return XST_SUCCESS if successful, otherwise XST_FAILURE. * * @note * * This function contains an infinite loop such that if interrupts are not * working it may never return. * **************************************************************************/ int RtcPsuAlarmIntrExample(XScuGic *IntcInstPtr, XRtcPsu *RtcInstPtr, u16 DeviceId, u16 RtcIntrId) { int Status; XRtcPsu_Config *Config; u32 CurrentTime, Alarm; XRtcPsu_DT dt0; /* * Initialize the RTC driver so that it's ready to use * Look up the configuration in the config table, then initialize it. */ Config = XRtcPsu_LookupConfig(DeviceId); if (NULL == Config) { return XST_FAILURE; } Status = XRtcPsu_CfgInitialize(RtcInstPtr, Config, Config->BaseAddr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* Check hardware build */ Status = XRtcPsu_SelfTest(RtcInstPtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } xil_printf("\n\rDay Convention : 0-Fri, 1-Sat, 2-Sun, 3-Mon, 4-Tue, 5-Wed, 6-Thur\n\r"); xil_printf("Current RTC time is..\n\r"); CurrentTime = XRtcPsu_GetCurrentTime(RtcInstPtr); XRtcPsu_SecToDateTime(CurrentTime,&dt0); xil_printf("YEAR:MM:DD HR:MM:SS \t %04d:%02d:%02d %02d:%02d:%02d\t Day = %d\n\r", dt0.Year,dt0.Month,dt0.Day,dt0.Hour,dt0.Min,dt0.Sec,dt0.WeekDay); /* * Connect the RTC to the interrupt subsystem such that interrupts * can occur. This function is application specific. */ Status = SetupInterruptSystem(IntcInstPtr, RtcInstPtr, RtcIntrId); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup the handlers for the RTC that will be called from the * interrupt context when alarm and seconds interrupts are raised, * specify a pointer to the RTC driver instance as the callback reference * so the handlers are able to access the instance data */ XRtcPsu_SetHandler(RtcInstPtr, (XRtcPsu_Handler)Handler, RtcInstPtr); /* * Enable the interrupt of the RTC device so interrupts will occur. */ XRtcPsu_SetInterruptMask(RtcInstPtr, XRTC_INT_EN_ALRM_MASK ); CurrentTime = XRtcPsu_GetCurrentTime(RtcInstPtr); Alarm = CurrentTime + ALARM_PERIOD; XRtcPsu_SetAlarm(RtcInstPtr,Alarm,0); while( IsAlarmGen != 1); /* * Disable the interrupt of the RTC device so interrupts will not occur. */ XRtcPsu_ClearInterruptMask(RtcInstPtr,XRTC_INT_DIS_ALRM_MASK); return XST_SUCCESS; }