SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)

SoC第二讲——使用C语言控制GPIO驱动点亮LED灯(四)

结合第一讲block design的设计,通过PS部分的外设GPIO来控制LED的亮灭,这次学习通过PS部分使用C语言通过GPIO外设控制PL部分LED灯的亮灭,实现简单的ZYNQ PS和PL部分的交互。

此节首先调用函数只是对GPIO进行初始化,然后调用相关函数对其数据进行配置。

一、PL部分控制LED

PL部分的verilog代码如下所示:
在博客也有介绍:https://blog.csdn.net/vivid117/article/details/97973277
SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第1张图片
此module中有2bit 的GPIO的输入,gpio[0] 直接控制LED0的输出。gpio[1] 控制一个计数器来控制LED1,当计数器的第27位为高电平时,计数清零并使输出电平反转。实现LED1灯的间隙闪烁。

并且使用ila IP core来对内部信号进行debug,可以实现PS和PL部分的联合debug,可以见后续的

二、PS部分控制GPIO驱动
C代码控制GPIO
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"

#include "xgpiops.h"		
#include "xparameters.h"	
#define GPIO_DEV_ID XPAR_PS7_GPIO_0_DEVICE_ID 
#define LED0 54   
#define LED1 55

//gpio的初始化首先要声明两个全局变量
XGpioPs	GpioPs;					
XGpioPs_Config * GpioPsCfgPtr;	

int initGpio(); 

int main()
{		int i; 
		initGpio();	
		for (i=0;i<8;i++){ 
			XGpioPs_WritePin(&GpioPs,LED1,0x00);	
			usleep(10000000);	
			XGpioPs_WritePin(&GpioPs,LED1,0x01);	
			usleep(10000000);	
		}
	    print("Hello World\n\r");
	    return 0;
}

//initial gpio
int initGpio(){
	int status;		
	GpioPsCfgPtr = XGpioPs_LookupConfig(GPIO_DEV_ID);
	//对象初始化 GpioPs
	status = XGpioPs_CfgInitialize(&GpioPs,GpioPsCfgPtr,GpioPsCfgPtr -> BaseAddr);	
	if(status != XST_SUCCESS){	
		return status;
	}
	//gpio 设置对应接口的输出输入的方向
	XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);  
	XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01);
	
	XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01);
	return status;	
}
C代码分析
  1. 头文件及自定义宏文件
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"

#include "xgpiops.h"		//gpio头文件需要引入,里面有相关的GPIO函数
#include "xparameters.h"	//xparameters.h存了很多宏定义, 里面有我们需要的gpio的device id,

#define GPIO_DEV_ID XPAR_PS7_GPIO_0_DEVICE_ID /*自己定义一个宏定义,XPAR_PS7_GPIO_0_DEVICE_ID
 	 	 在xparameter.h中有定义为0 */
#define LED0 54    //MIO 0-53,EMIO 54-...
#define LED1 55
  1. gpio的初始化的两个全局变量
//gpio的初始化首先要声明两个全局变量
XGpioPs	GpioPs;					//XGpioPs为结构体变量,初始化的内容即为此结构体,才能让GPIO工作
XGpioPs_Config * GpioPsCfgPtr;	//还需要一个结构体 XGpioPs_Config(定义指针,获取结构体中的相关参数)
//定义变量GpioPs是将其视为对象,实例化,并在内存中占了相关的地址空间,配置一般对此配置。
//指针通过此函数,需要清楚知道config的地址。

//新建一个驱动函数,
//初始化gpio,gpio需要初始化才可以使用。
int initGpio(); //定义初始化接口
  1. main 主函数主体,控制GPIO驱动
    定义一个for循环,在每一次循环中,计数使能 gpio[1] 从低电平高电平,进而实现PL的 div_cnt 开始计数,当计数器的第27位(div_cnt[26])为高时,LED1开始闪烁(大约以1s的间隔闪烁,时钟为100Mhz)
int main()
{		int i; //定义一个for循环
		initGpio();	//调用后面的初始化GPIO函数,使接口状态变化
		for (i=0;i<8;i++){ //便于debug的时候使能(单步执行)
			XGpioPs_WritePin(&GpioPs,LED1,0x00);	//先让计数器为0,再给1,gpio[1]。调用XGpioPs_Write,先给管家写一个状态0,计数器没有计数,相当于reset counter
			usleep(10000000);	//number*us,延时10s
			XGpioPs_WritePin(&GpioPs,LED1,0x01);	//将LED1拉高
			usleep(10000000);	//再延时10s
		}
	    print("Hello World\n\r");
	    return 0;
}
  1. GPIO初始化函数部分
//initial gpio
int initGpio(){
	int status;		//由于XGpioPs_CfgInitialize()函数一定会有返回值0,所以定义一个状态
	//指针初始化 GpioPsCfgPtr
	GpioPsCfgPtr = XGpioPs_LookupConfig(GPIO_DEV_ID);//XGpioPs_LookupConfig()函数,首先初始化GpioPsCfgPtr 指针,通过look up config函数 获取指针地址,返回值是指针
	//对象初始化 GpioPs
	status = XGpioPs_CfgInitialize(&GpioPs,GpioPsCfgPtr,GpioPsCfgPtr -> BaseAddr);	/*
		内部参数的可以使用快捷键ctrl+?来查看需要获取哪些变量 两个全局变量,u32基地址*/
	if(status != XST_SUCCESS){		//因为返回值总是0,XST_SUCCESS是一个宏定义,相当于0,
		return status;
	}
	//gpio 设置对应接口的输出输入的方向
	XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);  //对管脚的设置,传递的参数为实例化的地址,管脚(需要在前面定义两个管脚),方向:1为output,0为input.
	XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01);
	//gpio设置output enable,output enabl是将BD设计中的GPIO_T打开。本次实验可以不用。
	XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01);
	return status;	//如果正确,即为0,则返回
}

}
SDK 和 ILA 联合debug调试
  1. GPIO控制 LED1
    SDKdebug,通过单步执行,结合ILA和开发板 LED灯状态 联合debug 分析C代码控制GPIO驱动LED的 。
    并在vivado的FPGA部分使用 ILA在线逻辑分析仪 debug,debug之前界面如下 (ila是在FPGA中有实际的电路,实时监控里面的端口,可以通过JTAG传回软件),并设置触发条件
    SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第2张图片
    选择div_cnt_ctrl 的最高位作为触发,value选择上升沿(R)作为触发值(由于C代码中是先由0 -> 1),然后开始trigger,等待我们程序的执行。
    SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第3张图片
    下面已经显示等待程序trigger
    SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第4张图片
    后续根据SDK中单步执行来查看trigger的信号变化。
    SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第5张图片
    单步执行状态:
    当执行完76行代码时,GPIO为低电平状态。
    SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第6张图片
    执行完78行时,高位div_cnt_ctrl 被触发了,由低电平被拉为高电平。并且计数器 div_cnt 开始计数。并且开发板开始闪烁,大约以1s 的时间间隔闪烁。
    SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第7张图片
    以此即可实现ARM侧的 PS 部分与 PL 部分进行简单交互。
    当设置div_cnt_ctrl 低电平触发时:
    SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第8张图片
    当执行完第76行时,div_cnt_ctrl 低电平触发。此时代表计数器计数清零,并且开发板上的LED灯闪烁停止(常亮)。当执行完78行时,LED灯又开始闪烁。
    SoC第二讲——使用C语言通过GPIO驱动点亮LED灯(四)_第9张图片
  2. GPIO控制 LED0

你可能感兴趣的:(C语言,SOC设计)