请选择 进入手机版 | 继续访问电脑版

石家庄老站长

点击联系客服
客服QQ:509006671 客服微信:mengfeiseo
 找回密码
 立即注册
查看: 10|回复: 0

将GPIO外设连接到Cortex_M3 AHB总线的详细步骤

[复制链接]

1

主题

1

帖子

-7

积分

限制会员

积分
-7
发表于 5 天前 | 显示全部楼层 |阅读模式
在使用外围设备之前,您需要知道该外围设备如何工作,如何工作,输入/输出接口是什么,以及如何为外围设备分配地址。

GPIO的具体硬件结构在这里就不多说了。如果想自己写代码,就要明确硬件结构。)我们使用的GPIO模块是由ARM提供的。拿来就可以了。只要大致了解GPIO的硬件结构就可以了。

在写外围设备时,经常与寄存器打交道。寄存器分为内部寄存器和外部接口寄存器。内部寄存器为R0-R15、R0-R15,具有通用寄存器。有特殊功能寄存器。这大家应该都很清楚。不用看下面括号的内容。

(寄存器是为具有特定功能的内存设备赋予别名的存储单元。此别名是常用的寄存器,如PC指针寄存器。为分配了地址的特定功能的内存设备分配别名的过程称为寄存器映射。要访问寄存器,必须使用核心指针。

那么GPIO有什么寄存器呢?这些寄存器是干什么的?嗯?

寄存器用于GPIO控制,可以使用4个寄存器操作GPIO,使GPIO的各种应用程序易于实现。这四个寄存器分别是

1.控制方向的寄存器

控制输出级状态的两个寄存器

反映插针级状态的寄存器

通过地址操作这个寄存器可以使用GPIO。硬件代码需要GPIO从设备分配地址,KEIL软件代码需要写好结构,通过结构控制GPIO。例如,硬件代码就像水箱一样。写软件代码就像往水箱里放水一样。

例程以2个16位GPIO为例,如果需要几个端口,就定义几个。

系统文件system.v中的gpio地址定义(地址定义供CPU访问,以后地址解码)、端口定义、GPIO中断定义系统文件是和完整体系结构文件,具有很多实例化。必须手动修改系统文件。

parameter  base  addr  _ gpio  0=32’h  4001 _ 0000,//gpio0 peripheral  base  address

parameter  base  addr  _ gpio  1=32’h  4001 _ 1000,//gpio1 peripheral  base  address

Input  wire  [1533600] P0 _ in、//gpio0inputs

Outputwire  [1533600] P0 _ out、//gpio0
> outputs
  output wire  [15:0]  p0_outen,         // GPIO 0 output enables
  output wire  [15:0]  p0_altfunc,       // GPIO 0 alternate function (pin mux)
  input  wire  [15:0]  p1_in,            // GPIO 1 inputs
  output wire  [15:0]  p1_out,           // GPIO 1 outputs
  output wire  [15:0]  p1_outen,         // GPIO 1 output enables
  output wire  [15:0]  p1_altfunc,       // GPIO 1 alternate function (pin mux)

  wire              gpio0_hsel;     // AHB GPIO bus interface signals
  wire              gpio0_hreadyout;
  wire     [31:0]   gpio0_hrdata;
  wire              gpio0_hresp;
  wire              gpio1_hsel;     // AHB GPIO bus interface signals
  wire              gpio1_hreadyout;
  wire     [31:0]   gpio1_hrdata;
  wire              gpio1_hresp;

  wire     [15:0]   gpio0_intr;
  wire              gpio0_combintr;
  wire              gpio1_combintr;

还要把以上定义的系统参数例化到地址解码文件(decode.v)中,地址解码就相当于多路选择器,根据地址多选1,选中你需要的外设模块进行访问。在系统文件最重要的就是把GPIO挂到系统总线上,解码和挂总线如下,其中挂总线部分省略了大量无关代码:

  // AHB address decode
  cmsdk_mcu_addr_decode #(
     .BASEADDR_GPIO0       (BASEADDR_GPIO0),
     .BASEADDR_GPIO1       (BASEADDR_GPIO1),
     .BOOT_LOADER_PRESENT  (BOOT_LOADER_PRESENT)
    )
    u_addr_decode (
    // System Address
    .code_haddr   (code_haddr),
    .code_hsel    (code_hsel),
    .sys_haddr    (sys_haddr),
    .sys_hsel     (sys_hsel),
    .remap_ctrl   (remap_ctrl),
    .boot_hsel    (boot_hsel),
    .flash_hsel   (flash_hsel),
    .sram_hsel    (sram_hsel),
    .apbsys_hsel  (apbsys_hsel),
    .gpio0_hsel   (gpio0_hsel),
    .gpio1_hsel   (gpio1_hsel),
    .sysctrl_hsel (sysctrl_hsel),
    .defslv0_hsel (defslv0_hsel),
    .defslv1_hsel (defslv1_hsel)
  );

//把GPIO挂到总线上
    .HSEL5        (gpio0_hsel),        // Input Port 5
    .HREADYOUT5   (gpio0_hreadyout),
    .HRESP5       (gpio0_hresp),
    .HRDATA5      (gpio0_hrdata),
    .HSEL6        (gpio1_hsel),        // Input Port 6
    .HREADYOUT6   (gpio1_hreadyout),
    .HRESP6       (gpio1_hresp),
    .HRDATA6      (gpio1_hrdata),

当然,别忘了把gpio模块例化进来,如下:

