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
曾国藩在给儿子的一封家书中曾写道:余于凡事皆用困知勉行工夫,尔不可求名太骤,求效太捷也。熬过此关,便可少进。再进再困,再熬再奋,自有亨通精进之日。 不急躁不求捷径,小火慢炖,将事…...
电商客服外包怎么选|避坑指南[特殊字符]2026 商家必看
做电商绕不开客服外包,但低价陷阱、转包兼职、大促掉链、响应超时、售后甩锅真的太坑了!今天整理一套不踩雷选型攻略,全是行业干货,新手也能直接抄作业👇 🚫先避坑:这些雷区千万别碰 超低价诱惑…...
GB28181流媒体服务器选型笔记:为什么我们最终选择了ZLMediaKit?聊聊它的协议转换与性能表现
GB28181流媒体服务器选型实战:ZLMediaKit的协议转换与性能突围 在视频监控与安防领域的技术选型中,GB28181协议服务器的选择往往让架构师陷入"性能、兼容性、扩展性"的三角困境。经过三个月的技术验证与压力测试,我们团队最终选择了…...
MoveIt2新手必看:如何正确选择安装分支(main vs. tutorials)及使用vcs管理多仓库
MoveIt2分支选择与多仓库管理实战指南 当你在ROS2生态中开始使用MoveIt2时,第一个拦路虎往往不是算法理解或代码编写,而是如何正确搭建开发环境。MoveIt2作为由数十个独立Git仓库组成的复杂项目,其分支管理和版本协同问题困扰着许多中级开发者…...
OpenSubdiv高级特性:特征自适应细分与硬件曲面细分
OpenSubdiv高级特性:特征自适应细分与硬件曲面细分 【免费下载链接】OpenSubdiv An Open-Source subdivision surface library. 项目地址: https://gitcode.com/gh_mirrors/op/OpenSubdiv OpenSubdiv是一款强大的开源细分曲面库,为3D建模和动画提…...
ALM扩展开发教程:如何为TypeScript IDE创建自定义插件
ALM扩展开发教程:如何为TypeScript IDE创建自定义插件 【免费下载链接】alm :rose: A :cloud: ready IDE just for TypeScript :heart: 项目地址: https://gitcode.com/gh_mirrors/al/alm ALM是一款专为TypeScript和JavaScript设计的云端IDE,为开…...
Voron 2.4 3D打印机进阶调试与故障排除指南
Voron 2.4 3D打印机进阶调试与故障排除指南 【免费下载链接】Voron-2 Voron 2 CoreXY 3D Printer design 项目地址: https://gitcode.com/gh_mirrors/vo/Voron-2 机械系统精调:从结构应力到运动精度 问题导向:框架组装后出现对角线偏差超过2mm&a…...
AudioLDM-S极速音效生成:5分钟搞定游戏音效,小白也能当音效师
AudioLDM-S极速音效生成:5分钟搞定游戏音效,小白也能当音效师 1. 游戏音效制作的新纪元 想象一下这样的场景:你正在开发一款独立游戏,需要一个"科幻飞船引擎启动"的音效。传统方式可能需要花费数小时搜索音效库、购买…...
港科资讯|郑光廷教授出席国际科技组织发展与全球科技治理论坛 分享协作实践
2026年3 月 28 日,国际科技组织发展与全球科技治理论坛在北京中关村国际创新中心成功举办。香港科技大学副校长(研究及发展)郑光廷教授受邀出席并发表主题演讲,香港科大内地办(北京)主任袁冶老师一同参会,与中外嘉宾交…...
从ATE到RPE:用evo全面解读你的SLAM算法在KITTI上的表现
从ATE到RPE:用evo全面解读你的SLAM算法在KITTI上的表现 在SLAM算法开发中,量化评估是验证算法性能的关键环节。KITTI数据集作为自动驾驶领域最具影响力的基准测试平台之一,为研究者提供了丰富的真实场景数据。但如何从海量轨迹数据中提取有价…...
使用Python轻松管理Word页脚
在日常的办公自动化中,处理Word文档是许多人绕不开的环节。无论是生成报告、合同,还是制作项目文档,Word都是一个不可或缺的工具。然而,当文档数量庞大,或者需要频繁更新时,那些看似简单的重复性任务&#…...



