我是 Zephyr 的新手,我尝试将我所有的嵌入式软件都交给 Zephyr。我尝试了 Zephyr 文档和大量谷歌搜索,但很难弄清楚如何做到这一点。我试图了解“设备树”是如何工作的,以及如何在应用程序内部和 Zephyr 系统端外部使用它。我试着通过样品,看看它们是如何组合在一起的。现在我正在测试... zephyrproject/zephyr/samples/basic/button/。
我有一个输入(按钮)和一个可选输出(LED)。输入也可以是 ADC 多路复用器的模拟输入。我对其进行了一些修改,它做了它应该做的事情。但我想改变它来做更多的事情。我还想让这个中断(除其他外)让 CPU 脱离深度睡眠。工作完成后重新进入深度睡眠。
Question_1:如何禁用中断,将输入从中断输入更改为模拟输入(在中断/回调处理程序中)并启动ADC?然后,在另一个线程中,我想读取 ADC 并将输入更改回中断输入,启用它,做我想做的任何事情,然后回到深度睡眠。
如何以“Zephyr 方式”完成此操作(因此它可以在不同平台上工作),我在我的 nrf52dk_nrf52832(没有 Zephyr)上执行此操作,它可以满足我的需求。
输入来自带有一个输出的数字键盘,在按键按下时变为高电平,然后返回到每个按键都不同的模拟电平,松开按键时电平变为零。当然,目标是解码按下的键,并使用一条 io 行来完成。
问题_2:何时/如果这适用于 Zephyr;我该怎么做才能使其成为正确的 Zephyr 设备驱动程序?
最好有示例来执行此操作,所有操作都在应用程序中完成。还有一个是用 Zephyr“key_pad_device_driver”完成的。
(在我的非 Zephyr 系统中,我在中断后稍等片刻(大约 0.3 - 3 ms),然后读取 10 个模拟样本,丢弃两个最高和两个最低值,然后如果这些之间的跨度被接受,我取它们的平均值并锁定按下的键。这工作出奇的好)。
她是我的“button/src/main.c”的代码
/*
* Copyright (c) 2016 Open-RnD Sp. z o.o.
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <device.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <sys/printk.h>
#include <inttypes.h>
#define LED_ON_TIME 100
/*
* Get button configuration from the devicetree sw0 alias.
*
* At least a GPIO device and pin number must be provided. The 'flags'
* cell is optional.
*/
#define SW0_NODE DT_ALIAS(sw0)
#if DT_NODE_HAS_STATUS(SW0_NODE, okay)
#define SW0_GPIO_LABEL DT_GPIO_LABEL(SW0_NODE, gpios)
#define SW0_GPIO_PIN DT_GPIO_PIN(SW0_NODE, gpios)
#define SW0_GPIO_FLAGS (GPIO_INPUT | DT_GPIO_FLAGS(SW0_NODE, gpios))
#else
#error "Unsupported board: sw0 devicetree alias is not defined"
#define SW0_GPIO_LABEL ""
#define SW0_GPIO_PIN 0
#define SW0_GPIO_FLAGS 0
#endif
/* LED helpers, which use the led0 devicetree alias if it's available. */
static const struct device *initialize_led(void);
static struct gpio_callback button_cb_data;
K_SEM_DEFINE(kbd_pres_sem, 0, 1); /* starts off "not available" */ // K_SEM_DEFINE(kbd_pres_sem, 1, 1); /* starts off "available" */
void bp_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
static int cp_cnt;
printk("\n# bp_cb(): %d Button pressed at: %" PRIu32 "... ", cp_cnt++, k_cycle_get_32());
k_sem_give(&kbd_pres_sem); // Giving the semaphore increments its count, unless the count is already equal to the limit.
}
/*
* The led0 devicetree alias is optional. If present, we'll use it
* to turn on the LED whenever the button is pressed.
*/
#define LED0_NODE DT_ALIAS(led0)
#if DT_NODE_HAS_STATUS(LED0_NODE, okay) && DT_NODE_HAS_PROP(LED0_NODE, gpios)
#define LED0_GPIO_LABEL DT_GPIO_LABEL(LED0_NODE, gpios)
#define LED0_GPIO_PIN DT_GPIO_PIN(LED0_NODE, gpios)
#define LED0_GPIO_FLAGS (GPIO_OUTPUT | DT_GPIO_FLAGS(LED0_NODE, gpios))
#endif
K_SEM_DEFINE(led_blink_sem, 0, 1); /* starts off "not available" */ // K_SEM_DEFINE(led_blink_sem, 1, 1); /* starts off "available" */
const struct device *button;
const struct device *led;
void main(void)
{
int ret;
int bp_cnt = 0;;
if((button = device_get_binding(SW0_GPIO_LABEL)) == NULL){
printk("Error: didn't find %s device\n", SW0_GPIO_LABEL);
return;
}
if((ret = gpio_pin_configure(button, SW0_GPIO_PIN, SW0_GPIO_FLAGS)) != 0){
printk("Error %d: failed to configure %s pin %d\n",
ret, SW0_GPIO_LABEL, SW0_GPIO_PIN);
return;
}
if((ret = gpio_pin_interrupt_configure(button, SW0_GPIO_PIN, GPIO_INT_EDGE_TO_ACTIVE)) != 0){
printk("Error %d: failed to configure interrupt on %s pin %d edg %x\n",
ret, SW0_GPIO_LABEL, SW0_GPIO_PIN, GPIO_INT_EDGE_TO_ACTIVE);
return;
}
gpio_init_callback(&button_cb_data, bp_cb, BIT(SW0_GPIO_PIN));
gpio_add_callback(button, &button_cb_data);
printk("\tSet up button at %s pin %d edg 0x%x\n", SW0_GPIO_LABEL, SW0_GPIO_PIN, GPIO_INT_EDGE_TO_ACTIVE);
led = initialize_led();
printk("\tPress the button, ");
while(1){
k_sem_take(&kbd_pres_sem, K_FOREVER); // Taking the semaphore decrements its count, unless the semaphore is unavailable (i.e. at zero).
printk("# main(): %d Button press detected at: %" PRIu32 "... ", bp_cnt++, k_cycle_get_32());
k_sem_give(&led_blink_sem); // Giving the semaphore increments its count, unless the count is already equal to the limit.
}
}
#ifdef LED0_GPIO_LABEL
void led_handler(void)
{
int lb_cnt = 0;
printk("\t######## led_handler: Start #########\n");
while(1){
gpio_pin_set(led, LED0_GPIO_PIN, 1); // ledd off
k_sem_take(&led_blink_sem, K_FOREVER); // Taking the semaphore decrements its count, unless the semaphore is unavailable (i.e. at zero).
printk(" # led_handler(): %d Led blink", lb_cnt++);
gpio_pin_set(led, LED0_GPIO_PIN, 0); // ledd on
k_msleep(LED_ON_TIME); // k_msleep(3000);
}
}
#define STACKSIZE 1024 /* size of stack area used by each thread */
#define PRIORITY 7 /* scheduling priority used by each thread */
K_THREAD_DEFINE(led_handler_id, STACKSIZE, led_handler, NULL, NULL, NULL, PRIORITY, 0, 0);
#endif /* LED0_GPIO_LABEL */
static const struct device *initialize_led(void)
{
#ifdef LED0_GPIO_LABEL
const struct device *led;
int ret;
led = device_get_binding(LED0_GPIO_LABEL);
if (led == NULL) {
printk("Didn't find LED device %s\n", LED0_GPIO_LABEL);
return NULL;
}
ret = gpio_pin_configure(led, LED0_GPIO_PIN, LED0_GPIO_FLAGS);
if (ret != 0) {
printk("Error %d: failed to configure LED device %s pin %d flg %x\n",
ret, LED0_GPIO_LABEL, LED0_GPIO_PIN, LED0_GPIO_FLAGS);
return NULL;
}
printk("\tSet up LED at %s pin %d flg 0x%x\n", LED0_GPIO_LABEL, LED0_GPIO_PIN, LED0_GPIO_FLAGS);
return led;
#else /* !defined(LED0_GPIO_LABEL) */
printk("No LED device was defined\n");
return NULL;
#endif /* LED0_GPIO_LABEL */
}
Zephyr 应用程序还有更多配置内容,但对于能够回答这个问题的应用程序,我认为现在并不重要。但我认为答案确实需要一些配置才能工作。