【已解决】IO中断问题
请问一下,我使用tuya-ble-sdk-demo-project-tlsr8253 这份SDK,有IO中断的例程吗?我现在遇到的问题是io中断没有进入中断函数(irq_handler)
请问一下,我使用tuya-ble-sdk-demo-project-tlsr8253 这份SDK,有IO中断的例程吗?我现在遇到的问题是io中断没有进入中断函数(irq_handler)
telink的中断只有一个入口 ,这个入口在main.c中的 void irq_handler(void)函数中。IO口配置为中断后,当中断触发时,首先进入这个函数,然后通过判断标志位来确定是否有GPIO IO中断: if (reg_irq_src & FLD_IRQ_GPIO_EN) , 由于无法区分是哪个GPIO 触发的中断, 在中断处理中还需要读一下IO的电平状态来确定是否是目标GPIO IO触发中断。
例子:
1、通过vscode 的wind ide 插件拉下涂鸦OS版本的telink ble sdk, 里面的按键组件同时用到了中断和唤醒。可供参考
2、这里简单用伪码描述下
Code: Select all
_attribute_ram_code_ void irq_handler(void)
{
// ble 协议栈的处理函数必须在中断的最上层
irq_blt_sdk_handler ();
if (reg_irq_src & FLD_IRQ_GPIO_EN)
{
reg_irq_src |= FLD_IRQ_GPIO_EN;
// irq handler
}
}
void ty_gpio_input_irq_init(void)
{
gpio_set_func(GPIO_PC0, AS_GPIO);
gpio_set_output_en(GPIO_PC0, 0);
gpio_set_input_en(GPIO_PC0, 1);
#ifdef HIGH_ACTIVE
gpio_setup_up_down_resistor(GPIO_PC0, PM_PIN_PULLDOWN_100K);
gpio_set_interrupt_pol(GPIO_PC0, POL_RISING);
gpio_en_interrupt(GPIO_PC0, 0); //disable the pin's irq
cpu_set_gpio_wakeup(GPIO_PC0, Level_High, 1);//wakeup enable
#else
gpio_setup_up_down_resistor(GPIO_PC0, PM_PIN_PULLUP_10K);
gpio_set_interrupt_pol(GPIO_PC0, POL_FALLING);
gpio_en_interrupt(GPIO_PC0, 0);
cpu_set_gpio_wakeup(GPIO_PC0, Level_Low, 1);
#endif
reg_gpio_wakeup_irq |= FLD_GPIO_CORE_INTERRUPT_EN;
irq_clr_src(); //清除所有中断标志位
reg_irq_mask |= FLD_IRQ_GPIO_EN;
// 使能中断
gpio_en_interrupt(GPIO_PC0, 1);
}
注意 ,当时设备进入深度休眠后 ,每次唤醒都需要将IO再次初始化
安装给的例程,我添加上去了,不行,io是低电平有效,哪里还需要修改的吗?
Code: Select all
_attribute_ram_code_ void irq_handler(void)
{
// ble 协议栈的处理函数必须在中断的最上层
irq_blt_sdk_handler ();
#if (HCI_ACCESS==HCI_USE_UART)
unsigned char irqS = dma_chn_irq_status_get();
if(irqS & FLD_DMA_CHN_UART_RX) //rx
{
dma_chn_irq_status_clr(FLD_DMA_CHN_UART_RX);
u8* w = spp_rx_fifo.p + (spp_rx_fifo.wptr & (spp_rx_fifo.num-1)) * spp_rx_fifo.size;
if(w[0]!=0)
{
my_fifo_next(&spp_rx_fifo);
u8* p = spp_rx_fifo.p + (spp_rx_fifo.wptr & (spp_rx_fifo.num-1)) * spp_rx_fifo.size;
reg_dma_uart_rx_addr = (u16)((u32)p); //switch uart RX dma address
}
}
if(irqS & FLD_DMA_CHN_UART_TX) //tx
{
dma_chn_irq_status_clr(FLD_DMA_CHN_UART_TX);
}
#endif
if (reg_irq_src & FLD_IRQ_GPIO_EN)
{
reg_irq_src |= FLD_IRQ_GPIO_EN;
// irq handler
user_key_irq_handler();
}
static void ty_gpio_input_irq_init(void)
{
gpio_set_func(KEY_PIN, AS_GPIO);
gpio_set_output_en(KEY_PIN, 0);
gpio_set_input_en(KEY_PIN, 1);
#ifdef HIGH_ACTIVE
gpio_setup_up_down_resistor(KEY_PIN, PM_PIN_PULLDOWN_100K);
gpio_set_interrupt_pol(KEY_PIN, POL_RISING);
gpio_en_interrupt(KEY_PIN, 0); //disable the pin's irq
cpu_set_gpio_wakeup(KEY_PIN, Level_High, 1);//wakeup enable
#else
gpio_setup_up_down_resistor(KEY_PIN, PM_PIN_PULLUP_10K);
gpio_set_interrupt_pol(KEY_PIN, POL_FALLING);
gpio_en_interrupt(KEY_PIN, 0);
cpu_set_gpio_wakeup(KEY_PIN, Level_Low, 1);
#endif
reg_gpio_wakeup_irq |= FLD_GPIO_CORE_INTERRUPT_EN;
irq_clr_src(); //清除所有中断标志位
reg_irq_mask |= FLD_IRQ_GPIO_EN;
// 使能中断
gpio_en_interrupt(KEY_PIN, 1);
}
}
void user_key_init(void)
{
/* key gpio init */
//ty_pin_init(KEY_PIN, TY_PIN_MODE_IN_PU);
ty_gpio_input_irq_init();
}
void user_key_irq_handler(void)
{
//TUYA_APP_LOG_DEBUG("======>key irq.");
user_key_start_timer();
}
ty_system_enter_suspend();调用了这个进入sleep,有影响吗?
首先 ,不调用 ty_system_enter_suspend ,即让芯片保持唤醒状态, 看看中断有无效果。
如果确定中断有效,那你需要在芯片每次唤醒的时候都初始化一下GPIO。唤醒后芯片会跑到 user_init_deepRetn 这个函数 , 在这个函数的最下面添加 user_key_init();
可以了。再请教一下另外一个问题,调用了ty_system_enter_suspend,唤醒之后要调用这个函数 ty_system_exit_suspend 吗?
不需要。
这两个函数其实就是对休眠标志位的置1和清0,底层通过判断这个标志位来确定是否允许进入休眠。
ty_system_enter_suspend 执行之后并打开蓝牙广播/蓝牙连接,底层就会以蓝牙广播/蓝牙连接的interval来确定休眠唤醒周期。如果有定时器 ,就会综合定时器timeout时间和蓝牙广播/蓝牙连接interval时间来确定休眠唤醒周期。
通过验证,创建一个1000ms的定时器, 进入睡眠,会一直进入 user_init_deepRetn 这个函数,那一直初始化,会不会出现其他问题?
Code: Select all
_attribute_ram_code_ void user_init_deepRetn(void)
{
blc_ll_initBasicMCU(); //mandatory
ty_ble_set_tx_power(RF_POWER_P3p01dBm);
blc_ll_recoverDeepRetention();
extern int sdk_mainLoop_run_flag;
sdk_mainLoop_run_flag = 0;
extern u8 blt_dma_tx_rptr;
blt_dma_tx_rptr = 0;
irq_enable();
////////////////// SPP initialization ///////////////////////////////////
//note: dma addr must be set first before any other uart initialization!
ty_uart_init();
ty_pin_init(0,0);
blt_soft_timer_init();
extern void user_dev_exit_sleep(void);
user_dev_exit_sleep();
}
void user_dev_exit_sleep(void)
{
//ty_system_exit_suspend();
//TUYA_APP_LOG_DEBUG("======>exit sleep");
//user_set_enter_sleep_t(2);
user_key_init();
user_led_init();
}
wt呃呃 2023年 Mar 21日 16:07通过验证,创建一个1000ms的定时器, 进入睡眠,会一直进入 user_init_deepRetn 这个函数,那一直初始化,会不会出现其他问题?
Code: Select all
_attribute_ram_code_ void user_init_deepRetn(void) { blc_ll_initBasicMCU(); //mandatory ty_ble_set_tx_power(RF_POWER_P3p01dBm); blc_ll_recoverDeepRetention(); extern int sdk_mainLoop_run_flag; sdk_mainLoop_run_flag = 0; extern u8 blt_dma_tx_rptr; blt_dma_tx_rptr = 0; irq_enable(); ////////////////// SPP initialization /////////////////////////////////// //note: dma addr must be set first before any other uart initialization! ty_uart_init(); ty_pin_init(0,0); blt_soft_timer_init(); extern void user_dev_exit_sleep(void); user_dev_exit_sleep(); } void user_dev_exit_sleep(void) { //ty_system_exit_suspend(); //TUYA_APP_LOG_DEBUG("======>exit sleep"); //user_set_enter_sleep_t(2); user_key_init(); user_led_init(); }
这里的初始化有两个地方需要注意:
1、芯片执行了这个函数,说明是从deepsleep状态唤醒。当芯片进入deepsleep后,所有芯片内部外设都会掉电(包括uart iic spi gpio等)所以唤醒后 ,这部分的初始化需要再执行一遍。
2、芯片休眠后,虽然芯片内部外设掉电, 但是sram都还保持着,所以纯软件的东西不需要再初始化(包括软件定时器的创建,各种变量参数等)