13、nRF52xx蓝牙学习(GPIOTE组件方式的任务配置)
nrfx_err_t nrfx_gpiote_out_init(nrfx_gpiote_pin_t pin,
nrfx_gpiote_out_config_t const * p_config)
{
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
NRFX_ASSERT(p_config);
nrfx_err_t err_code = NRFX_SUCCESS;
if (pin_in_use(pin))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
else
{
if (p_config->task_pin)
{
int8_t channel = channel_port_alloc(pin, NULL, true);
if (channel != NO_CHANNELS)
{
nrf_gpiote_task_configure((uint32_t)channel,
pin,
p_config->action,
p_config->init_state);
}
else
{
err_code = NRFX_ERROR_NO_MEM;
}
}
else
{
pin_in_use_set(pin);
}
if (err_code == NRFX_SUCCESS)
{
if (p_config->init_state == NRF_GPIOTE_INITIAL_VALUE_HIGH)
{
nrf_gpio_pin_set(pin);
}
else
{
nrf_gpio_pin_clear(pin);
}
nrf_gpio_cfg_output(pin);
pin_configured_set(pin);
}
}
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrfx_gpiote_out_init 函数的主要作用是初始化一个 GPIO 引脚作为 GPIOTE(通用外设中断和事件)的输出引脚。它接收一个引脚编号和一个配置结构体指针作为参数,根据配置对引脚进行相应的初始化设置,并返回初始化结果的错误码。
函数参数 • nrfx_gpiote_pin_t pin:要初始化的 GPIO 引脚编号。
• nrfx_gpiote_out_config_t const * p_config:指向 GPIO 输出配置结构体的指针,该结构体包含了引脚的各种配置信息,如是否作为任务引脚、引脚动作、初始状态等。
nrfx_gpiote_out_config_结构体定义如下 :
typedef struct
{
nrf_gpiote_polarity_t action; /**< Configuration of the pin task. */
nrf_gpiote_outinit_t init_state; /**< Initial state of the output pin. */
bool task_pin; /**< True if the pin is controlled by a GPIOTE task. */
} nrfx_gpiote_out_config_t;
其中nrf_gpiote_outinit_t是枚举类型,其定义如下 :
typedef enum
{
NRF_GPIOTE_INITIAL_VALUE_LOW = GPIOTE_CONFIG_OUTINIT_Low, ///< Low to high.
NRF_GPIOTE_INITIAL_VALUE_HIGH = GPIOTE_CONFIG_OUTINIT_High ///< High to low.
} nrf_gpiote_outinit_t;
NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
NRFX_ASSERT(p_config);
NRFX_ASSERT 是一个断言宏,用于在开发和调试阶段检查某些条件是否满足。如果条件不满足,程序会触发断言失败,帮助开发者快速定位问题。
nrf_gpio_pin_present_check(pin) 检查指定的引脚是否存在
m_cb.state == NRFX_DRV_STATE_INITIALIZED 检查 GPIOTE 驱动的状态是否已经初始化。
p_config 检查配置结构体指针是否有效。
if (pin_in_use(pin))
{
err_code = NRFX_ERROR_INVALID_STATE;
}
pin_in_use(pin) 函数检查指定的引脚是否已经被使用。如果该引脚已经被使用,则将错误码设置为 NRFX_ERROR_INVALID_STATE,表示状态无效。
else
{
if (p_config->task_pin)
{
int8_t channel = channel_port_alloc(pin, NULL, true);
if (channel != NO_CHANNELS)
{
nrf_gpiote_task_configure((uint32_t)channel,
pin,
p_config->action,
p_config->init_state);
}
else
{
err_code = NRFX_ERROR_NO_MEM;
}
}
如果引脚未被使用,检查配置结构体中的 task_pin 字段。
如果 task_pin 为真,表示该引脚要作为任务引脚使用。
channel_port_alloc(pin, NULL, true) 函数尝试为该引脚分配一个 GPIOTE 通道。如果分配成功,返回通道编号;如果没有可用通道,返回 NO_CHANNELS。
如果通道分配成功,调用 nrf_gpiote_task_configure 函数对该通道进行配置,传入通道编号、引脚编号、引脚动作和初始状态等参数。
如果通道分配失败,将错误码设置为 NRFX_ERROR_NO_MEM,表示内存不足(这里实际是没有可用的 GPIOTE 通道)。
channel_port_alloc函数代码如下:
static int8_t channel_port_alloc(uint32_t pin, nrfx_gpiote_evt_handler_t handler, bool channel)
{
int8_t channel_id = NO_CHANNELS;
uint32_t i;
uint32_t start_idx = channel ? 0 : GPIOTE_CH_NUM;
uint32_t end_idx =
channel ? GPIOTE_CH_NUM : (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS);
// critical section
for (i = start_idx; i < end_idx; i++)
{
if (m_cb.handlers[i] == FORBIDDEN_HANDLER_ADDRESS)
{
pin_in_use_by_te_set(pin, i, handler, channel);
channel_id = i;
break;
}
}
// critical section
return channel_id;
}