Melis4.0[D1s]:1.启动流程(与adc按键初始化相关部分)跟踪笔记
文章目录
- 1.启动流程
- 1.1 最先进入的文件:head_s.S
- 1.2 start_kernel()函数所在的文件:init.c
- 1.3 input_init()函数所在文件:sys_input.c
- 1.4 INPUT_LKeyDevInit()所在文件:keyboarddev.c
- 1.5 esINPUT_RegLdev()所在文件:input.c
- 1.5.1 来到这里,无法与后面的硬件初始化搭上关系。
- 2.从底层操作硬件的函数往前面跟踪
- 2.1 实现对adc按键硬件初始化的函数 sunxi_keyboard_init()
- 2.1.1 本函数是被do_initcalls()调用的
- 2.1.2 本函数注册了中断函数keyboard_irq_callback(),直接产生按键消息
- 3.根据分压电阻的实际阻值修改代码
- 3.1 关键代码分析
- 3.1 根据硬件不同,重新计算参数
- 4. mq-r(F133)按键接法
本文是自己为了厘清Melis4.0[D1s]启动时加载输入按键驱动流程而做的笔记。
开发板使用了mangopi-MQ-R(F133),melis只支持spinor flash,不支持spinand和sd卡。而mangopi-MQ-R(F133)没有焊接spinor flash,必须自己购买补焊。
我在立创商城买的华邦的 W25Q128JVSIQ:
参考文章:
- 作者:waxly-,文章 :全志 Melis-4.0(rt-thread内核) 环境搭建与初步编译介绍
1.启动流程
Melis4.0的RTOS内核有2种选择,我们选的是RT-Thread:

关于RT-Thread启动流程的详细资料可以参考官方文档:RT-Thread Nano 移植原理。
但是Melis的启动流程似乎与RT-Thread关系不大,参考全志官方文档《Melis4.0 RTOS系统开发指南》。
下面做部分摘录,稍作整理:
1.1 最先进入的文件:head_s.S
该文件路径为 《D1s-Melis\ekernel\arch\riscv\rv64gc\head_s.S》,完成以下功能:
• bss 段的清零;
• sp 栈指针的初始化;
• mmu 初始化和页表基地址赋值;
• 异常统一入口赋值;
• 跳转至 start_kernel 函数;
1.2 start_kernel()函数所在的文件:init.c
该文件路径为 《D1s-Melis\ekernel\arch\riscv\sunxi\init.c》,start_kernel()函数间接调用input_init()函数完成输入设备初始化函数的调用。

