前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >迅为2K1000龙芯开发板pmon 下操作 GPIO

迅为2K1000龙芯开发板pmon 下操作 GPIO

原创
作者头像
用户9167207
发布2022-06-02 15:58:02
6410
发布2022-06-02 15:58:02
举报
文章被收录于专栏:嵌入式开发板嵌入式开发板

我们可以来学习如何在 pmon 下操作 gpio 了, 为什么要把这个需求单独拿出来讲呢? 因为有的时候我们做了一款产品, 在特定的环境下需要让 GPIO 在上电时就是就保证是一个确定的电平, 如高电平或者低电平。 Uboot 上这些资料非常的多, 所以我们别的板子对于这个需求就没单独拿出来给大家讲, 但是龙芯用的是 pmon, pmon 上相关的资料太少了, 所以有必要单独作为一章给大家讲解。

平台:迅为i.TOP-2K1000开发板

CPU:国产龙芯处理器,双核64位系统,板载2G DDR3内存,

系统支持:busybox,buiroot,Loognix,qt

在 pmon 下控制 GPIO 有俩种方法, 这里以开发板上的 led3 给大家举例, 一种方法是在 c 语言环境建立之前来控制, 另一种方法是在 c 语言环境建立以后来控制。 我们分别来看一下这俩种方法。

1 软硬件分析 这里以开发板上的 led3 给大家举例, 我们打开开发板的底板原理图, 找到 led3 的电路, 如下图所示:

通过硬件电路图我们可以发现, 当 LS2K_GPIO0 管脚输出为高电平时, Led3 发光, 反之则不发光。 我们查阅数据手册得知, 龙芯 2K1000 共有 60 个 GPIO 引脚, 4 个为专用 GPIO, 其余 56 个与其他功能复用。

开发板上 Led3 连接的管脚为 GPIO0, 其中 GPIO0~GPIO3 为专用 GPIO 管脚, 所以不需要设置复用, 如下图所示。 注意! 如果你用的不是专用 GPIO 引脚, 则需要设置复用关系!

如果要操作一个 GPIO, 我们光知道他的复用关系还不行, 我们还要操作 GPIO 的方向寄存器以及数据寄存器,通过查阅数据手册, 我们发现 LS2K 的 GPIO 的方向寄存器的地址为 0x1fe10500, 数据寄存器的地址为0x1fe10510, 如下图所示:

方向寄存器描述:

通过上图我们可以发现, 如果为 0, 则 GPIO 的方向为输入, 反之则为输出。 0 到 63 分别对应 60 个 GPIO。数据寄存器描述:

通过上图我们可以发现, 如果为 0, 则 GPIO 输出低电平, 反之则为输高电平。 0 到 63 分别对应 60 个 GPIO。

2 通过 C 控制 GPIO

2.1 编写驱动程序 首先我们使用命令 cd Targets/LS2K/dev 进到 pmon 的 Targets/LS2K/dev 目录, 在这个目录下放的是和 LS2K相关的驱动代码, 如下图所示:

然后我们这个这个目录下使用命令 vim topeet_led.c 创建一个 c 程序, 并输入以下代码:

#include <stdio.h> /* * 初始化 led3 管脚 */ void led3_init(void) { *(volatile int *)0xbfe10500 &= ~(0x01); //设置方向为输出 *(volatile int *)0xbfe10510 &= ~(0x01); //默认输出低电平 printf("led3 init!\n"); } / * * 点亮 led3 */ void led3_on(void) { *(volatile int *)0xbfe10510 |= 0x01; //输出高电平 printf("led3 on!\n"); } / * * 熄灭 led3 */ void led3_off(void) {

*(volatile int *)0xbfe10510 &= ~(0x01); //输出低电平 printf("led3 off!\n"); }

为什么这里的我们操作的地址是 0xbfe10500 和 0xbfe10510 而不是我们在上一小节所说的 0x1fe10500和 0x1fe10510 呢, 因为系统上电启动后, 任何 MIPS 架构的 CPU 都是从系统的虚拟地址 0xbfc00000 启动的,其对应的物理地址为 0x1FC00000, 所以这里我们操作的是 0x1fe10500 和 0x1fe10510 对应的虚拟地址0xbfe10500 和 0xbfe10510。创建完成后如下图所示:

2.2 添加编译规则 接下来就是要把我们添加的这个 C 程序编译到 pmon 里面, 这个要如何添加呢, 如果大家看了第 9.3 小节, 我相信大家一定知道要怎么做了。我们进到 pmon 源码下的 argets/LS2K/conf 文件夹,

然后使用命令 vim files.LS2K 打开配置文件, 并在配置文件的最下面添加以下代码 file Targets/LS2K/dev/topeet_led.c如下图所示:

2.3 控制 led 在 9.4 小节, 我们分析了 pmon 的启动流程, 最终会在 Targets/LS2K/ls2k/tgt_machdep.c 下的 c 文件里面的 initmips 函数初始化外设, 所以我们是不是只要在这里调用我们写的 C 程序就可以了呢。 我们打开 Targets/LS2K/ls2k/tgt_machdep.c 文件, 在 initmips 函数里面添加以下代码:

led3_init(); int j=3; while(j--) { led3_on(); delay(1000000); led3_off(); delay(1000000); }

如下图所示:

9.6.2.4 编译验证 我们将编译好的 pmon 烧写到开发板, 观察 led3 的现象, 可以发现在 pmon 启动的时候 led3 会闪烁 3次, 说明我们在 pmon 下控制 led 成功, 同时可以在控制终端看到如下打印, 如下图所示:

至此, 通过 C 控制 GPIO 完成。如大家没有成功点亮, 可以参考手册 9.7.6 章节使用 Ejtag 单步调试 pmon。

3 通过汇编控制 GPIO 上一小节, 我们使用了 C 语言控制了 gpio, 这一小节我们来看一下如何使用汇编来控制 gpio 呢? 有的同学可能会有疑问了, 既然我们可以使用 C 语言来控制 gpio, 为什么我们还要使用更底层的汇编语言呢,如果我们要使用 C 语言, 是不是需要等待 C 语言环境建立起来才可以使用呢, 那他是不是就要比汇编稍微的慢一些呢, 如果我们想让他上电立马就确定 gpio 管脚的电平的状态, 使用汇编会更好些。 我们打开 Targets/LS2K/ls2k/start.S 下的 start.S 文件, 我们在 9.4.2 小节里面已经确定了他的位置, 这里就不在赘述了。 然后我们在第 487 行输入以下代码, 同样, 这里还是用 gpio0 给大家举例 /* *设置使用 GPIO 的方向为输出 */ li v0, 0xbfe10500 ld v1, (v0) dli a0, (1<<0) //gpio0 or v1, a0 xor v1, a0 sd v1, (v0) /* *找到 GPIO 输出数据寄存器 */ //0x10(v0)这种写法就是给 v0 地址偏移 0x10,v0 地址是 0xbfe10500,偏移 0x10 就是 0xbfe10510,即 输出数据寄存器 ld v1, 0x10(v0) /* *给数据寄存器写 1 输出高电平 */ or v1, a0 sd v1, 0x10(v0) //on /* *延迟 */ dli a2,0xffff //delay 1: subu a2, 0x1

nop bgtz a2, 1b /* *给数据寄存器写 0 输出低电平 */ or v1, a0

xor v1, a0  //off

sd v1, 0x10(v0)

/* *延迟 */ dli a2,0xffff //delay 2: subu a2, 0x1 nop bgtz a2, 2b 如下图所示:

汇编程序的思路同 C 语言一下, 同样第一步也是先设置 gpio 的复用以及方向, 如果是专用 gpio 则不用设置复用关系。 第二步则是设置 gpio 输出的高低电平。 只不过现在我们是用汇编来完成这个操作, 如大家对汇编指令不是很清楚, 可以参考资料中的龙芯架构参考手册, 位置: LS2K1000 开发板资料\07_第三方库以其他参考资料\01_其他参考资料我们将编译好的 pmon 镜像烧写开发板, 开机上电会可以观察到开发板立刻闪烁一下, 闪烁完以后串口终端才有打印信息出现。 如大家没有成功点亮, 可以参考手册 9.7.5 章节使用 Ejtag 单步调试 pmon。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档