cmsdk_ahb_gpio #(
    .ALTERNATE_FUNC_MASK     (16'h0000), // No pin muxing for Port #0
    .ALTERNATE_FUNC_DEFAULT  (16'h0000), // All pins default to GPIO
    .BE                      (BE)
    )
    u_ahb_gpio_0  (
   // AHB Inputs
    .HCLK         (HCLKSYS),
    .HRESETn      (HRESETn),
    .FCLK         (FCLK),
    .HSEL         (gpio0_hsel),
    .HREADY       (sys_hready),
    .HTRANS       (sys_htrans),
    .HSIZE        (sys_hsize),
    .HWRITE       (sys_hwrite),
    .HADDR        (sys_haddr[11:0]),
    .HWDATA       (sys_hwdata),
   // AHB Outputs
    .HREADYOUT    (gpio0_hreadyout),
    .HRESP        (gpio0_hresp),
    .HRDATA       (gpio0_hrdata),
    .ECOREVNUM    (4'h0),// Engineering-change-order revision bits
    .PORTIN       (p0_in),   // GPIO Interface inputs
    .PORTOUT      (p0_out),  // GPIO Interface outputs
    .PORTEN       (p0_outen),
    .PORTFUNC     (p0_altfunc), // Alternate function control
    .GPIOINT      (gpio0_intr[15:0]),  // Interrupt outputs
    .COMBINT      (gpio0_combintr)
  );
  cmsdk_ahb_gpio #(
    .ALTERNATE_FUNC_MASK     (16'hF82A), // pin muxing for Port #1
    .ALTERNATE_FUNC_DEFAULT  (16'h0000), // All pins default to GPIO
    .BE                      (BE)
    )
    u_ahb_gpio_1  (
   // AHB Inputs
    .HCLK         (HCLKSYS),
    .HRESETn      (HRESETn),
    .FCLK         (FCLK),
    .HSEL         (gpio1_hsel),
    .HREADY       (sys_hready),
    .HTRANS       (sys_htrans),
    .HSIZE        (sys_hsize),
    .HWRITE       (sys_hwrite),
    .HADDR        (sys_haddr[11:0]),
    .HWDATA       (sys_hwdata),
   // AHB Outputs
    .HREADYOUT    (gpio1_hreadyout),
    .HRESP        (gpio1_hresp),
    .HRDATA       (gpio1_hrdata),
    .ECOREVNUM    (4'h0),// Engineering-change-order revision bits
    .PORTIN       (p1_in),   // GPIO Interface inputs
    .PORTOUT      (p1_out),  // GPIO Interface outputs
    .PORTEN       (p1_outen),
    .PORTFUNC     (p1_altfunc), // Alternate function control
    .GPIOINT      (),  // Interrupt outputs
    .COMBINT      (gpio1_combintr)
  );

cmsdk_ahb_gpio.v这个文件是不需要你写的,添加进来即可,这个文件里还包括2个和gpio相关的文件,这2个文件是用来实现gpio底层逻辑的,都是ARM提供,添加进来即可。

再来讲一下decode.v文件,这个也是需要我们自己修改的。每添加一个外设,就要相应修改decode文件中的代码,下面是对外设解码的相关逻辑。

  // ----------------------------------------------------------
  // Peripheral Selection decode logic
  // ----------------------------------------------------------
  assign apbsys_hsel  = (sys_haddr[31:16]==16'h4000) &
                        sys_hsel;                           // 0x40000000
  assign gpio0_hsel   = (sys_haddr[31:12]==
                         BASEADDR_GPIO0[31:12]) & sys_hsel; // 0x40010000
  assign gpio1_hsel   = (sys_haddr[31:12]==
                         BASEADDR_GPIO1[31:12]) & sys_hsel; // 0x40011000
  assign sysctrl_hsel = (sys_haddr[31:12]==20'h4001F) &
                        sys_hsel;            

在顶层module中,把IO设置为inout数据类型,在顶层模块定义一个参数parameter,用来设置GPIO模块的基地址。把参数都例化到system.v这个文件

  inout  wire  [15:0]  P0,
  inout  wire  [15:0]  P1,

  localparam BASEADDR_GPIO0       = 32'h4001_0000;           //外设基地址
  localparam BASEADDR_GPIO1       = 32'h4001_1000;

顶层定义几个连线变量,用于例化到system.v中

  wire    [15:0]  p1_in;         // I/O port #1 input
  wire    [15:0]  p1_out;        // I/O port #1 output
  wire    [15:0]  p1_outen;      // I/O port #1 output enable (tristate buffer control)
  wire    [15:0]  p1_altfunc;    // I/O port #1 alternate function

例化到system.v

    // IO Ports
    .p0_in            (p0_in),
    .p0_out           (p0_out),
    .p0_outen         (p0_outen),
    .p0_altfunc       (p0_altfunc),
    .p1_in            (p1_in),
    .p1_out           (p1_out),
    .p1_outen         (p1_outen),
    .p1_altfunc       (p1_altfunc),

除了端口要例化,GPIO外设基地址也要例化。

      .BASEADDR_GPIO0 (BASEADDR_GPIO0),  // GPIO0 Base Address
      .BASEADDR_GPIO1 (BASEADDR_GPIO1),  // GPIO1 Base Address

外设基地址既不是输入变量,也不是输出变量,例化时要把它写道"#()"的括号里,学过verilog的人应该都知道。

至此,gpio已经刮到了总线上。接下来就是写用keil软件的过程,我们需要在启动文件添加一些中断,还要写一些结构体,用于设置GPIO的各种参数,给GPIO结构体中变量赋值的过程就是写寄存器的过程,我们透过结构体操控了寄存器,进而控制了GPIO。
回复

使用道具 举报

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

本版积分规则

QQ|无图版|手机版|小黑屋|石家庄@IT精英团

GMT+8, 2021-6-15 17:11 , Processed in 5.847227 second(s), 27 queries .

Powered by Discuz! X3.4

© 2001-2021 Comsenz Inc.

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