这一部分是基于基于ZYNQ-7000开发板的调试系列(4)继续展开的,主要的部分是需要两个定时器开启中断开始。这一部分主要是需要使用TTC,完成2组流水灯的同时工作,两组的频率也不一致。
[参考自ZYNQ7000 TRM (Page.245-249)]
TTC可以完成的工作比较多,其实TTC的使用是可以控制GPIO的占空比。这个的最简单的使用例程就是做一个呼吸灯。但是需要使用到PL的PWM,这里就先不涉及这一部分的内容了。
[参考自ZYNQ进阶之路8–PS端实现EMIO TTC PWM输出(与PL端PWM联合使用)]
其实这里主要就是需要把TTC0和TTC1打开,这里提供的EMIO是可以向外输出波形的,这里可以并不需要,所以这里可以不用向外提供接口。具体的Diagram图大概是这个样子的。
然后这里就没有其他需要修改的部分了,这里生成Bitstream即可。
这一部分的程序编写其实和上一部分几乎是一致的,和上一部分最大的不同就是TTC的使能和控制。
其中,引入必须引入的库:
#include "xttcps.h"
然后是关于TTC的函数:
XTtcPs_Config *XTtcPs_LookupConfig(
u16 DeviceId
);
s32 XTtcPs_CfgInitialize(
XTtcPs *InstancePtr,
XTtcPs_Config * ConfigPtr,
u32 EffectiveAddr
);
s32 XTtcPs_SetOptions(
XTtcPs *InstancePtr,
u32 Options
); //关于TTC的模式配置
void XTtcPs_CalcIntervalFromFreq(
XTtcPs *InstancePtr,
u32 Freq,
XInterval *Interval,
u8 *Prescaler
); //通过用户给定的频率计算分频和间隔的数值,并赋值到指定的地址上
void XTtcPs_SetInterval(
XTtcPs *InstancePtr;
XInterval interval
); // 该函数实质上就是往寄存器里写入值
void XTtcPs_SetPrescaler(
XTtcPs *InstancePtr,
u8 PrescalerValue
); // 该函数按照指定的分频向寄存器内写入值
void XTtcPs_EnableInterrupts(
XTtcPs *InstancePtr,
u32 InterruptMask
); // 该函数实质上就是往寄存器里写入值,使能TTC中断
定时器开始
XTtcPs_Start(
XTtcPs *InstancePtr
); // 该函数实质上就是往寄存器里写入值,开始计数
中断内函数
u32 XTtcPs_GetInterruptStatus(
XTtcPs *InstancePtr
); // 检测是否已经触发了中断
void XTtcPs_ClearInterruptStatus(
XTtcPs *InstancePtr,
u32 statusEvent
); // 如果触发中断,该部分解除中断
其余部分和上一部分几乎一致。程序如下:
#include "xparameters.h"
#include "xgpio.h"
#include "xgpiops.h"
#include "xttcps.h"
#include "xstatus.h"
#include "xscugic.h"
#include "xil_exception.h"
#define PS_GIC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define LEDG1_INTR_ID XPAR_XTTCPS_0_INTR
#define LEDG2_INTR_ID XPAR_XTTCPS_3_INTR
#define LED1_INTR_DEVICE_ID XPAR_XTTCPS_0_DEVICE_ID
#define LED2_INTR_DEVICE_ID XPAR_XTTCPS_3_DEVICE_ID
#define LED1_FREQ_HZ 2
#define LED2_FREQ_HZ 3
#define PL_GPIO_DEVICE_ID XPAR_GPIO_0_DEVICE_ID
#define PS_GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define PL_LED_CHANNEL 1
#define PL_KEY_CHANNEL 2
#define PS_BANK XGPIOPS_BANK0
#define PL_LED0 0x01
#define PL_LED1 0x02
#define PL_LED2 0x04
#define PL_LED3 0x08
#define PL_LED4 0x10
#define PS_LED0 0x09
#define PS_LED1 0x00
typedef struct {
u32 OutputHz; /* Output frequency */
XInterval Interval; /* Interval value */
u8 Prescaler; /* Prescaler value */
u16 Options; /* Option settings */
} TmrCntrSetup;
volatile u8 led_status = 0x00;
volatile u8 state1;
volatile u8 state2;
volatile u8 plLed;
volatile u8 psLed;
XGpio plGpio;
XGpioPs psGpio;
XTtcPs psTimer1;
XTtcPs psTimer2;
XScuGic psGic;
static TmrCntrSetup timer1Setup = {LED1_FREQ_HZ, 0, 0, 0};
static TmrCntrSetup timer2Setup = {LED2_FREQ_HZ, 0, 0, 0};
int init();
void run();
int init_Gpio();
int init_Exti();
int init_Gpio_Pl();
int init_Gpio_Ps();
int init_Exti_Timer1();
int init_Exti_Timer2();
int init_Exti_Gic();
void psIntrTimer1Handler(void*);
void psIntrTimer2Handler(void*);
// 0
int main(){
int status;
status = init();
if(status != XST_SUCCESS) return XST_FAILURE;
run();
return 0;
}
// 1
int init(){
int status;
status = init_Gpio();
if(status != XST_SUCCESS) return XST_FAILURE;
status = init_Exti();
if(status != XST_SUCCESS) return XST_FAILURE;
return XST_SUCCESS;
}
void run(){
XTtcPs_Start(&psTimer1);
XTtcPs_Start(&psTimer2);
while(1){
switch(state1){
case 1: {
plLed = (plLed & 0x10) + 0x0E;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
}break;
case 2: {
plLed = (plLed & 0x10) + 0x0D;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
}break;
case 3: {
plLed = (plLed & 0x10) + 0x0B;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
}break;
case 4: {
plLed = (plLed & 0x10) + 0x07;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
}break;
case 0: {
plLed = (plLed & 0x10) + 0x0F;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x00);
}break;
default:{
plLed = (plLed & 0x10) + 0x0F;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
}
}
switch(state2){
case 0:{
plLed = (plLed & 0x0F) + 0x00;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
} break;
case 1:{
plLed = (plLed & 0x0F) + 0x10;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x00);
} break;
default:{
plLed = (plLed & 0x0F) + 0x10;
XGpio_DiscreteWrite(&plGpio, PL_LED_CHANNEL, plLed);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
}
}
}
}
// 2
int init_Gpio(){
int status;
status = init_Gpio_Pl();
if(status != XST_SUCCESS) return XST_FAILURE;
status = init_Gpio_Ps();
if(status != XST_SUCCESS) return XST_FAILURE;
// PL
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL, 0x00);
XGpio_SetDataDirection(&plGpio, PL_KEY_CHANNEL, 0x01);
// PS
XGpioPs_SetDirection(&psGpio, PS_BANK, 0x201);
XGpioPs_SetOutputEnable(&psGpio, PS_BANK, 0x201);
return XST_SUCCESS;
}
int init_Exti(){
int status;
TmrCntrSetup *t1;
TmrCntrSetup *t2;
status = init_Exti_Timer1();
if(status != XST_SUCCESS) return XST_FAILURE;
status = init_Exti_Timer2();
if(status != XST_SUCCESS) return XST_FAILURE;
status = init_Exti_Gic();
if(status != XST_SUCCESS) return XST_FAILURE;
// Timer //
t1 = &timer1Setup;
t2 = &timer2Setup;
t1->Options |= (XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE);
t2->Options |= (XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE);
XTtcPs_SetOptions(&psTimer1, t1->Options);
XTtcPs_CalcIntervalFromFreq(&psTimer1, t1->OutputHz, &(t1->Interval), &(t1->Prescaler));
XTtcPs_SetInterval(&psTimer1, t1->Interval);
XTtcPs_SetPrescaler(&psTimer1, t1->Prescaler);
XTtcPs_EnableInterrupts(&psTimer1, XTTCPS_IXR_INTERVAL_MASK);
XTtcPs_SetOptions(&psTimer2, t2->Options);
XTtcPs_CalcIntervalFromFreq(&psTimer2, t2->OutputHz, &(t2->Interval), &(t2->Prescaler));
XTtcPs_SetInterval(&psTimer2, t2->Interval);
XTtcPs_SetPrescaler(&psTimer2, t2->Prescaler);
XTtcPs_EnableInterrupts(&psTimer2, XTTCPS_IXR_INTERVAL_MASK);
// Gic
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&psGic);
status = XScuGic_Connect(&psGic, LEDG1_INTR_ID,
(Xil_ExceptionHandler)psIntrTimer1Handler,
(void *)&psTimer1);
if(status != XST_SUCCESS) return XST_FAILURE;
XScuGic_Enable(&psGic, LEDG1_INTR_ID);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&psGic);
status = XScuGic_Connect(&psGic, LEDG2_INTR_ID,
(Xil_ExceptionHandler)psIntrTimer2Handler,
(void *)&psTimer2);
if(status != XST_SUCCESS) return XST_FAILURE;
XScuGic_Enable(&psGic, LEDG2_INTR_ID);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
// 3
int init_Gpio_Pl(){
XGpio_Config *xGpioCfg;
xGpioCfg = XGpio_LookupConfig(PL_GPIO_DEVICE_ID);
if(xGpioCfg == (XGpio_Config *)NULL) return XST_FAILURE;
return XGpio_CfgInitialize(&plGpio, xGpioCfg, xGpioCfg->BaseAddress);
}
int init_Gpio_Ps(){
XGpioPs_Config *xGpioCfg;
xGpioCfg = XGpioPs_LookupConfig(PS_GPIO_DEVICE_ID);
if(xGpioCfg == (XGpioPs_Config *)NULL) return XST_FAILURE;
return XGpioPs_CfgInitialize(&psGpio, xGpioCfg, xGpioCfg->BaseAddr);
}
int init_Exti_Timer1(){
XTtcPs_Config *xGpioCfg;
xGpioCfg = XTtcPs_LookupConfig(LED1_INTR_DEVICE_ID);
if(xGpioCfg == (XTtcPs_Config *)NULL) return XST_FAILURE;
return XTtcPs_CfgInitialize(&psTimer1, xGpioCfg, xGpioCfg->BaseAddress);
}
int init_Exti_Timer2(){
XTtcPs_Config *xGpioCfg;
xGpioCfg = XTtcPs_LookupConfig(LED2_INTR_DEVICE_ID);
if(xGpioCfg == (XTtcPs_Config *)NULL) return XST_FAILURE;
return XTtcPs_CfgInitialize(&psTimer2, xGpioCfg, xGpioCfg->BaseAddress);
}
int init_Exti_Gic(){
XScuGic_Config *xGpioCfg;
xGpioCfg = XScuGic_LookupConfig(PS_GIC_DEVICE_ID);
if(xGpioCfg == (XScuGic_Config *)NULL) return XST_FAILURE;
return XScuGic_CfgInitialize(&psGic, xGpioCfg, xGpioCfg->CpuBaseAddress);
}
void psIntrTimer1Handler(void *ref){
u32 statusEvent;
statusEvent = XTtcPs_GetInterruptStatus(&psTimer1);
XTtcPs_ClearInterruptStatus(&psTimer1, statusEvent);
if(0 != (XTTCPS_IXR_INTERVAL_MASK & statusEvent)){
switch(state1){
case 0: state1 = 1; break;
case 1: state1 = 2; break;
case 2: state1 = 3; break;
case 3: state1 = 4; break;
case 4: state1 = 0; break;
default: state1 = 0;
}
}
}
void psIntrTimer2Handler(void *ref){
u32 statusEvent;
statusEvent = XTtcPs_GetInterruptStatus(&psTimer2);
XTtcPs_ClearInterruptStatus(&psTimer2, statusEvent);
if(0 != (XTTCPS_IXR_INTERVAL_MASK & statusEvent)){
switch(state2){
case 0: state2 = 1; break;
case 1: state2 = 0; break;
default: state2 = 0;
}
}
}
该部分代码和之前没有太大的出入,完成流水灯部分代码。