这里的awos_init_thread()函数还调用do_initcalls(),而do_initcalls()调用了sunxi_keyboard_init()。下面摘录官方文章介绍do_initcalls()的内容:
do_initcalls()函数通过层层调用,调用了initcall_levels数组定义的函数地址标识,这些地址标识在riscv/lds/kernel.lds中定义,表示代码段名称为initcallxx.init类的代码,c 文件通过__attribute__((section(“text”))),指定函数或变量在链接时存放的代码段段名称。这个由source/include/melis/init.h文 件 中 的 宏 定 义___define_initcall(fn, id, .initcall##id)来 声 明 实现。
例 如:subsys_initcall(drv_dma_init);将 函 数 指 定 到 代 码 段.initcall4.init, 将 会 在 调用__initcall4_start时,把__initcall4_start到__initcall5_start代码段地址区间的函数接口执行一遍。
1.3 input_init()函数所在文件:sys_input.c
该文件路径为 《D1s-Melis\ekernel\legacy\input\sys_input.c》,按键初始化是默认有的,触摸则根据配置参数决定是否初始化,鼠标则默认没有。按键设备的初始化函数为INPUT_LKeyDevInit(),继续跟踪。
int32_t input_init(void)
{__inf("input system initialize....");if (INPUT_CoreInit() != EPDK_OK){__wrn("INPUT_CoreInit failed");return EPDK_FAIL;}if (INPUT_LKeyDevInit() != EPDK_OK){__wrn("INPUT_LkeyDevInit failed");INPUT_CoreExit();return EPDK_FAIL;}
#if 0if (INPUT_LMouseDevInit() != EPDK_OK){__wrn("INPUT_LMouseDevInit failed");INPUT_LKeyDevExit();INPUT_CoreExit();return EPDK_FAIL;}
#endif#if CONFIG_SUPPORT_TOUCHPANELif (INPUT_LTSDevInit() != EPDK_OK){__wrn("INPUT_LTPDevInit failed");//INPUT_LMouseDevExit();INPUT_LKeyDevExit();INPUT_CoreExit();return EPDK_FAIL;}
#endifreturn EPDK_OK;
}
1.4 INPUT_LKeyDevInit()所在文件:keyboarddev.c
该文件路径为 《D1s-Melis\ekernel\legacy\input\keyboard\keyboarddev.c》,调用了esINPUT_RegLdev()。
1.5 esINPUT_RegLdev()所在文件:input.c
该文件路径为 《D1s-Melis\ekernel\legacy\input\input\input.c》
1.5.1 来到这里,无法与后面的硬件初始化搭上关系。
上面是从开始往后面跟踪调用子函数,下面是从子函数跟踪被哪个上级函数调用,来到这里失联了。
2.从底层操作硬件的函数往前面跟踪
根据本节的分析,adc按键的功能是默认的,不用使用 make menuconfig 进行配置。不过为了保险起见,还是做足下面的配置:


2.1 实现对adc按键硬件初始化的函数 sunxi_keyboard_init()
该文件路径为 《D1s-Melis\ekernel\drivers\drv\source\input\keyboard\sunxi_keyboard.c》。
2.1.1 本函数是被do_initcalls()调用的
在文件sunxi_keyboard.c有下面的语句:
late_initcall(sunxi_keyboard_init);
对应的宏定义在文件 《D1s-Melis\include\melis\init.h》:
#define late_initcall(fn) __define_initcall(fn, 7)
于是变成了指针数组 initcall_levels 的一员:
static initcall_entry_t *initcall_levels[] =
{__initcall0_start,__initcall1_start,__initcall2_start,__initcall3_start,__initcall4_start,__initcall5_start,__initcall6_start,__initcall7_start,__initcall_end,
};
最终在do_initcalls()被调用,do_initcalls()所在的文件为 《D1s-Melis\ekernel\arch\common\initcall.c》。
2.1.2 本函数注册了中断函数keyboard_irq_callback(),直接产生按键消息
int sunxi_keyboard_init(void)
{.......hal_gpadc_init();hal_gpadc_channel_init(GP_CH_0);hal_gpadc_register_callback(GP_CH_0, keyboard_irq_callback);return 0;
}
keyboard_irq_callback()可以直接发送系统消息:
int keyboard_irq_callback(uint32_t data_type, uint32_t data)
{......if (key_data->key_code < key_config.key_num){if (key_flag == 0){console_LKeyDevEvent(NULL, EV_KEY, key_data->scankeycodes[key_data->key_code], 1);console_LKeyDevEvent(NULL, EV_SYN, 0, 0);key_flag = 1;}......
}
3.根据分压电阻的实际阻值修改代码
官方的adc按键部分电路:

我用万能板焊接的电路板,使用了手头已有的电阻4.7k,10k,20k,30k:

3.1 关键代码分析
计算键值的关键代码:
struct sunxikbd_config key_config =
{.measure = 1800,.key_num = 5,.key_vol = {210, 410, 590, 750, 880},.scankeycodes = {KPAD_UP, KPAD_DOWN, KPAD_ENTER, KPAD_MENU, KPAD_RETURN},.name = "sunxi-keyboard"
};static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, /* key 1, 0-8 */1, 1, 1, 1, 1, /* key 2, 9-13 */2, 2, 2, 2, 2, 2, /* key 3, 14-19 */3, 3, 3, 3, 3, 3, /* key 4, 20-25 */4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* key 5, 26-36 */5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* key 6, 37-39 */6, 6, 6, 6, 6, 6, 6, 6, 6, /* key 7, 40-49 */7, 7, 7, 7, 7, 7, 7 /* key 8, 50-63 */
};
大概思路是将AD值处理后(大约是除以32),在keypad_mapindex[]里面查表,得到一个在0-4(共5个按键)范围内的值,再从key_config. scankeycodes[]里面查表得到最终的键值。以key1为例,key1按下时的AD值(理论值) 经过处理,应该是4,这样可以使允许误差最大化。
3.1 根据硬件不同,重新计算参数
K0对应的AD理论值为183,除以32得 5.7,约等于6,那么可以取:
static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* key 1, 0-10 */
K1对应的AD理论值为524,除以32得 16.3,约等于16,那么可以取:
static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* key 1, 0-10 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* key 2, 11-20 */
K2对应的AD理论值为1055,除以32得 33,那么可以取:
static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* key 1, 0-10 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* key 2, 11-20 */2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* key 3, 21-36 */
K3对应的AD理论值为1448,除以32得 45.2,约等于45,那么可以取:
static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* key 1, 0-10 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* key 2, 11-20 */2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* key 3, 21-39 */3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* key 4, 40-50 */
K3对应的AD理论值为1878,除以32得 58.6,约等于58,那么可以取:
static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* key 1, 0-10 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* key 2, 11-20 */2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* key 3, 21-39 */3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* key 4, 40-50 */4, 4, 4, 4, 4, 4, 4, 4, 4, 4,4, 4, 4, 4, 4, 4, 4, 4, 4, /* key 5, 51-69 */
其实,这个表是由下面的代码重新计算,并覆盖掉的:
static int sunxikbd_data_init(struct sunxikbd_drv_data *key_data, struct sunxikbd_config *sunxikbd_config)
{int i, j = 0;int key_num = 0;unsigned int resol;unsigned int key_vol[KEY_MAX_CNT];key_num = sunxikbd_config->key_num;if (key_num < 1 || key_num > KEY_MAX_CNT){return -1;}resol = sunxikbd_config->measure / MAXIMUM_SCALE;for (i = 0; i < key_num; i++){key_data->scankeycodes[i] = sunxikbd_config->scankeycodes[i];}for (i = 0; i < key_num; i++){key_vol[i] = sunxikbd_config->key_vol[i];}for (i = 0; i < (key_num - 1); i++){key_vol[i] += (key_vol[i + 1] - key_vol[i]) / 2;}
/*for (i = 0; i < MAXIMUM_SCALE; i++){if (i * resol > key_vol[j]){j++;}keypad_mapindex[i] = j;}
*/key_data->last_key_code = INITIAL_VALUE;return 0;
}
我因为还没看懂这个函数的逻辑,把其中覆盖keypad_mapindex[128]的代码屏蔽了。
4. mq-r(F133)按键接法

相关文章:
Melis4.0[D1s]:1.启动流程(与adc按键初始化相关部分)跟踪笔记
文章目录1.启动流程1.1 最先进入的文件:head_s.S1.2 start_kernel()函数所在的文件:init.c1.3 input_init()函数所在文件:sys_input.c1.4 INPUT_LKeyDevInit()所在文件:keyboarddev.c1.5 esINPUT_RegLdev()所在文件:in…...
GNU make 中文手册 第三章:Makefile 总述
一、Makefile 总述 3.1 Makefile 的内容 在一个完整的 Makefile 中,包含了 5 个东西:显式规则、隐含规则、变量定义、指示符和注释。关于“规则”、“变量” 和 “Makefile 指示符” 将在后续的章节进行详细的讨论。本章讨论的是一些基本概念。 显式规…...
简历的专业技能怎么写?排版需要注意的事项
一、简历的专业技能怎么写? 首先,先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几 天时间学习一下,然后在简历上可以写上自己了解这个技…...
【Git】为什么需要版本控制?版本控制工具有那些?
目录 一、为什么需要版本控制? 二、版本控制工具有那些? 💟 创作不易,不妨点赞💚评论❤️收藏💙一下 一、为什么需要版本控制? 首先我们要知道什么是版本控制?对版本控制进行文字…...
SSH远程执行Python3 Error: UnicodeEncodeError: ‘ascii‘ codec
首先确定要执行脚本服务器的语言编码环境,执行 # locale -a C en_US.utf8 POSIX # locale LANGen_US.utf8 LC_CTYPE"en_US.utf8" LC_NUMERIC"en_US.utf8" LC_TIME"en_US.utf8" LC_COLLATE"en_US.utf8" LC_MONETARY"…...
极简TypeScript教程--面向对象
在早期的JavaScript开发中(ES5)我们需要通过函数和原型链来实现类和继承,从ES6开始,引入了class关键字,可以更加方便的定义和使用类。TypeScript作为JavaScript的超集,也是支持使用class关键字的࿰…...
java TCP/UDP、Socket、URL网络编程详解
文章目录网络通信协议通信双方地址端口号IP地址InetAddress类Socket 网路编程Socket类的常用构造器Socket类的常用方法UDP协议什么是UDP协议UDP网络编程DatagramSocket 构造方法DatagramSocket 常用方法DatagramPacket常用方法实现步骤单向数据发收的UDP程序双向数据发收的UDP程…...
【C语言】宏
🚀write in front🚀 📜所属专栏:> c语言学习 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是…...
【测试面试】自我分析+功能+接口自动化+性能测试面试题(大全),知己知彼百战百胜......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 分析自己和面试企业…...
ASE4N65SE-ASEMI高压MOS管ASE4N65SE
编辑-Z ASE4N65SE在TO-220F封装里的静态漏极源导通电阻(RDS(ON))为2.5Ω,是一款N沟道高压MOS管。ASE4N65SE的最大脉冲正向电流ISM为16A,零栅极电压漏极电流(IDSS)为10uA,其工作时耐温度范围为-55~150摄氏度。ASE4N65S…...
MyBatis概述环境搭建(一)
🚗MyBatis学习起始站~ 🚩本文已收录至专栏:数据库学习之旅 👍希望您能有所收获 一.什么是MyBatis (1) 引言 MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDB…...
3.8国际妇女节即将到来,跨境卖家如何做好选品和营销?
不知不觉,时间已来到了2月末,一年一度的三八国际妇女节也即将来临。三八节又称女神节,这不仅是庆祝女性伟大贡献的日子,也是跨境卖家们促销的大好时机。 有数据显示,女性是跨境消费的主力人群,占比超七成&…...
Glue Connector 和 Connection 的关系与区别
AWS Glue作为一种无服务器产品,其运行环境是“不可预知”的,也就是“一个黑盒”,所以如何能连接一些自有数据源是Glue必须考虑并给予满足的,为此,Glue给出的解决方案就是Connector和Connection,一个connect…...
如何使用ngxin的 upstream
1.引言: 1.1反向代理: 反向代理是充当Web服务器网关的代理服务器。当您将请求发送到使用反向代理的Web服务器时,他们将先转到反向代理,由该代理将确定是将其路由到Web服务器还是将其阻止。 这意味着有了反向代理,您…...
Java数组,超详细整理,适合新手入门
目录 一、什么是Java中的数组? 二、数组有哪些常见的操作? 三、数组的五种赋值方法和使用方法 声明数组 声明数组并且分配空间 声明数组同时赋值(1) 声明数组同时赋值(2) 从控制台输入向数组赋值 四、求总和平均 五、求数组中最大值最小值 六…...
1.3数据传输控制方式:IO数据传输控制方式、程序控制(查询)方式、程序中断方式、DMA方式、通道方式、I/O处理机
1.3数据传输控制方式:IO数据传输控制方式、程序控制(查询)方式、程序中断方式、DMA方式、通道方式、I/O处理机程序控制(查询)方式程序中断方式DMA方式通道方式、I/O处理机I/O数据传输方式,由软件到硬件发展…...
Linux 设置语言
文章目录1. 临时设置环境变量2. 默认语言设置3. 语言包4. 安装浏览器 chromium1. 临时设置环境变量 通过设置环境变量,可以使单个命令使用另一种语言LANG $ LANGfr_FR.utf8 date mar. mai 24 12:16:51 CDT 2022后续命令将恢复为使用系统的默认语言进行输出。该loc…...
Python基础-数据类型之集合
一、集合的定义 集合:是一个无序的没有重复元素的序列,因此不能通过索引来进行操作 1:使用set()创建集合 set(object) # 参数为一个序列,整型不能作为参数 set_a set("abcb") print(set_a) # {b, a, c} 2&…...
[Css]Grid属性简单陈列(适合开发时有基础的快速过一眼)
[css进阶]Grid属性简介 文章目录[css进阶]Grid属性简介典型需求网格容器的属性displaygrid-template-columns和grid-template-rowsgrid-template-areasgrid-templategrid-column-gap grid-row-gapgrid-gapjustify-itemsalign-itemsjustify-contentalign-contentgrid-auto-colum…...
100种思维模型之启发式偏差思维模型-017
曾国藩在给儿子的一封家书中曾写道:余于凡事皆用困知勉行工夫,尔不可求名太骤,求效太捷也。熬过此关,便可少进。再进再困,再熬再奋,自有亨通精进之日。 不急躁不求捷径,小火慢炖,将事…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...



