新手入门
- 积分
- 6
- 金钱
- 6
- 注册时间
- 2025-12-1
- 在线时间
- 1 小时
|
我实现的功能跟老师留下的练习略有区别,故分享一下我的方法,因为我的使用的并不是正点原子的开发板,是其他家的板子,我的板子PS端只有一个LED灯,所以的设计目标是:
1.通过串口发送1来开启呼吸灯,发送0来关闭呼吸灯
2.呼吸灯我使用的IP核来实现的,也就说是我使用的PL的资源来实现呼吸灯效果的
我说一下我的设计思路,首先UART我是来当一个控制开关的,通过本节课程介绍的中断来实现的接收和发送功能,IP核输出的LED_OUT这个引脚我是通过AXI_GPIO接到了PS端,然后通过AXI_GPIO的中断来实现PS_LED的呼吸灯的亮灭。
因此,可能跟老师的设计目标不太一致,仅供大家参考,IP核的代码是我自己编写的,可能会跟老师的有出入,但功能是一致的,这个实验目前是在我的开发板上已经实现了,大家也可以参考一下。
以防大家下载不了,我把除IP核代码以外的VITIS代码放在下面了,由于上传不了的整个Vivado工程,所以我只上传ip_core文件。
#include "stdio.h"
#include "xparameters.h"
#include "xuartps.h"
#include "xgpio.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "led_ip_core.h"
#define LED_REG_BASEADDR XPAR_LED_IP_CORE_0_S0_AXI_BASEADDR
#define LED_REG0 LED_IP_CORE_S0_AXI_SLV_REG0_OFFSET
#define LED_REG1 LED_IP_CORE_S0_AXI_SLV_REG1_OFFSET
#define GPIO_PL_ID XPAR_AXI_GPIO_0_DEVICE_ID //AXI GPIO 器件ID
#define GPIO_PS_ID XPAR_XGPIOPS_0_DEVICE_ID //PS MIO器件ID
#define UART1_DEVICE_ID XPAR_PS7_UART_1_DEVICE_ID //UART DEVICE ID
#define UART1_INTR_ID XPAR_XUARTPS_1_INTR //UART INTR ID 注意查找对应硬件的CortexA9的器件ID
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID //GIC ID
#define AXI_GPIO_INTR_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR //AXI GPIO INTR ID
//引脚定义
#define PS_LED0 7 //MIO7
#define AXI_GPIO_Channel 1 //只启用一个AXI_GPIO口,并没有使用双通道,故为1
//结构体变量定义
XGpio AXI_Gpio; //AXI_GPIO 的结构体指针
XGpioPs GpioPs; //GPIP_PS 的结构题指针
XUartPs UartPs; //UART 的结构体变量
XScuGic Intc; //中断控制器结构体变量
void GPIO_init(XGpioPs *GpioPs,XGpio *Gpio_AXI);
void uart_init(XUartPs *uartPs);
void Intr_init(XScuGic *Intc, XUartPs *uartps , XGpio *AXI_Gpio);
void uart_intr_handler(void *CallBackRef);
void AXI_Gpio_handler(void *CallbackRef);
//全局控制变量
volatile int led_run_mode = 0;
int main()
{
GPIO_init(&GpioPs,&AXI_Gpio);
uart_init(&UartPs);
Intr_init(&Intc,&UartPs,&AXI_Gpio);
xil_printf("system INIT END\r\n");
while(1);
return 0;
}
void GPIO_init(XGpioPs *GpioPs,XGpio *Gpio_AXI)
{
XGpioPs_Config *Gpio_ps_cfg;
XGpio_Config *Gpio_axi_cfg;
//PS端的GPIO配置
Gpio_ps_cfg = XGpioPs_LookupConfig(GPIO_PS_ID);
XGpioPs_CfgInitialize(GpioPs,Gpio_ps_cfg,Gpio_ps_cfg->BaseAddr);
XGpioPs_SetDirectionPin(GpioPs, PS_LED0, 1);
XGpioPs_SetOutputEnablePin(GpioPs, PS_LED0, 1);
XGpioPs_WritePin(GpioPs, PS_LED0, 0); //默认为LED灭
//AXI_GPIO的配置
Gpio_axi_cfg = XGpio_LookupConfig(GPIO_PL_ID);
XGpio_CfgInitialize(Gpio_AXI,Gpio_axi_cfg,Gpio_axi_cfg->BaseAddress);
XGpio_SetDataDirection(Gpio_AXI, AXI_GPIO_Channel,1);
//开启led_ip_core
LED_IP_CORE_mWriteReg(LED_REG_BASEADDR, LED_REG0,1); //启用led
LED_IP_CORE_mWriteReg(LED_REG_BASEADDR, LED_REG1, 0x10000063);//启用breath_freq控制
}
//UART 初始化和配置
void uart_init(XUartPs *uartps)
{
XUartPs_Config *Uart_cfg; // UART 的基础配置信息(如BASEADDR)
//根据器件ID来查找器件的配置信息,如BASEADDR 和其余的 OFFSET ADDR
Uart_cfg = XUartPs_LookupConfig(UART1_DEVICE_ID);
//对UART驱动进行初始化
XUartPs_CfgInitialize(uartps,Uart_cfg,Uart_cfg->BaseAddress);
//对UART进行配置
//设置波特率
XUartPs_SetBaudRate(uartps, 115200);
//设置模式 : 正常模式
XUartPs_SetOperMode(uartps,XUARTPS_OPER_MODE_NORMAL);
}
void Intr_init(XScuGic *Intc, XUartPs *uartps , XGpio *AXI_Gpio)
{
XScuGic_Config *IntcConfig; //GUI配置信息的驱动实例
//初始化GIC(中断控制器)
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); //内部函数就是一个大型的表格,去对应参数
XScuGic_CfgInitialize(Intc, IntcConfig,
IntcConfig->CpuBaseAddress);
//注册异常
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
Intc);
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
//连接 AXI GPIO 中断(搬运工,搬运 IP 核输出的 led_out)
XScuGic_Connect(Intc, AXI_GPIO_INTR_ID,
(Xil_ExceptionHandler)AXI_Gpio_handler,
(void *)AXI_Gpio);
XScuGic_Enable(Intc, AXI_GPIO_INTR_ID);
//连接 UART 中断(指挥官)
XScuGic_Connect(Intc, UART1_INTR_ID,
(Xil_ExceptionHandler)uart_intr_handler,
(void *)uartps);
XScuGic_Enable(Intc, UART1_INTR_ID);
//开启AXI_GPIO的通道使能和全局使能
XGpio_InterruptEnable(AXI_Gpio, XGPIO_IR_CH1_MASK);
XGpio_InterruptGlobalEnable(AXI_Gpio);
//对UART中断进行配置
XUartPs_SetFifoThreshold(uartps,1);
XUartPs_SetInterruptMask(uartps,XUARTPS_IXR_RXOVR); //使能触发阈值中断
}
//XUARTPS_IXR_RXOVR
void uart_intr_handler(void *CallBackRef)
{
u32 Intr_Status;
u8 rec_data;
XUartPs *uart_ps = (XUartPs *)CallBackRef;
Intr_Status = XUartPs_ReadReg(uart_ps->Config.BaseAddress, XUARTPS_ISR_OFFSET);//Interrupt Status
XUartPs_WriteReg(uart_ps->Config.BaseAddress, XUARTPS_ISR_OFFSET, Intr_Status);
if(Intr_Status & XUARTPS_IXR_RXOVR) //如果满载则执行
{
// 循环读取所有数据,直到 FIFO 为空
while (XUartPs_IsReceiveData(uart_ps->Config.BaseAddress))
{
//如果FIFO还有数据则执行
rec_data = XUartPs_RecvByte(uart_ps->Config.BaseAddress);
//发送 数据
XUartPs_SendByte(uart_ps->Config.BaseAddress, rec_data); // 回环逻辑
if(rec_data == '1')
{
led_run_mode = 1; //开启呼吸
xil_printf("CMD: Start Breathing\r\n");
}
else if(rec_data == '0')
{
led_run_mode = 0; //关闭呼吸
xil_printf("CMD: Stop\r\n");
}
else if(rec_data == '\r' || rec_data == '\n')
{
xil_printf("contain r or n");
}
else
{
xil_printf("Unknown CMD: %x\r\n", rec_data);
}
}
}
}
void AXI_Gpio_handler(void *CallbackRef)
{
XGpio *Axi_gpio = (XGpio *)CallbackRef;
u32 pl_val;
// 清除中断标志
XGpio_InterruptClear(Axi_gpio, XGPIO_IR_CH1_MASK); //掩码定义在 xgpio_I.h
//检查开关是否开启
if (led_run_mode == 1)
{
// 读取 PL 发过来的波形状态 (0 或 1)
pl_val = XGpio_DiscreteRead(Axi_gpio, AXI_GPIO_Channel);
// 把这个状态写给 MIO7
XGpioPs_WritePin(&GpioPs, PS_LED0, pl_val & 0x1);
}
else
{
// 不管 PL 发什么,MIO7 始终保持灭 (假设0是灭)
XGpioPs_WritePin(&GpioPs, PS_LED0, 0);
}
}
|
|