Zynq开发实践(SDK之定时器)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
定时器是芯片提供的一个常见功能。尤其是在mcu里面,如果我们不想使用rtos开发固件程序,一般情况下就会选择轮询+定时器中断来处理,最多加一个状态机。当然在处理的过程中,还有可能需要处理其他的中断,这也是有可能的。今天就看看zynq上面怎么处理定时器的。
1、私有定时器和公共定时器
由于zynq上面是双核a9 cpu,所以定时器本身就分成了两种。一种是私有定时器,每个cpu各一个。还有一个是公共定时器。我们自己写代码的时候,如果只是在一个core上面运行,可以只设置私有定时器即可。如果还有其他core需要处理,core0处理定时器的时候,发一个核间中断也可以。
2、定时器不需要外设pin脚
本身定时器就是和clock相关,和cpu相关,不需要任何的外设pin脚。
3、如何做block design
和第一个纯PS工程一样,添加好soc之后,去掉三个接口、添加mio14、mio15串口、添加ddr3初始化即可。
4、参考的代码
参考的代码,就是最简单的hello world工程。
5、创建定时器、初始化中断、开始轮询
整个流程还是比较简单的,首先就是创建定时器,设置一下定时器的相关参数,比如多长时间trigger一下等等。接下来就是初始化中断,zynq里面的中断也是一个外设接口。这些都做好了,就是开始轮询设置了。
int main()
{int Status;XScuTimer_Config *ConfigPtr;init_platform();xil_printf("SCU Private Timer Demo Start\r\n");// load configurationConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);if (ConfigPtr == NULL)return XST_FAILURE;// initialize timerStatus = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr,ConfigPtr->BaseAddr);if (Status != XST_SUCCESS)return XST_FAILURE;// 1s = 333000000 cyclesXScuTimer_LoadTimer(&TimerInstance, 333000000);XScuTimer_EnableAutoReload(&TimerInstance);Status = SetupInterruptSystem(&IntcInstance, &TimerInstance);if (Status != XST_SUCCESS)return XST_FAILURE;// enable interruptXScuTimer_EnableInterrupt(&TimerInstance);// enable timerXScuTimer_Start(&TimerInstance);while (1) {if (TimerExpired) {xil_printf("Timer Interrupt Triggered!\r\n");TimerExpired = 0;}}cleanup_platform();return XST_SUCCESS;
}
6、中断初始化和定时器中断注册
定时器的触发,这里是通过中断实现的。我们有必要初始化中断,关联中断号,并且注册一下回调函数。这样中断发生的时候,这个回调函数就可以直接被引用。
// callback functionvoid TimerIntrHandler(void *CallBackRef)
{XScuTimer *Timer = (XScuTimer *)CallBackRef;XScuTimer_ClearInterruptStatus(Timer);TimerExpired = 1;xil_printf("Timer Interrupt Happened, counter = %d!\r\n", counter++);
}int SetupInterruptSystem(XScuGic *IntcInstancePtr, XScuTimer *TimerInstancePtr)
{int Status;XScuGic_Config *IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);if (NULL == IntcConfig)return XST_FAILURE;Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);if (Status != XST_SUCCESS)return XST_FAILURE;Xil_ExceptionInit();Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,IntcInstancePtr);// register callback functionStatus = XScuGic_Connect(IntcInstancePtr, TIMER_IRPT_INTR_ID,(Xil_ExceptionHandler)TimerIntrHandler,(void *)TimerInstancePtr);if (Status != XST_SUCCESS)return XST_FAILURE;XScuGic_Enable(IntcInstancePtr, TIMER_IRPT_INTR_ID);Xil_ExceptionEnable();return XST_SUCCESS;
}
这些都准备好了之后,就可以连接jtag、连接串口,准备开始调试了,
7、为什么定时器这么重要
定时器就像人的心脏一样,推进各个业务往前走。不同的外部接口,不同的中断,都是在定时器的舞动之下,一步一步实现状态的变更。这中间哪怕没有高级的rtos,只要有定时器+状态机,也可以开发出很多有意思的产品。
最后给出完整的代码,有兴趣的同学可以好好参考下,
#include "xscutimer.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xparameters.h"
#include "xil_printf.h"#include "platform.h"#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define TIMER_IRPT_INTR_ID XPAR_SCUTIMER_INTRstatic XScuTimer TimerInstance;
static XScuGic IntcInstance;volatile int TimerExpired = 0;
static int counter = 0;// callback functionvoid TimerIntrHandler(void *CallBackRef)
{XScuTimer *Timer = (XScuTimer *)CallBackRef;XScuTimer_ClearInterruptStatus(Timer);TimerExpired = 1;xil_printf("Timer Interrupt Happened, counter = %d!\r\n", counter++);
}int SetupInterruptSystem(XScuGic *IntcInstancePtr, XScuTimer *TimerInstancePtr)
{int Status;XScuGic_Config *IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);if (NULL == IntcConfig)return XST_FAILURE;Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);if (Status != XST_SUCCESS)return XST_FAILURE;Xil_ExceptionInit();Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,IntcInstancePtr);// register callback functionStatus = XScuGic_Connect(IntcInstancePtr, TIMER_IRPT_INTR_ID,(Xil_ExceptionHandler)TimerIntrHandler,(void *)TimerInstancePtr);if (Status != XST_SUCCESS)return XST_FAILURE;XScuGic_Enable(IntcInstancePtr, TIMER_IRPT_INTR_ID);Xil_ExceptionEnable();return XST_SUCCESS;
}int main()
{int Status;XScuTimer_Config *ConfigPtr;init_platform();xil_printf("SCU Private Timer Demo Start\r\n");// load configurationConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);if (ConfigPtr == NULL)return XST_FAILURE;// initialize timerStatus = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr,ConfigPtr->BaseAddr);if (Status != XST_SUCCESS)return XST_FAILURE;// 1s = 333000000 cyclesXScuTimer_LoadTimer(&TimerInstance, 333000000);XScuTimer_EnableAutoReload(&TimerInstance);Status = SetupInterruptSystem(&IntcInstance, &TimerInstance);if (Status != XST_SUCCESS)return XST_FAILURE;// enable interruptXScuTimer_EnableInterrupt(&TimerInstance);// enable timerXScuTimer_Start(&TimerInstance);while (1) {if (TimerExpired) {xil_printf("Timer Interrupt Triggered!\r\n");TimerExpired = 0;}}cleanup_platform();return XST_SUCCESS;
}