IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> DE1-SoC HPS CAN中断方式通信调试过程--WL -> 正文阅读

[嵌入式]DE1-SoC HPS CAN中断方式通信调试过程--WL

DE1-SoC HPS CAN通信(中断方式)调试

实验目的:
利用Altera Cyclone V SoPC HPS集成的CAN总线控制器,采用中断方式,实现裸机下的CAN报文数据的收发。
实验环境:
硬件:DE1-SoC开发板,
软件:Quartus II 15.0和DS-5 18.1,Preloader,HPS裸机固件驱动库(18.1)。
实验流程:
1.硬件设计
2.软件设计
a. Preloader部分
b. HPS引导流程
c. CAN裸机中断收发程序流程
1. 主程序框架
2. 关键硬件资源的初始化
3. 中断收发服务函数实现及触发流程

1.硬件设计
HPS 中包含CAN 总线控制器,所以不需要添加 IP 核,只需从 HPS 中引出 CAN 的 tx、rx 的引脚,使其能够通过这两个引脚连接片外驱动电路并和外部进行通信。

具体步骤:
在 Qsys 系统组件 HPS 参数选项标签页设置 CAN 的外设引脚

注:CAN pin选择FPGA ,因为 HPS I/O Set 没有可以连接外部进行 CAN 通信的引脚
双击红色区域引出 CAN 的引脚

用 verilog 进行端口声明:

经过综合与分析后,在 Pin Planner 中就会看到上面声明的 CAN 端口
双击 Location进行引脚分配:

分配的引脚是从板上2个40pin GPIO中随意挑选的,但需要注意的是,由于 CAN 通信是差分信号输入到 CAN 总线上,所以挑选引脚复用时要选择 DIFFIO_RX DIFFIO_TX

电路连接如下:
需要注意的是,需要加一个电平转换器件,因为 TTL 电平标准和 CAN 的电平标准不同。
最终编译生成的.sof文件经由USB-Blaster下载到开发板中。

3.软件设计

硬件部分设计完成,但HPS 的配置信息还不知道,软件程序运行的环境没准备好,裸机程序还需加载,所以需要准备一个完成软硬件交互的文件,也就是preloader部分。

a.Preloader部分
最终需要生成 u-boot-spl 二进制文件进行相关硬件初始化,并且引导加载裸机程序
那么怎么得到u-boot-spl ?
首先,我们需要知道配置 HPS 的信息,如使能的外设,管脚的复用等
对此,可以编译上面说明的硬件设计,得到.sof文件(经由USB Blaster下载到板子中)和handoff文件夹,handoff文件夹中包含了这些信息
然后,经由 preloader 生成器,也就是bsp(板级支持包) editor 将 handoff 文件夹里的信息转换成源代码、 另外生成 preloader 设置文件、 preloader 调试脚本以及编译 preloader 所用的 makefile。
由此我们得到了源文件,但是和我们最终想要的二进制文件存在差异,需要借助 makefile进行编译。
Bsp editor支持多种型号板子的 preloader 配置信息的生成

generated文件夹可以看到许多头文件与C语言文件,这些文件是用来更新uboot中相关文件的,主要涉及到系统配置,IO复用,DDR初始化等
Makefile 制定了编译规则,生成最终的二进制文件,执行以下步骤:
1.把 generated文件夹下的相应文件拷贝到uboot-socfpga/board/altera/socfpga与下面sdram子目录
2.通过下面的变量设置

PRELOADER_UPDATE_DIR := $(PRELOADER_SRC_DIR)/board/altera/socfpga
SOCFPGA_BOARD_CONFIG := socfpga_$(DEVICE_FAMILY)_config
DEVICE_FAMILY := cyclone5

以及执行make $(board)_config 对工程进行配置,以确定特定于目标板的各个子目录和头文件。生成配置文件config.h(知道取用U-Boot源代码中的哪些相应文件)
3.配置完成后,就要进行编译 spl 得到 u-boot-spl.bin
uboot-socfpga目录下顶层文件Makefile有下面的语句

ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin

打开spl目录下的文件Makefile
在这里我们可以看到编译 spl 所需要用的各种配置文件、汇编文件和用到的链接器文件,下面是其中的一部分

