Melis4.0[D1s]:1.启动流程(与adc按键初始化相关部分)跟踪笔记

news2024/12/25 0:47:39

文章目录

  • 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]启动时加载输入按键驱动流程而做的笔记。

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 0
    if (INPUT_LMouseDevInit() != EPDK_OK)
    {
        __wrn("INPUT_LMouseDevInit failed");
        INPUT_LKeyDevExit();
        INPUT_CoreExit();
        return EPDK_FAIL;
    }
#endif

#if CONFIG_SUPPORT_TOUCHPANEL
    if (INPUT_LTSDevInit() != EPDK_OK)
    {
        __wrn("INPUT_LTPDevInit failed");
        //INPUT_LMouseDevExit();
        INPUT_LKeyDevExit();
        INPUT_CoreExit();
        return EPDK_FAIL;
    }
#endif
    return 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)按键接法

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/358205.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LVS负载均衡

文章目录前言一、LVS模式-DR二、ipvsadm配置参数三、DR模式的部署server1:调度器&#xff08;VS&#xff09;server2:真实服务器&#xff08;RS&#xff09;server3:真实服务器&#xff08;RS&#xff09;真实服务器(server2和server3)屏蔽客户端测试&#xff1a;纯代码步骤演示…

SpringCloud保姆级搭建教程六---ElasticSearch

es下载地址&#xff1a;https://www.elastic.co/cn/downloads/elasticsearch 最新版本或者 https://github.com/elastic/elasticsearch 7.17.9kibana下载地址&#xff1a;https://github.com/elastic/kibana 各个版本jdk8 对应的es应该是7.*版本&#xff0c;最新的es应该对应的…

【论文及代码详解】BEIT: BERT Pre-Training of Image Transformers

记录下论文《BEIT: BERT Pre-Training of Image Transformers》&#xff0c;这是一篇将Transformer应用于图像领域&#xff0c;并使用自监督方法进行参数初始化的文章。 论文链接 整体概要 由于网络整体流程图没有标注好模型的运行过程&#xff0c;结合论文的描述&#xff1a…

收藏,核心期刊的投稿、审稿、出刊流程详解

学术期刊论文&#xff08;核心和普刊&#xff09;的发表流程总的来说其实是一样的&#xff0c;整个流程包括&#xff1a;1写作-2选择刊物-3投稿-4审稿-5返修或拒稿-6录用-7出刊-8上网检索。 其中1和2其实顺序是可以调换的&#xff0c;可以选择好刊物再写作&#xff0c;根据刊物…

麦克风阵列波束基本概念理解

波束形成 本质上是设计合适的滤波器&#xff0c;对于一类固定滤波器系数的阵列来说&#xff0c;无论输入信号或者噪声信号的统计特征如何&#xff0c;其滤波器系数固定不变&#xff0c;此类波束形成叫Fixed Beamforming&#xff0c;固定波束形成好比传统数字信号处理里面的经典…

TCP并发服务器(多进程与多线程)

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 TCP并发服务器&#xff08;多进程与多线程&#xff09;1. 多进程并发服务器&#xff08;1&#xff09;…

NPDP认证|2023年,0基础转行产品经理可以吗?

2023年&#xff0c;告别了疫情&#xff0c;各个行业正在快速回暖&#xff0c;很多企业都在高薪招聘产品经理岗位&#xff0c;这让很多其他岗位的朋友也想转行做产品经理&#xff0c;那没有基础&#xff0c;没有经验能转行做产品经理吗&#xff1f; 0基础转行产品经理是可能的&a…

Redis 删除策略

过期数据Redis中的数据特征 Redis是一种内存级数据库&#xff0c;所有数据均存放在内存中&#xff0c;内存中的数据可以通过TTL指令获取其状态XX &#xff1a;具有时效性的数据-1 &#xff1a;永久有效的数据-2 &#xff1a;已经过期的数据 或 被删除的数据 或 未定义的数据数…

Windows出现0xc00d36e5错误怎么办?

当我们使用Windows Media Player来播放视频文件时&#xff0c;可能会出现无法播放&#xff0c;并显示0xc00d36e5错误代码。该错误可能是因为Windows Media Player不支持视频格式、注册表项损坏、系统配置问题、第三方应用程序冲突等。下面将开始介绍0xc00d36e5错误的解决方法&a…

