除錯備忘錄-SWD協議解析

洛神殤發表於2021-05-30
目錄--點選可快速直達

寫在前面

最近由於公司需要,所以就做了個基於SWD協議的離線燒寫器。由於過程中參考了很多大神的文章,因此就想寫個隨筆記錄下。整個燒寫器由三個部分組成分別為:

  • SWD協議讀寫晶片內部暫存器、RAM、Flash.
  • STM32 + SPI + Flash + USB + FAFTS,通過USB虛擬出一個U盤,將要燒寫的BIN檔案放到這個U盤中,就可以燒寫了.
  • OLED + 按鍵,實現簡單的操作頁面.

本章先對SWD協議進行解析,整個文章主要分了三個部分,第一部分是對SWD協議進行簡介;第二部分是對SWD協議進行物理層上的解析;

1  SWD協議簡介

SWD的全稱應該是The Serial Wire Debug Port(SW-DP),也就是序列除錯埠,是ARM目前支援的兩種除錯埠之一,另一個除錯埠叫做JTAG Debug Port,也就是我們常用的J-link上面的除錯埠(JTAG模式下)。

基於ARM CoreSight除錯構架,SWD可以通過傳輸資料包來讀寫晶片的暫存器。

2  SWD物理層協議解析

SWD需要三根線與目標的MCU連線,分別為SWDIO、SWDCLK和GND.後面的內容中,HOST為主機,就是我們提供的SCK的一方;TARGET為目標MCU。

  • SWDIO為雙向Data線,主機讀寫目標晶片資料。
  • SWDCLK為時鐘線,類似於SPI需要由主機提供時鐘。同時,資料都是在時鐘下降沿讀取,上升沿進行資料翻轉。
  • GND為雙向Data口,主機讀寫目標晶片資料。

2.1  SWD通訊時序分析

首先放個寫操作成功的時序圖。

從圖中可知,整個流程大致分為三部分:

  • 第一部分:HOST -> TARGET 主機傳送讀寫命令,這部分指定了讀寫操作,指定了要訪問AP還是DP,還指定了ADDR。
  • 第二部分:TARGET -> HOST 目標MCU回覆Ack,通知主機是否可以繼續操作。
  • 第三部分:HOST -> TARGET 主機寫資料

下面,我們針對圖中的一些名詞做出解釋:

  • Start: 一位起始位,值為1。
  • APnDP: 一位,表示訪問的是DP暫存器還是AP暫存器,0:DP,1: AP。
  • RnW: 一位,表明是讀操作還是寫操作,0:寫,1:讀。
  • ADDR[2:3]:兩位,給出DP或者AP暫存器地址ADDR[3:2]地址區域,傳送時低位在前(後面有具體說明)。
  • Parity: 一位 為前面的資料包提供奇偶校驗。在包頭中的校驗位校驗了APnDP, RnW and A[2:3],在資料中的校驗位校驗了32位的資料。
  • Stop: 一位,停止位,值為0。
  • Park: 一位,在傳輸該位時,主機不對SWDIO進行驅動,該線由硬體拉高(上拉),所以這位讀作一。
  • Trn: 調轉週期,在該週期中,不對線進行前驅動,實際應用時,這個時候要將SWDIO引腳的輸入輸出狀態翻轉。這個週期的時間由TURNROUND控制(位於WCR暫存器中)。
  • Ack[0:2]: 三位,目標MCU到主機的響應,低位在前。100:成功,010:等待,001:失敗。
  • WDATA[0:31]: 32位的寫資料包,由主機傳送給目標MCU。
  • RDATA[0:31]: 32位的讀資料包,由MCU傳送給主機。

值的注意的是,Trn,調轉週期,因為我們是單匯流排通訊,一根線上既有寫又有讀,而這個Trn就是發生在寫讀切換的時候的一個延時。

2.2  SWD 暫存器簡介

SWD通訊的時候主要涉及的暫存器就兩個,一個DP,一個AP。

如圖所示,DP就是Debug port,AP 就是 Access port。如果要訪問核心暫存器,就得先配置DP->AP->MEM-AP。

2.2.1  DP暫存器

DP暫存器如下圖,地址就是我們在包頭中的ADDR[2:3],這兩位指示的地址。具體的暫存器實在是太多了,具體的請參考《ARM Debug Interface v5 Architecture Specification》。

