完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
平台:Android 8.3326 UBOOT:U-Boot 2017.09 RESET和Recovery SoC需求:RESET可以复用为Recovery脚,从而激活Loader模式。
引导进入系统后,SET为重置键。引导前uboot启动检测阶段,RESET为恢复键。
int board_late_init(void) { #if (CONFIG_ROCKCHIP_BOOT_MODE_REG > 0) setup_boot_mode(); #endif #ifdef CONFIG_DM_CHARGE_DISPLAY charge_display(); #endif #ifdef CONFIG_DRM_ROCKCHIP rockchip_show_logo(); #endif rockchip_set_serialno(); soc_clk_dump(); return rk_board_late_init(); } 10CONFIG_ROCKCHIP_BOOT_MODE_REG定义为0xff010200,接下来执行boot模式检测。 在boot_mode.c中: int setup_boot_mode(void) { int boot_mode = BOOT_MODE_NORMAL; char env_preboot[256] = {0}; devtype_num_envset(); rockchip_dnl_mode_check(); ... } rockchip_dnl_mode_check()检测download行为,条件为真时执行download loader模式 void rockchip_dnl_mode_check(void) { if (rockchip_dnl_key_pressed()) { if (rockchip_u2phy_vbus_detect()) { printf("download key pressed, entering download mode...n"); /* If failed, we fall back to bootrom download mode */ run_command_list("rocku*** 0 ${devtype} ${devnum}", -1, 0); set_back_to_bootrom_dnl_flag(); do_reset(NULL, 0, 0, NULL); } else { printf("recovery key pressed, entering recovery mode!n"); env_set("reboot_mode", "recovery"); } } } 主要函数为rockchip_dnl_key_pressed(void) __weak int rockchip_dnl_key_pressed(void) { int keyval = false; /* * This is a generic interface to read key */ #if defined(CONFIG_DM_KEY) keyval = key_read(KEY_VOLUMEUP); return key_is_pressed(keyval); #elif defined(CONFIG_ADC) const void *blob = gd->fdt_blob; unsigned int val; int channel = 1; int node; int ret; u32 chns[2]; node = fdt_node_offset_by_compatible(blob, 0, "adc-keys"); if (node >= 0) { if (!fdtdec_get_int_array(blob, node, "io-channels", chns, 2)) channel = chns[1]; } /*读取当前channel的键值*/ ret = adc_channel_single_shot("saradc", channel, &val); if (ret) { printf("%s adc_channel_single_shot fail! ret=%dn", __func__, ret); return false; } if ((val >= KEY_DOWN_MIN_VAL) && (val <= KEY_DOWN_MAX_VAL)) return true; else return false; #endif return keyval; } 一、CONFIG_DM_KEY 由于平台默认开启了CONFIG_DM_KEY,因此会调用key-uclass,这里涉及以下及部分代码: adc_key.c ------> 读取dts里面的adc配置 key-uclass.c ----> 提供api读取判断按键状态 boot_mode.c ----> download模式检测 adc_key.c 要使用按键检测,平台默认为判断KEY_VOLUMEUP按键,因此dts需要配置如下: adc-keys { status = "okay"; compatible = "adc-keys"; io-channels = <&saradc 2>; io-channel-names = "buttons"; poll-interval = <100>; keyup-threshold-microvolt = <1800000>; vol-up-key { linux,code = label = "volume up"; press-threshold-microvolt = <40>; }; }; 注:press-threshold-microvolt可以灵活配置,最终目的是通过key-uclass的键值域检测 dts配置好后,adc_key驱动会读取并将该key信息加入由key-uclass维护的key_list链表,驱动任务结束。 boot_mode.c download模式检测时,调用key_read(KEY_VOLUMEUP)获取按键状态,检测的重点就是该函数。 当检测到KEY_VOLUMEUP是KEY_PRESS_DOWN或者KEY_PRESS_LONG_DOWN时,才会进入download loader模式,否则正常启动。 key-uclass.c 现在来看看按键状态检测的重点:key_read() int key_read(int code) { struct udevice *dev; struct input_key *key; static int initialized; unsigned int adcval; int keyval = KEY_NOT_EXIST; int found = 0, ret; /* Initialize all key drivers */ if (!initialized) { for (uclass_first_device(UCLASS_KEY, &dev); dev; uclass_next_device(&dev)) { debug("%s: dev.name = %sn", __func__, dev->name); ; } } /* Search on the key list */ list_for_each_entry(key, &key_list, link) { if (key->code == code) { found = 1; break; } } if (!found) goto out; /* Is a adc key? */ if (key->type & ADC_KEY) { ret = adc_channel_single_shot("saradc", key->channel, &adcval); if (ret) printf("%s: failed to read saradc, ret=%dn", key->name, ret); else keyval = key_read_adc_simple_event(key, adcval); /* Is a gpio key? */ } else if (key->type & GPIO_KEY) { /* All pwrkey must register as an interrupt event */ if (key->code == KEY_POWER) { keyval = key_read_gpio_interrupt_event(key); } else { keyval = key_read_gpio_simple_event(key); } } else { printf("%s: invalid key type!n", __func__); } debug("%s: key.name=%s, code=%d, keyval=%dn", __func__, key->name, key->code, keyval); out: return keyval; } 首先,会从链表key_list中查找是否有KEY_VOLUMEUP按键,若dts中没有配置KEY_VOLUMEUP按键,程序返回KEY_NOT_EXIST;若dts中有配置KEY_VOLUMEUP按键,在adc_key初始化时已经将按键信息假如到链表key_list中,这里found就会置1,程序继续执行。 因为配置的是adc按键类型,先获取当前adc键值然后调用key_read_adc_simple_event()来真正的检测按键状态: /* * What's simple and complex event mean? * * simple event: key press down or none; * complext event: key press down, long down or none; */ static int key_read_adc_simple_event(struct input_key *key, unsigned int adcval) { int max, min, margin = 30; int keyval; /* Get min, max */ max = key->adcval + margin; if (key->adcval > margin) min = key->adcval - margin; else min = 0; debug("%s: %s: val=%d, max=%d, min=%d, adcval=%dn", __func__, key->name, key->adcval, max, min, adcval); /* Check */ if ((adcval <= max) && (adcval >= min)) { keyval = KEY_PRESS_DOWN; debug("%s key pressed..n", key->name); } else { keyval = KEY_PRESS_NONE; } return keyval; } 有两个值:key->adcval和adcval key->adcval是从dts中获取到的按键press-threshold-microvolt信息,经过以下处理: ofnode_read_u32(node, "press-threshold-microvolt", µvolt); /* Convert microvolt to adc value */ key->adcval = microvolt / (key->vref / 1024); adcval是读取到的当前adc键值 先根据key->adcval得出按键检测域的最大值和最小值,再通过当前adc键值adcval和这两个值对比,若在区间内,则认为按键是按下的,返回按键状态KEY_PRESS_DOWN。若不在区间内,则返回按键状态KEY_PRESS_NONE。 因此,key_read(KEY_VOLUMEUP)有两种状态(GPIO按键暂不讨论): KEY_PRESS_DOWN和KEY_PRESS_NONE 最后在boot_mode中,调用key_is_pressed(keyval) int key_is_pressed(int keyval) { return (keyval == KEY_PRESS_DOWN || keyval == KEY_PRESS_LONG_DOWN); } 如果按键是KEY_PRESS_DOWN或KEY_PRESS_LONG_DOWN(按键为GPIO类型)时,返回true 注:由于硬件原因,RESET开机时的adc值为36,因此需要修改默认的margin为40,否则也检测不到按键按下。 二、CONFIG_ADC uboot当中还有另外一种方式检测download模式,使用该方式首先需要关闭CONFIG_DM_KEY,默认是开启的。 该方式检测更简单,通过对比adc键值是否在KEY_DOWN_MIN_VAL和KEY_DOWN_MAX_VAL区间内来判断按键是否按下,并且不会判断按键code,代码如下: #define KEY_DOWN_MIN_VAL 0 #define KEY_DOWN_MAX_VAL 30 if ((val >= KEY_DOWN_MIN_VAL) && (val <= KEY_DOWN_MAX_VAL)) return true; else return false; 因此,当键值val在区间KEY_DOWN_MIN_VAL和KEY_DOWN_MAX_VAL中时返回true,否则返回false。 注:同样需要修改KEY_DOWN_MAX_VAL为40,但是dts中可以不用配置按键code,只需要配置adc需要检测的channel即可。 三、总结 两种方式都可以满足RESET复用为Recovery使用,各有各的特点。 相同点:
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案
1070 浏览 0 评论
1248 浏览 1 评论
981 浏览 1 评论
2263 浏览 1 评论
3586 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-29 11:32 , Processed in 0.512267 second(s), Total 70, Slave 54 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号