痞子衡嵌入式:探析i.MXRT1050在GPIO上增加RC延時電路後導致邊沿中斷誤觸發問題(上篇)

来源:https://www.cnblogs.com/henjay724/p/18354026
-Advertisement-
Play Games

大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是i.MXRT1050在GPIO上增加RC延時電路後導致邊沿中斷誤觸發問題探析。 前段時間有一個 RT1052 客戶反饋了一個有趣的問題,他們設計得是一個帶 LCD 屏交互的應用,應用以官方 SDK 里的 lvgl_demo_widget ...



  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是i.MXRT1050在GPIO上增加RC延時電路後導致邊沿中斷誤觸發問題探析

  前段時間有一個 RT1052 客戶反饋了一個有趣的問題,他們設計得是一個帶 LCD 屏交互的應用,應用以官方 SDK 里的 lvgl_demo_widgets_bm 常式為基礎。當客戶在這個常式基礎上增加了 GPIO 輸入邊沿中斷檢測,並且硬體上給 GPIO 增加了 RC 延時電路後,發現邊沿中斷觸發得不太準確,這是怎麼回事?今天痞子衡帶大家還原現場:

一、問題描述

  客戶做得硬體改動很簡單,在 GPIO_AD_B1_04 引腳和 GPIO_AD_B1_10 引腳之間加瞭如下的 RC 延時電路。GPIO_AD_B1_04 上產生得是 500Hz 的方波(既可以是 GPIO 模塊輸出,也可以去掉 R290 後直接接信號發生器),這個方波經過 RC 電路之後輸出給 GPIO_AD_B1_10,然後通過其輸入邊沿中斷來檢測電平變化,並且在每個邊沿中斷里都翻轉一次 GPIO_AD_B1_11 電平。

  代碼改動也足夠簡單,只需要在 \SDK_2_15_000_EVKB-IMXRT1050\boards\evkbimxrt1050\lvgl_examples\lvgl_demo_widgets_bm 工程里添加 test_gpio_irq() 函數調用即可(這裡假定 GPIO_AD_B1_04 上的方波是由外部信號發生器提供的):

void GPIO1_Combined_16_31_IRQHandler(void)
{
    // 檢測到 GPIO_AD_B1_10 邊沿
    if ((GPIO1->ISR & (1U << 26)) && (GPIO1->IMR & (1U << 26)))
    {
        GPIO_PortClearInterruptFlags(GPIO1, 1U << 26);
        // 翻轉 GPIO_AD_B1_11 電平
        GPIO_PortToggle(GPIO1, 1 << 27);
        __DSB();
    }
}

void config_rc_in_gpio(void)
{
    // 配置 GPIO_AD_B1_10 為邊沿中斷輸入檢測模式
    gpio_pin_config_t in_config = { kGPIO_DigitalInput, 1, kGPIO_NoIntmode };
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_10_GPIO1_IO26, 1);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_10_GPIO1_IO26, 0x011030U);
    GPIO_PinInit(GPIO1, 26, &in_config);
    GPIO_SetPinInterruptConfig(GPIO1, 26, kGPIO_IntRisingOrFallingEdge);
    EnableIRQ(GPIO1_Combined_16_31_IRQn);
    GPIO_PortEnableInterrupts(GPIO1, 1U << 26);
}

void config_user_out_gpio(void)
{
    // 配置 GPIO_AD_B1_11 為普通輸出模式
    gpio_pin_config_t out_config = { kGPIO_DigitalOutput, 1, kGPIO_NoIntmode };
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_11_GPIO1_IO27, 0);
    GPIO_PinInit(GPIO1, 27, &out_config);
    GPIO_PinWrite(GPIO1, 27, 0U);
}

void test_gpio_irq(void)
{ 
    config_rc_in_gpio();
    config_user_out_gpio();
}

  如果 GPIO_AD_B1_10 邊沿中斷檢測無誤,那麼輸出的 GPIO_AD_B1_11 信號應該是和原始輸入 GPIO_AD_B1_04 完全同頻的方波,而事實上客戶用示波器抓到的 GPIO_AD_B1_11 信號偶爾會出現如下情況,很顯然有邊沿中斷誤觸發的情況發生:

  並且更有趣的是,這樣的測試僅在 lvgl_demo_widgets_bm 工程里能復現,而在普通 input_interrupt 工程下沒有任何問題。

  • Note1:在 lvgl_demo_widgets_bm 工程下出現的 GPIO 邊沿中斷誤觸發問題僅在增加 RC 電路時存在。
  • Note2:在普通 input_interrupt 工程下即使增加 RC 電路,GPIO 邊沿中斷誤觸發問題也不存在。