LIBS-$(CONFIG_SPL_FRAMEWORK) += common/spl/libspl.o
LIBS-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/libcommon.o
LIBS-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/libdisk.o
LIBS-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/libi2c.o
LIBS-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/libgpio.o
LIBS-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/libmmc.o
LDSCRIPT :=(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds

链接文件决定一个可执行程序的各个段的存储(加载)地址,以及运行(链接)地址。

b.HPS引导流程
上电 reset 后,位于 HPS 中的 ROM 运行封装好的一段代码Boot ROM
Boot ROM代码的作用是确定所选的boot源,重置后初始化HPS,将 preloader 映像从 flash 加载到OCRAM然后跳转到 preloader 。
所选的 Flash 类型 SDMMC 在 bsp-editor spl boot 选项中设置
在这里插入图片描述
OCRAM 由地址 0xFFFF0000知
在这里插入图片描述
Preloader 在完成Clock Reconfiguration、初始化SDRAM接口、配置HPS I/O引脚及复用、初始化加载下一阶段程序的接口后,将裸机程序引导映像从引导设备复制到SDRAM。并执行
SDRAM 地址0x00100000–0xC0000000
在这里插入图片描述
c. CAN裸机中断收发程序流程
1. 主程序框架

初始化:1.通过协议组寄存器模块(如CCTRL寄存器、CBT寄存器等)进行软件初始化(如设置比特率,设置通信模式等)
2.通过IF接口寄存器初始化Message RAM中的接收邮箱和发送邮箱(分别初始化)。
消息对象结构:掩码位、仲裁位、控制位、数据位
在这里插入图片描述
通过IF接口寄存器配置消息对象的掩码位、仲裁位、控制位、数据位,存储到Message RAM对应邮箱中请求发送。
Message Handler(状态机)接收到了请求,处理消息对象发送。
邮箱中的消息对象通过IF寄存器传输到CAN core中的移位寄存器,经过封装然后到达CAN 总线接口,进行数据帧的传送。

中断相关:
GIC–中断控制器连接所有能够产生中断的I/O外围设备的IRQ中断信号。CAN0 控制器有4个中断信号连接到全局中断控制器 (GIC),
在这里插入图片描述
GIC 由分配器和 CPU 接口组成,分配器从I/O外设接收IRQ中断信号
CPU接口将分配器收到的IRQ请求发送给Cortex-A9处理器。

中断信号可以分为3种
1.SPI(shared peripheral interrupts):该中断由中断控制器可以路由到多个内核的外设生成.中断号32-211
2.PPI(private peripherals interrupts):专用于单个CPU .中断号27-30
3.SGI(software generated interrupts):由软件通过写入专用分配器寄存器生成.中断号0-15

中断过程:
当发生中断时,CAN0 控制器发送一个消息中断信号 ALT_INT_INTERRUPT_CAN0_MO_IRQ 给 GIC ,由分配器接收,然后CPU接口将中断请求发送给Cortex-A9处理器让处理器进行处理,进入到中断模式。
在程序中,跳转到中断向量表 irq 入口,通过跳转指令,跳转到中断服务函数。执行完中断服务函数后,回到原程序继续运行

2.关键硬件资源的初始化代码

进行 CAN 通信,先要对 CAN controller 初始化,其中包括比特率的设置,Message Ram的初始化以及接收邮箱和发送邮箱的初始化等

 /* Initialize the can controller*/
     alt_can_init( ALT_CAN_CAN0, candev);
    /*Initialize the can controller rx mailbox for many received messages  */
    alt_can_mailbox_init(candev,0x1, 0x16,  0x5,ALT_CAN_TMOD_TX, ALT_CAN_FIFO_MODE_SINGLE_MSG);
    alt_can_mailbox_init(candev,0x2, 0x0101,  0x3,ALT_CAN_TMOD_RX, ALT_CAN_FIFO_MODE_SINGLE_MSG);
    alt_can_mailbox_init(candev,0x3, 0x0102,  0x3,ALT_CAN_TMOD_RX, ALT_CAN_FIFO_MODE_SINGLE_MSG);
    alt_can_mailbox_init(candev,0x4,0x0103,0x3,ALT_CAN_TMOD_RX, ALT_CAN_FIFO_MODE_SINGLE_MSG);

注:当接收多个报文/数据帧时,为避免数据错乱,需设置邮箱的ID 标识符以及掩码位

  1. 中断收发服务函数实现及触发流程

要以中断方式实现数据收发,需要配置 GIC(包括分配器和 CPU 接口),并配置 CAN 控制器使其能发送中断信号
配置 GIC

  ALT_STATUS_CODE status = ALT_E_SUCCESS;
     if (status == ALT_E_SUCCESS)
    {
        status = alt_int_global_init();
    }

    if (status == ALT_E_SUCCESS)
    {
        status = alt_int_cpu_init();
    }

    /* Setup the interrupt specific items */

    if (status == ALT_E_SUCCESS)
    {
        status = alt_int_isr_register(ALT_INT_INTERRUPT_CAN0_MO_IRQ, can_int_callback,NULL);
    }

    if (status == ALT_E_SUCCESS)
       /* Ignore target_set() for non-SPI interrupts. */
    {
        int target = 0x3; /* 1 = CPU0, 2=CPU1 */
        status = alt_int_dist_target_set(ALT_INT_INTERRUPT_CAN0_MO_IRQ, target);
    }

    if (status == ALT_E_SUCCESS)
       {
        status = alt_int_dist_trigger_set(ALT_INT_INTERRUPT_CAN0_MO_IRQ,ALT_INT_TRIGGER_LEVEL);
       }
    /* Enable the distributor, CPU, and global interrupt */

    if (status == ALT_E_SUCCESS)
    {
        status = alt_int_dist_enable(ALT_INT_INTERRUPT_CAN0_MO_IRQ);
    }

    if (status == ALT_E_SUCCESS)
    {
        status = alt_int_cpu_enable();
    }

    if (status == ALT_E_SUCCESS)
    {
        status = alt_int_global_enable();
    }

配置I/O外围设备 CAN 控制器,使其可以发送IRQ中断请求到GIC。

 /* Enable can0 interrupt//CCTRL.MIL */
    alt_can_int_enable(candev, 0xf);

设置消息对象接收中断。消息对象/邮箱的中断是在消息对象的控制位中设置的。设置成功后,一旦接收到报文,就触发中断

 /* Enable rx interrupt */
       ALT_CAN_MSG_IFMCTR_t ctrl0 = {0};
       ctrl0.data_len=0x8;
       ctrl0.block_end=true;
       ctrl2.rx_int=true;
   alt_can_if_msg_ctrl_set( candev, ALT_CAN_INTERFACE_WRITE,&ctrl0);
 ALT_CAN_MSG_PARAM_t  msgparam1 = {0};
	   msgparam1.control=true;
	   alt_can_message_put(candev, ALT_CAN_INTERFACE_WRITE, 0x2,&msgparam1);


触发中断后,跳转指令到中断服务函数
中断服务函数:实现点亮FPGA灯,以及将接收到的数据帧发送出去

void can_int_callback()
	{
  	  /* light the FPGA led */
	alt_write_word(0xff200000,0x1);}

然后通过读取寄存器 MOIPA 的值判断哪一个消息对象的中断标志位 Inpnd 置1,知道哪个邮箱触发中断

   /* send a message object which receive just now */

    ALT_CAN_MSG_PARAM_t  cmd_params0 = {0};

	cmd_params0.arbitration=true;   
	cmd_params0.control=true;     
    cmd_params0.data_A=true;
    cmd_params0.data_B=true;       // true = transfer Data Bytes 0-3 to IFxDA.

  	 alt_can_message_get(candev,ALT_CAN_INTERFACE_READ, i, &cmd_params0);

  	 uint32_t a = alt_read_word(0xFFC00108);
  	 uint32_t b = alt_read_word(0xFFC00110);
   	uint32_t c = alt_read_word(0xFFC00114);
  	 uint32_t d = a & 0x1fffffff;
  	 arb_param0.direction=true;
  	 arb_param0.id=d;
  	 arb_param0.extended=false;
  	 arb_param0.valid=true;    //MsgVal bit

  	 alt_can_if_arb_set( candev,ALT_CAN_INTERFACE_WRITE, &arb_param0);

   	ALT_CAN_MSG_IFMCTR_t ctrl0 = {0};
  	 ctrl0.data_len=0x8;
  	 ctrl0.block_end=true;
  	 alt_can_if_msg_ctrl_set( candev, ALT_CAN_INTERFACE_WRITE,&ctrl0);

   	/*Sends 8 data bytes to the CAN controller.IF register*/
 	  alt_can_if_data_set( candev, ALT_CAN_INTERFACE_WRITE, b, c);

    ALT_CAN_MSG_PARAM_t  msgparam = {0};
    msgparam.data_B=true;          //true = transfer Data Bytes 0-3 to Message Object.
    msgparam.data_A=true;
    msgparam.tx_rqst_new_dat=true;   // true = set TxRqst and NewDat in Message Object to one
    msgparam.control=true;     //true = transfer Control Bits to Message Object.
    msgparam.arbitration=true;
    alt_can_message_put(candev, ALT_CAN_INTERFACE_WRITE, 0x1,&msgparam);

	 /* clear rx interrupt bit */
    ALT_CAN_MSG_IFMCTR_t ctrl2 = {0};
    ctrl2.int_pending=false;
    ctrl2.data_len=0x8;
    ctrl2.block_end=true;
    ctrl2.rx_int=true;
    alt_can_if_msg_ctrl_set( candev, ALT_CAN_INTERFACE_WRITE,&ctrl2);
    ALT_CAN_MSG_PARAM_t  msgparam4 = {0};
    msgparam4.control=true;
	  alt_can_message_put(candev,ALT_CAN_INTERFACE_WRITE,i,&msgparam4);

为了程序能正常运行而不是一直进入中断,要清除中断位,在对应邮箱/消息对象的 Intpnd 位置0即可。
程序设计完成后,经过编译、汇编、链接最终生成.axf二进制文件

实验结果:

每当USB-CAN Tool 发送一个消息对象,程序触发中断,进入中断服务函数,将接收到的消息对象再返回发送到USB-CAN Tool中,如下图所示。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 11:46:32  更:2022-02-26 11:49:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:51:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码