OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 112|回复: 0

[XILINX] ZYNQ&MPSoC系列之嵌入式Vitis软件开发篇(第9讲学习分享)

[复制链接]

1

主题

1

帖子

0

精华

新手入门

积分
6
金钱
6
注册时间
2025-12-1
在线时间
1 小时
发表于 2025-12-4 14:06:12 | 显示全部楼层 |阅读模式
我实现的功能跟老师留下的练习略有区别,故分享一下我的方法,因为我的使用的并不是正点原子的开发板,是其他家的板子,我的板子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);
    }
}



led_ip_core.zip

42.33 KB, 下载次数: 0

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-12-13 14:13

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表