二、問題復現

  理論上分析 GPIO_AD_B1_10 引腳輸入的信號頻率是 500Hz,那麼其邊沿中斷應該是每 1ms 產生一次,而從上一節客戶抓取的 GPIO_AD_B1_11 實際信號反推,似乎有時候邊沿中斷在 10us 內連續產生了兩次。

  為了從軟體角度抓到這個中斷誤觸發現象,痞子衡稍微改了一下代碼,將 GPIO_AD_B1_04 上信號改為軟體輸出(在 SysTick 1ms 一次的中斷響應里翻轉電平),並且用了兩個計數器 s_outputPinEdgeCount、s_inputRcPinIrqCount 來分別記錄 GPIO_AD_B1_04、GPIO_AD_B1_10 邊沿次數。如果邊沿中斷觸發無誤的話,這兩個計數器的值應該是永遠相等的,但是實際跑了一段時間後發現 s_inputRcPinIrqCount 會超過 s_outputPinEdgeCount,並且隨著時間累積,差距會越來越大。這說明邊沿中斷誤觸發現象是一直存在的。

volatile uint32_t s_inputRcPinIrqCount   = 0;
volatile uint32_t s_outputPinEdgeCount = 0;

void GPIO1_Combined_16_31_IRQHandler(void)
{
    // 檢測到 GPIO_AD_B1_10 邊沿
    if ((GPIO1->ISR & (1U << 26)) && (GPIO1->IMR & (1U << 26)))
    {
        GPIO_PortClearInterruptFlags(GPIO1, 1U << 26);
        // 計數 GPIO_AD_B1_10 邊沿
        s_inputRcPinIrqCount++;
        __DSB();
    }
}

void config_rc_out_gpio(void)
{
    // 配置 GPIO_AD_B1_04 為普通輸出模式
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_04_GPIO1_IO20, 0);
    GPIO_PinInit(GPIO1, 20, &out_config);
    GPIO_PinWrite(GPIO1, 20, 0U);
}

void test_gpio_irq(void)
{ 
    config_rc_in_gpio();
    config_rc_out_gpio();
}

void SysTick_Handler(void)
{
    // 計數 GPIO_AD_B1_04 邊沿
    s_outputPinEdgeCount++;
    GPIO_PortToggle(GPIO1, 1 << 20);
    __DSB();

    // 原應用代碼省略
}

三、問題定位

  描述至此,你的第一反應到底是哪裡出了問題?痞子衡想你可能會覺得罪魁禍首是 RC 延時電路,它將標準的方波上升、下降過程變得平緩,導致信號電壓處於臨界區的時間變長(極端情況下,對於高頻信號,可能會導致其一直處於臨界區),這個可能會影響 GPIO 電平跳變判定。既如此,我們先翻看一下 RT1050 的 datasheet,找到如下 GPIO DC 參數表,其高、低電平判定值分別是 70%、30% NVCC_XXXX,此外備註里說明瞭只要電平變化是單調的(隨著時間單向增大或減小),且轉換時間範圍在 0.1ns - 1s 內均會被認定為有效跳變。

  這時候我們再根據 RC 延時電路標準時間常數公式 t = RC * $\ln (\frac{(V1-V0)}{V1-Vt})$ 來推算(V1 電源電壓、V0 電容初始時刻電壓、$V_t$ 為 t 時刻電容電壓)。如果 NVCC 為 3.3V,那麼上升沿時從 0V 充電到 2.31V 的時間是 12us,顯然這個 12us 充電時間對於 500Hz 的方波來說不足以影響其跳變判定。

  有沒有方法能抓住這個異常邊沿中斷發生時,GPIO_AD_B1_10 信號當時的波形狀態呢?當然是可以的,我們可以再修改一下邊沿中斷處理函數代碼,在裡面計算兩次中斷之間的 Tick 間隔,如果間隔 Tick 低於一定值,說明是誤觸發,此時翻轉一次 GPIO_AD_B1_11 電平用作標記。

volatile uint32_t s_systickCurVal = 0;
volatile uint32_t s_systickLastVal = 0;
volatile uint32_t s_systickCurCount = 0;
volatile uint32_t s_systickLastCount = 0;
volatile uint32_t s_systickDeltaVal;

uint32_t s_systickReloadVal = 0;

void GPIO1_Combined_16_31_IRQHandler(void)
{
     /* clear the interrupt status */
    if ((GPIO1->ISR & (1U << 26)) && (GPIO1->IMR & (1U << 26)))
    {
        s_systickCurVal = SysTick->VAL;
        s_systickCurCount = s_outputPinEdgeCount;
        GPIO_PortClearInterruptFlags(GPIO1, 1U << 26);
        // 計算兩次中斷之間的 Tick 間隔
        s_systickDeltaVal = (s_outputPinEdgeCount - s_systickLastCount) * s_systickReloadVal + s_systickLastVal - s_systickCurVal;
        s_systickLastVal = s_systickCurVal;
        s_systickLastCount = s_systickCurCount;
        // 當間隔 Tick 低於一定值時,說明是誤觸發,此時翻轉一次 GPIO_AD_B1_11 電平
        if (s_systickDeltaVal <= s_systickReloadVal / 2)
        {
            GPIO_PortToggle(GPIO1, 1 << 27);
        }
        __DSB();
    }
}

