ZYNQ 7020学习笔记之PL侧普通信号中断PS的实验
1、参考
UG585
网络笔记
2、理论知识
见中断部分
3、实验目的
练习使用PL侧的普通信号来中断PS处理器。
4、实验过程
建立工程,设置并初始化串口中断,在运行程序之后,如果串口接收到N(1-63)个字节数据,则产生串口中断,Zynq响应中断,将数据从RXFIFO读出之后写入到DDR3预定的地址中。
5、实验平台
Microphase ZUS zynq7020 开发板。 串口使用 uart1[48,49]. DDR选择 MT41J256M16 RE-125,32bit. BANK1 = 1.8v.
6、Vivado 建立工程
block design 如下:
7、SDK的工程程序
/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xscugic.h"
#include "xscutimer.h"
#include "xparameters.h"
#include "xil_exception.h"
#include <unistd.h> //sleep() usleep()
#define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define INTC_PL_INTERRUPT_ID XPAR_FABRIC_MY_AXI4LITE_IP_0_PL_TO_ZYNQ_IRQ_INTR
#define INT_TYPE_MASK 0x01
#define INT_TYPE_RISING_EDGE 0X03
#define INT_TYPE_HIGHLEVEL 0X01
#define INT_CFG0_OFFSET 0x00000C00 //(intID/16 )*4
#define INT_ENABLE_OFFSET 0x00000100 //(intID/32 )*4
#define INT_CLEAR_OFFSET 0x00000280 //(intID/32 )*4
#define INT_PRIORITY_OFFSET 0x00000400 //(intID/4 )*4
#define INT_PROCESSORTARGET_OFFSET 0x00000800 //(intID/4 )*4
#define INT_ICCPMR_OFFSET 0xF8F00104
#define INT_ICCICR_OFFSET 0xF8F00100
#define BRAM_BASS_ADDRESS 0X40000000
XScuGic INTCInst;
static void PLIRQIntrHandler(void * InstancePtr); //中断处理功能函数
static void CPU_Init(void);
static void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType) ;
static void IntcTypeEnable(XScuGic *InstancePtr, int intId, int intMask) ;
static void IntcTypeClear(XScuGic *InstancePtr, int intId ) ;
static int InterruptSystemSetup(XScuGic * XScuGicInstancePtr); //中断系统建立
static int IntcInitFunction(u16 DeviceID); //中断控制器初始化功能
int main()
{
init_platform();
CPU_Init();
int status;
//中断建立
status = IntcInitFunction(INTC_DEVICE_ID);
if(status != XST_SUCCESS)
return XST_FAILURE ;
print(">>>>>>>>>>>> TEST Start >>>>>>>>>>>>>>>>\n\r");
print(" Press the Key for PL begin write data to PS DDR3 : \n\r");
while(1)
{
;
}
cleanup_platform();
return 0;
}
// 中断控制器初始化功能
static int IntcInitFunction(u16 DeviceId)
{
XScuGic_Config * IntcConfig ;
int status;
printf("Enter the interrupt system >>>>>>\n");
// 第二步, 对中断控制器进行初始化
IntcConfig = XScuGic_LookupConfig(DeviceId); //查找 GIC 的ID
status = XScuGic_CfgInitialize(&INTCInst, IntcConfig, IntcConfig->CpuBaseAddress);
if(status != XST_SUCCESS)
return XST_FAILURE;
//第三步,建立中断系统
status = InterruptSystemSetup(&INTCInst);
if(status != XST_SUCCESS)
return XST_FAILURE ;
//第四步,GPIO中断连接到GIC上
status = XScuGic_Connect(&INTCInst, INTC_PL_INTERRUPT_ID,
(Xil_ExceptionHandler)PLIRQIntrHandler, (void *)1);
if(status != XST_SUCCESS)
return XST_FAILURE ;
//******************//
// 参考
IntcTypeSetup(&INTCInst, INTC_PL_INTERRUPT_ID, INT_TYPE_RISING_EDGE); //重要
IntcTypeEnable(&INTCInst, INTC_PL_INTERRUPT_ID, INT_TYPE_MASK);
//*********************************//
XScuGic_Enable(&INTCInst, INTC_PL_INTERRUPT_ID); //CIG允许中断
return XST_SUCCESS ;
}
static int InterruptSystemSetup (XScuGic * XScuGicInstancePtr)
{
//中断异常的处理,指定该中断异常的处理器
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler, XScuGicInstancePtr);
Xil_ExceptionEnable(); //异常处理使能
return XST_SUCCESS;
}
void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType)
{
//Setup 包括 触发方式配置, 优先级配置,CPU连接。 设置某个中断信息的前提是不影响其他中断设置
int mask;
//设置边沿触发方式
mask = XScuGic_DistReadReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4); //read ICDICFR *4,因为1个寄存器4个字节
mask &= ~(0X3 << (intId%16)*2); //把读出的值对应2bit,清00,其他保持不变 //*2因为每个中断对应2bit
mask |= intType << ((intId%16)*2); //把清0后的值对应2bit,写01,其他保持不变
XScuGic_DistWriteReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4, mask); //WRITE ICDICFR
//设置优先级
mask = XScuGic_DistReadReg(InstancePtr, INT_PRIORITY_OFFSET + (intId/4)*4); //read 优先级状态
mask &= ~(0XFE << (intId%4)*8); //把读出的值对应8bit,清00,其他保持不变 //*8因为每个中断对应8bit
mask |= 0XA0 << ((intId%4)*8); //把清0后的值对应8bit,写A0,其他保持不变
XScuGic_DistWriteReg(InstancePtr, INT_PRIORITY_OFFSET + (intId/4)*4, mask); //WRITE ICDICFR
//设置处理器CPIID
mask = XScuGic_DistReadReg(InstancePtr, INT_PROCESSORTARGET_OFFSET + (intId/4)*4); //read 优先级状态
mask &= ~(0X03 << (intId%4)*8); //把读出的值对应8bit,清00,其他保持不变 //*8因为每个中断对应8bit
mask |= 0X01 << ((intId%4)*8); //把清0后的值对应8bit,写A0,其他保持不变
XScuGic_DistWriteReg(InstancePtr, INT_PROCESSORTARGET_OFFSET + (intId/4)*4, mask); //WRITE ICDICFR
}
void IntcTypeEnable(XScuGic *InstancePtr, int intId,int intMask)
{
// 本函数 只包括 使能中断。使能之前先判断是否需要屏蔽
int mask;
mask = XScuGic_DistReadReg(InstancePtr, INT_ENABLE_OFFSET + (intId/32)*4);
mask &= ~(0x01 << (intId%32)*1); //把对应的Enable bit 清0
mask |= intMask << ((intId%32)*1); //把对应的Enable bit 与 mask
XScuGic_DistWriteReg(InstancePtr, INT_ENABLE_OFFSET + (intId/32)*4, mask); //WRITE ICDICFR
}
void IntcTypeClear(XScuGic *InstancePtr, int intId )
{
//本函数仅包括清楚中断,注意只能清除本中断对应的寄存器位
int mask;
mask = XScuGic_DistReadReg(InstancePtr, INT_CLEAR_OFFSET + (intId/32)*4); //read ICDICPR
mask &= ~(0x01 << (intId%32)*1);
mask |= 0x01 << ((intId%32)*1);
XScuGic_DistWriteReg(InstancePtr, INT_CLEAR_OFFSET + (intId/32)*4, mask); //WRITE ICDICPR
}
void CPU_Init( )
{
//中断优先级都是A0,优先级高于F0,CPU可接受这些中断
Xil_Out32(INT_ICCPMR_OFFSET,0xF0);
//处理器能接收IRQ,使能中断信号连接到处理器
Xil_Out32(INT_ICCICR_OFFSET,0x07);
}
static void PLIRQIntrHandler(void * InstancePtr)
{
//default led all turn off
printf("\n************* test STARAT *********************\n");
int i;
int readdata;
sleep(1);
for(i = 0; i < 4; i++)
{
readdata = Xil_In32(BRAM_BASS_ADDRESS+i*4); //读取数据函数。
sleep(1);
printf("the read address is 0x%04x, the read data is 0x%04x.\n", BRAM_BASS_ADDRESS+i*4, readdata);
}
printf("\n************* test finish *********************\n");
// ***************************************************** //
IntcTypeClear(&INTCInst, INTC_PL_INTERRUPT_ID);
IntcTypeEnable(&INTCInst, INTC_PL_INTERRUPT_ID, INT_TYPE_MASK);
}