值的說明的是,匯流排復位之後,然後進行JTAG和SWD的切換操作(發0X79,0XE7或者0X6D,0XB7),然後必須先讀下IDDCODE,判斷下MCU的型別,然後才能繼續別的操作。

2.2.2  AP暫存器

AP暫存器如下路,AP暫存器相比較於DP則是複雜了很多。具體的暫存器實在是太多了,具體的請參考《ARM Debug Interface v5 Architecture Specification》。

2.3  SWD通訊流程

2.3.1  SWD復位

如下圖,ARM對SWD的復位有明確的說明,要求連續50個時鐘週期的高電平,認為是SWD復位,同時復位之後必須讀一次IDCODE(位於DP暫存器中)。

下圖是我的復位時序,多寫了5個週期的電平

2.3.2  SWD讀IDCODE

IDCODE位於SWD DP暫存器中,將地址設定為00b,讀DP操作,就可以讀到IDCODE了,根據核心型號不同,一般第一數字不一樣,我的是0x0BB11477.

下圖是我的讀IDCODE時序

2.3.3  SWD清除錯誤標誌位,並且使能AP除錯

通過寫DP中的APBORT[4:1],來清除錯誤標誌位。

通過寫DP中的CTRL/STAT[30]和CTRL/STAT[28]使能AP除錯

2.3.4  SWD讀取AP IDR(也就是AP暫存器的ID CODE)

讀取AP暫存器的步驟:

  • 第一步通過寫DP 中的SELECT暫存器,確定APBANK.
  • 第二步通過AP命令包頭的地址,確定APBANK內部的位置,傳送讀AP命令。
    如圖DP SELECT暫存器。

如圖,AP暫存器,APBANK決定的是BANK 0x0 -> BANK 0xF.ADDR[3:2]決定的是BANK內部的地址(ADDR[1:0]都是0),0x00,0x04,0x08,0x0C,

所以,如果我要讀取AP IDR的話,就先設定DP SELECT暫存器中的APBANKSEL為0xF,然後直接發讀AP命令,ADDR[3:2]為11b.

2.3.5  SWD讀寫MCU任意暫存器

讀取MCU任意暫存器的步驟:

  • 第一步通過寫DP 中的SELECT暫存器,確定APBANK為BANK0.
  • 第二步通過AP命令包頭的ADDR[3:2]地址,確定APBANK內部的地址為0x00(CSW),傳送寫AP命令。資料為0x23000002(該值可能有問題,此處請自行檢視CSW暫存器描述,如果這個值寫完之後依然讀不出DRW,請聯絡我).
  • 第三步通過AP命令包頭的ADDR[3:2]地址,確定APBANK內部的地址為0x04(TAR),傳送寫AP命令。資料為要讀取的暫存器地址。
  • 第四步通過AP命令包頭的ADDR[3:2]地址,確定APBANK內部的地址為0x0C(DRW),傳送讀AP命令。一次讀回來的資料無效。
  • 第五步通過AP命令包頭的ADDR[3:2]地址,確定APBANK內部的地址為0x0C(DRW),傳送讀AP命令。此時讀回來的資料為正確資料。(這裡讀DP的RDBUFF也可以,詳細請自行查閱暫存器文件)

步驟一波形:

步驟二波形:

步驟三波形:

步驟四波形:

步驟五波形:

寫入MCU任意暫存器的步驟:

  • 第一步通過寫DP 中的SELECT暫存器,確定APBANK為BANK0.
  • 第二步通過AP命令包頭的ADDR[3:2]地址,確定APBANK內部的地址為0x00(CSW),傳送寫AP命令。資料為0x23000012(該值可能有問題,此處請自行檢視CSW暫存器描述,如果這個值寫完之後依然不能寫入DRW,請聯絡我).
  • 第三步通過AP命令包頭的ADDR[3:2]地址,確定APBANK內部的地址為0x04(TAR),傳送寫AP命令。資料為要讀取的暫存器地址。
  • 第四步通過AP命令包頭的ADDR[3:2]地址,確定APBANK內部的地址為0x0C(DRW),傳送寫AP命令。寫入成功。

步驟一波形:

步驟二波形:

步驟三波形:

步驟四波形:

特殊說下,設定好CSW[5:4]之後,每次讀寫DRW之後,DRW的地址會自動+1,省去了需要每次重新設定地址的麻煩。

以上,本章的內容就結束了,通過本章的內容,可以實現SWD任意讀取MCU暫存器,如果問題,請聯絡我~~~
參考文獻:ARM Debug Interface

相關文章