int main(void)
{
    // 應用代碼省略...
    test_gpio_irq();

    s_systickReloadVal = SystemCoreClock / (LVGL_TICK_MS * 1000U);
    s_inputRcPinIrqCount   = 0;
    s_systickLastVal = s_systickReloadVal;

    DEMO_SetupTick();
    // 應用代碼省略...
}

  如果用示波器以 GPIO_AD_B1_11 跳變為觸發信號(ch2),即能看到案發現場 GPIO_AD_B1_10 狀態(ch1),確實我們看到充放電時間內出現了短時脈衝波干擾(glitch),這個脈衝導致了電平變化不是單調的,因而產生了 GPIO 中斷誤觸發。本篇僅是定位問題,下一篇我們會具體分析這個 glitch 是如何產生的!

  至此,i.MXRT1050在GPIO上增加RC延時電路後導致邊沿中斷誤觸發問題探析(上篇)痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

文章會同時發佈到我的 博客園主頁CSDN主頁知乎主頁微信公眾號 平臺上。

微信搜索"痞子衡嵌入式"或者掃描下麵二維碼,就可以在手機上第一時間看了哦。

  最後歡迎關註痞子衡個人微信公眾號【痞子衡嵌入式】,一個專註嵌入式技術的公眾號,跟著痞子衡一起玩轉嵌入式。

痞子衡嵌入式-微信二維碼 痞子衡嵌入式-微信收款二維碼 痞子衡嵌入式-支付寶收款二維碼

  衡傑(痞子衡),目前就職於某全球頂級半導體原廠MCU系統部門,擔任高級嵌入式系統應用工程師。

  專欄內所有文章的轉載請註明出處:http://www.cnblogs.com/henjay724/

  與痞子衡進一步交流或咨詢業務合作請發郵件至 [email protected]

  可以關註痞子衡的Github主頁 https://github.com/JayHeng,有很多好玩的嵌入式項目。

  關於專欄文章有任何疑問請直接在博客下麵留言,痞子衡會及時回覆免費(劃重點)答疑。

  痞子衡郵箱已被私信擠爆,技術問題不推薦私信,堅持私信請先掃碼付款(5元起步)再發。



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ...
  • 前言 在實際項目開發中,需求變更和項目迭代是常態。要求我們能夠迅速響應,對資料庫結構進行相應的調整,如添加新表、更新現有表結構或增加欄位等。 為了確保團隊成員之間的信息同步,實時更新和維護資料庫文檔變得至關重要。這不僅提升了資料庫的可讀性,也極大提高了開發效率和團隊協作的流暢性。 SmartSQL, ...
  • 前言 .NET許可權管理及快速開發框架、最好用的許可權工作流系統。 基於經典領域驅動設計的許可權管理及快速開發框架,源於Martin Fowler企業級應用開發思想及最新技術組合(SqlSugar、EF、Quartz、AutoFac、WebAPI、Swagger、Mock、NUnit、Vue2/3、Ele ...
  • 本章將和大家分享Linux系統中的管道命令、grep命令、sed命令和awk命令。廢話不多說,下麵我們直接進入主題。 一、管道命令 Linux 中的管道命令(pipe)是一種非常強大的特性,它允許你將一個命令的輸出作為另一個命令的輸入。管道命令極大地增強了命令行的靈活性和功能,使得複雜的數據處理任務 ...
  • 1. 配置 1.1 如果是配置全局文件,則編輯/etc/mail.rc 1.2 如果是配置當前用戶,則編輯~/.mailrc 2. 配置文件內容 # 這裡填入smtp地址,這裡的xxx為qq或者163等,如果用的雲伺服器,安全組策略要開放465/25埠,入站和出站都要開放該埠 set smtp= ...
  • 一、背景 在公司軟體的實際開發中,當一個版本的客戶端安裝包本地調試、測試驗證都沒問題後外發,到用戶實際機器上出問題了,怎麼辦? 很多人說,讓客戶給出復現步驟,我來試試!但是按照步驟操作之後還是沒效果。這時你又想到了是不是環境的差異,但是又說不上來是哪裡出問題。提供兩個辦法:1.寫日誌,編一個相近版本 ...
  • 1、用戶操作 阿裡雲預設是 root 用戶,我們一般要自己創建一個用戶,然後給該用戶 sudo 許可權 添加用戶 sudo adduser newUserName 賦予sudo許可權 sudo usermod -aG sudo newUserName 刪除用戶 sudo deluser --remove ...
  • 1、Docker 基本概念 什麼是 Docker? Docker 是一個開源的容器化平臺,允許開發者封裝他們的應用程式及其所有依賴項到一個標準化的單元中,這個單元被稱為“容器”。容器可以在任何支持 Docker 的環境中運行,從而確保應用程式的可移植性和一致性。 Docker 的優勢 一致性和可移植 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...