K_A12_014 基于STM32等单片机驱动S12SD紫外线传感器模块 串口与OLED0.96双显示

K_A12_014 基于STM32等单片机驱动S12SD紫外线传感器模块 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:数据对比&#xff1a;四、部分代码说明1、接线引脚定义1.1、STC89C52RCS12SD紫外线传感器模块1.2、STM32F103…

【数据结构】P0 三要素与五个特征

三要素与五个特征什么是数据结构数据结构的三要素逻辑结构存储结构数据的运算算法的五个特征时间复杂度什么是数据结构 数据元素之间存在着一种或者多种关系&#xff0c;这种关系称为结构。 数据结构的三要素 数据结构的三要素&#xff1a;逻辑结构、存储结构、数据的运算。 …

【面试题】手写防抖和节流

1. 手写防抖 debounce 首先介绍一个防抖的应用场景。假如需要监听一个输入框在输入文字后触发的change事件&#xff0c;那么通过keyup事件&#xff0c;每次输入文字后都会触发change事件&#xff0c;频繁触发的情况会影响系统的性能。因此可以使用防抖来降低触发频率&#xff…

flutter系列之:在flutter中使用导航Navigator

文章目录简介flutter中的NavigatorNavigator的使用总结简介 一个APP如果没有页面跳转那么是没有灵魂的&#xff0c;页面跳转的一个常用说法就是Navigator,flutter作为一个最为优秀的前端框架&#xff0c;Navigator肯定是必不可少的&#xff0c;那么在flutter中如何使用Navigat…

自建Git服务器

Gitea - Git with a cup of tea是一个国外团队基于国内一位大牛写的gogs开源项目&#xff08;Go语言开发&#xff09;二次开发的轻量Git社区&#xff0c;其稳定性非常好&#xff0c;而且是非常轻量级在个人亲测在1核1G的centos7主机上1个月不重启依然稳定运行&#xff0c;引用g…

chatgpt怎么去玩?解析各种用途和强大的功能

关于chatgpt怎么玩&#xff1f;他的一些原理以及玩法&#xff0c;相信大家都是挺好奇的吧&#xff0c;毕竟这个新的人工智能和以往我们玩过的&#xff0c;是完全不一样的&#xff0c;它具备更多的可玩性&#xff0c;而且具备有一定的学习能力&#xff0c;这就造就了它的强大&am…

记一次IDE的Docker插件实战(Dockfile篇)

IDEA下使用Docker插件制作镜像、推送及运行 前言 本部分主要根据IDEA的Docker插件实战(Dockerfile篇)_程序员欣宸的博客-CSDN博客_idea编写dockerfile一文所述内容进行实践&#xff0c;并对其中遇到的问题进行解答&#xff0c;从而串接多个知识点。 如何编写Dockfile 在Int…

【elasticsearch】elasticsearch es读写原理

一、前言&#xff1a; 今天来学习下 es 的写入原理。 Elasticsearch底层使用Lucene来实现doc的读写操作&#xff1a; Luence 存在的问题&#xff1a; 没有并发设计 lucene只是一个搜索引擎库&#xff0c;并没有涉及到分布式相关的设计&#xff0c;因此要想使用Lucene来处理海量…

「可信计算」与软件行为学

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…

亮个相吧小宝贝儿,五款压箱底的软件

今天要给大家推荐5款压箱底的宝贝软件了&#xff0c;百度搜索一下就能找到下载链接了。 1.开源浏览器——Firefox Firefox是一个自由的&#xff0c;开放源码的浏览器&#xff0c;适用于 Windows, Linux 和 MacOS X平台&#xff0c;Mozilla Firefox官方版体积小速度快&#xf…

【项目】Vue3+TS CMS 登录模块搭建

&#x1f4ad;&#x1f4ad; ✨&#xff1a;Vue3 TS   &#x1f49f;&#xff1a;东非不开森的主页   &#x1f49c;: keep going&#x1f49c;&#x1f49c;   &#x1f338;: 如有错误或不足之处&#xff0c;希望可以指正&#xff0c;非常感谢&#x1f609;   Vue3TS一、…