CLA 控制律加速器終極指南 - 老張開釋啦!

(辦公室裡,老張叼著一根沒點的菸,看著新人小李對著示波器上的波形愁眉苦臉)

老張:「喂,小李。對,叫你呢,別看了,你那塊板子上的馬達再抖下去,就要原地起飛了。過來一下。」

老張:「你看你這個表情,跟便祕三天一樣。是不是覺得這顆 C2000 微控制器很秋條?主頻跑個幾百兆,功能一大堆,結果你一個小小的控制迴路,CPU 佔用率就快頂到天花板了?主程式那邊還想做個漂亮的 UI 跟通訊?門都沒有。」

老張:「我跟你說,這就是典型的『沒摸熟架構就想一步登天』的症頭。你以為德州儀器(TI)那群人是吃素的?他們早就想到這問題了。來,茶杯拿著,我今天心情好,跟你講個東西,叫做『Control Law Accelerator』,控制律加速器,簡稱 CLA。」

(罐頭音效:登登登登~ 氣勢磅礡的音樂)

開場白:CLA 是你 CPU 的神隊友!

老張:「你不要聽到『加速器』三個字就高潮了,它不是什麼氮氣瓶,按下去你的程式碼就會跑得跟火箭一樣快。你要把它想像成,你,也就是主CPU,是個大老闆,每天要管公司營運、要看財報、要跟客戶吃飯、還要應付老闆的老闆,事情多得要死。你很忙,對吧?」

老張:「現在,公司有個部門,專門負責一個極度重要、極度規律、但又極度無聊的工作,比如說,每毫秒要精準地調整一次生產線上的馬達轉速。這個工作不能等,你一分心,馬達可能就燒了,或是產品就歪了。你這個大老闆,總不能為了這件鳥事,把所有客戶的電話都掛掉吧?」

老張:「CLA 就是你請來的一個超級書呆子,一個數學宅男。你把他關在一個小房間裡,跟他說:『嘿,宅男,從現在開始,生產線上的所有數學運算,ADC 採樣一進來,你就要立刻、馬上、'Just-in-time' 地給我算完,然後把結果丟給 PWM 模組。做完你就可以繼續發呆,沒做完你就死定了。其他所有跟客戶溝通、跟老闆屁話的事情,都交給我這個大老闆來處理。』」

所以啦,簡單一句話:CLA 就是讓你把 C28x CPU 從水深火熱的即時控制迴圈中解放出來的超級賽亞人! 它能做到「Just-in-time」讀取 ADC 採樣,大幅縮短從採樣到輸出的延遲,讓你的系統反應跟閃電一樣快,控制迴圈頻率也能拉得更高。聽起來很香對不對?

(罐頭音效:烏鴉飛過… 啊… 啊… 啊…) -> (老張:喂!這音效不對吧!)

第一章:CLA 你哪位?基本盤點一下

老張:「好,概念懂了,接下來就是最噁心的部分了:你怎麼叫這個書呆子開始工作?你以為遞張紙條給他就行了?太天真了。你需要一套完整的SOP,從幫他劃定辦公區域、給他工作手冊、到教他怎麼看懂門口的提示燈。這就是我們今天要搞的,CLA 的初始化流程。你筆記本拿出來,接下來我說的每個字,都可能是你未來加班到半夜時,能救你一命的救命毫毛。」

獨立自主的山大王

它有自己的一套架構,跟 C28x CPU 各玩各的,但又能緊密合作。它有自己的:

數學小天才

它的指令集可是專為控制演算法設計的,包含:

多工處理小能手

CLA 最多可以處理八個獨立的「任務 (Task)」。你可以把它想像成 CLA 有八個專案可以同時接,但一次只做一個專案裡的一件事。

老張:「CLA 的任務是有優先權的。Task 1 優先權最高,Task 8 最低。如果 Task 2 正在執行,這時候觸發 Task 1 的信號來了,CLA 會不會放下手邊的工作,先去做 Task 1?答案是:不會!CLA 的任務是『不可嵌套』的(除非用 Type-2 CLA 的背景任務)。意思就是,書呆子一次只會專心做一件事,做完之前,天塌下來他都不會理你。搞不清楚這一點,你可能會發現為什麼你最高優先權的任務有時候會延遲。」

叫醒服務(任務觸發機制)

記憶體三劍客:劃地盤

老張:「這是所有新手的第一个天坑,也是最大的坑。你記住,CLA 跟主CPU雖然在同一顆晶片上,但他們預設是老死不相往來的。他們共用一些叫做 LSxRAM 的記憶體區塊,你可以把它想像成辦公室裡的幾塊共用大白板。」

第二章:CLA 上工啦!標準作業流程 (SOP)

老張:「好,地盤劃好了,信箱也準備好了。第二步:撰寫工作手冊,也就是 CLA 程式碼。... 第六步:開綠燈,啟用中斷。我們回顧一下:」

這個初始化流程,基本上都是由 C28x 主 CPU 來完成的。菜鳥們,筆記本拿出來,這段 SOP 很重要,搞錯一步,CLA 就躺平給你看,到時候 debug 到天荒地老,別說我沒提醒你!

  1. 步驟一:把 CLA 的程式碼「搬家」到 CLA 程式記憶體

    你寫好的 CLA 程式,CPU 的任務就是把它複製到指定的 LSxRAM 區塊。

    菜鳥OS:「為什麼不直接讓 CLA 從 Flash 讀?」

    老張:「傻孩子,Flash 比較慢啊!CLA 這種急驚風,當然要用 RAM 才跑得快!」

  2. 步驟二:(如果需要的話)初始化 CLA 資料記憶體

    如果你的 CLA 程式需要一些預設的常數、查找表、或是初始化的資料緩衝區,CPU 也要把它們填到指定的 LSxRAM 區塊。

  3. 步驟三:設定 CLA 的相關暫存器(但先別急著開中斷!)

    這個步驟最繁瑣,但也最關鍵。就像幫新員工設定電腦權限一樣。

    • 3a. 啟用 CLA 的周邊時脈 (Peripheral Clock):找到對應的 PCLKCRn 暫存器,把 CLA 的時脈打開。
    • 3b. 填寫 CLA 任務的中斷向量 (Interrupt Vectors):CLA 有八個任務,每個任務都有一個對應的向量暫存器,從 MVECT1MVECT8。要把每個 CLA 任務程式的起始位址填到對應的 MVECTx

      老張:「這樣,當 Task 1 被觸發時,CLA 就會去看 MVECT1 裡面的地址,然後跑到那個地址開始讀取指令。如果你忘了設,或是設錯了,CLA 就會跑到一個鳥不生蛋的地方去執行程式,後果你懂的。這是第五個坑。」

    • 3c. 選擇任務的中斷觸發源 (Interrupt Sources):設定 DmaClaSrcSelRegs.CLA1TASKSRCSELx[TASKx],告訴 CLA 哪個周邊事件對應到哪個任務。

      老張:「要做到這點,你需要設定一個叫做 DmaClaSrcSelRegs 的暫存器。這名字很長,但你拆開看:DMA CLA Source Select Registers。你可以把它想像成一個總機接線板...你就在這個接線板上,用跳線把『ADC A 中斷 1』連到『CLA Task 1』。這個『跳線號碼牌』就是你要填到暫存器裡的值。每個號碼牌對應一個特定的周邊中斷源。這些號碼牌寫在哪?當然是在你那本比磚頭還厚的 TRM (Technical Reference Manual) 裡面啦!你以為我會背給你聽?自己去翻,查那個 CLA 章節裡的『Configuration Options』表格,通常是 Table 7-1 那一大串!」

      TRM 是你的好朋友:具體哪個周邊對應哪個選擇值,請務必查閱 TRM 裡的 CLA 觸發源列表 (通常是 Table 7-1)。

      老張:「喏,怕你懶得翻,我把那張落落長的『CLA 任務召喚獸對照表』貼給你看。這張表就是告訴你,你要讓哪個周邊的哪個事件去叫醒 CLA 的哪個任務,你就要在 DmaClaSrcSelRegs.CLA1TASKSRCSELx[TASKx] 這個暫存器裡面填上對應的『Select Value』。看清楚啦,這可是考試重點!」

      Select Value CLA Trigger Source
      0CLA_SOFTWARE_TRIGGER
      1ADCAINT1
      2ADCAINT2
      3ADCAINT3
      4ADCAINT4
      5ADCA_EVT_INT
      6ADCBINT1
      7ADCBINT2
      8ADCBINT3
      9ADCBINT4
      10ADCB_EVT_INT
      11ADCCINT1
      12ADCCINT2
      13ADCCINT3
      14ADCCINT4
      15ADCC_EVT_INT
      16-28Reserved
      29XINT1
      30XINT2
      31XINT3
      32XINT4
      33XINT5
      34-35Reserved
      36EPWM1_INT
      37EPWM2_INT
      38EPWM3_INT
      39EPWM4_INT
      40EPWM5_INT
      41EPWM6_INT
      42EPWM7_INT
      43EPWM8_INT
      44EPWM9_INT
      45EPWM10_INT
      46EPWM11_INT
      47EPWM12_INT
      48EPWM13_INT
      49EPWM14_INT
      50EPWM15_INT
      51EPWM16_INT
      52MCANA_FEVT0
      53MCANA_FEVT1
      54MCANA_FEVT2
      55MCANB_FEVT0
      56MCANB_FEVT1
      57MCANB_FEVT2
      58EPWM17_INT
      59EPWM18_INT
      60-67Reserved
      68CPU_TINT0
      69CPU_TINT1
      70CPU_TINT2
      71-74Reserved
      75ECAP1_INT
      76ECAP2_INT
      77ECAP3_INT
      78ECAP4_INT
      79ECAP5_INT
      80ECAP6_INT
      81ECAP7_INT
      82Reserved
      83EQEP1_INT
      84EQEP2_INT
      85EQEP3_INT
      86EQEP4_INT
      87EQEP5_INT
      88EQEP6_INT
      89-91Reserved
      92ECAP6_INT2
      93ECAP7_INT2
      94Reserved
      95SD1_ERRINT
      96SD2_ERRINT
      97SD3_ERRINT
      98SD4_ERRINT
      99LINA_INT1
      100LINA_INT0
      101LINB_INT1
      102LINB_INT0
      103ECAT_SYNC0
      104ECAT_SYNC1
      105PMBUSA_INT
      106-108Reserved
      109SPIA_TXINT
      110SPIA_RXINT
      111SPIB_TXINT
      112SPIB_RXINT
      113SPIC_TXINT
      114SPIC_RXINT
      115SPID_TXINT
      116SPID_RXINT
      117CLB5_INT
      118CLB6_INT
      119-120Reserved
      121CLA_INTERRUPT1
      122Reserved
      123FSITXA_INT1
      124FSITXA_INT2
      125FSIRXA_INT1
      126FSIRXA_INT2
      127CLB1_INT
      128CLB2_INT
      129CLB3_INT
      130CLB4_INT
      131-142Reserved
      143SD1FLT1_DRINT
      144SD1FLT2_DRINT
      145SD1FLT3_DRINT
      146SD1FLT4_DRINT
      147SD2FLT1_DRINT
      148SD2FLT2_DRINT
      149SD2FLT3_DRINT
      150SD2FLT4_DRINT
      151SD3FLT1_DRINT
      152SD3FLT2_DRINT
      153SD3FLT3_DRINT
      154SD3FLT4_DRINT
      155FSITXB_INT1
      156FSITXB_INT2
      157FSIRXB_INT1
      158FSIRXB_INT2
      159FSIRXC_INT1
      160FSIRXC_INT2
      161FSIRXD_INT1
      162FSIRXD_INT2
      163-183Reserved
      184DMA_CH1INT
      185DMA_CH2INT
      186DMA_CH3INT
      187DMA_CH4INT
      188DMA_CH5INT
      189DMA_CH6INT
      190-201Reserved
      202SD4FLT1_DRINT
      203SD4FLT2_DRINT
      204SD4FLT3_DRINT
      205SD4FLT4_DRINT
      206-255Reserved
      老張:「CLA 任務觸發是對「邊緣 (edge)」敏感的,不是對「電位 (level)」。如果周邊中斷在你設定 CLA 之前就已經發生而且卡在那裡,CLA 可能會收不到那個邊緣觸發!所以,保險起見,先設定好 CLA,再啟用周邊中斷,或者在啟用 CLA 任務前,先清除周邊的待處理中斷旗標。這是第六個坑,多少英雄好漢在這裡翻船。」
    • 3d. (如果需要軟體觸發)啟用 IACK 功能:若想讓 CPU 用 IACK 指令來啟動 CLA 任務,記得要把 MCTL 暫存器裡的 IACKE 位元設起來。
    • 3e. 把 CLA 資料記憶體映射到 CLA 空間

      老張:「接下來,你要做一個非常重要的動作:『交出所有權』。你要對著記憶體控制器大喊:『嘿!從現在開始,這幾塊白板,是給 CLA 專用的了!我主CPU沒事不會去亂碰!』這個『喊話』的動作,就是去設定幾個特殊的暫存器。LSxMSELLSxCLAPGM。」

      首先,寫入記憶體組態暫存器 MemCfgRegs.LSxMSEL[MSEL_LSx] 位元為 1。然後,寫入 MemCfgRegs.LSxCLAPGM[CLAPGM_LSx] 位元為 0 (資料記憶體)。
    • 3f. 把 CLA 程式記憶體映射到 CLA 空間: 一樣,先寫 MemCfgRegs.LSxMSEL[MSEL_LSx] 為 1。然後,重點來了,要寫 MemCfgRegs.LSxCLAPGM[CLAPGM_LSx] 為 1 (程式記憶體)。
      老張:「標準流程是:主CPU先把 CLA 的程式碼搬到某個 LSxRAM (如 LS0RAM),資料搬到另一個 LSxRAM (如 LS1RAM)。然後設 LS0RAM 的 LS0MSEL=1, LS0CLAPGM=1。再去設 LS1RAM 的 LS1MSEL=1, LS1CLAPGM=0。搞混了會怎樣?呵呵,輕則 CLA 罷工,重則『程式跑飛』,那時候你只能拔電源了。」
    重要提醒:在整個初始化流程中,CLA 的主中斷致能 (MIER 暫存器) 最好先全部清成 0。等所有東西都設定妥當了,最後才打開。
  4. 步驟四:初始化 PIE 向量表和相關暫存器

    當 CLA 完成一個任務時,它會在 PIE 模組產生一個對應的中斷訊號給 CPU。CPU 這邊也要設定好 PIE。

  5. 步驟五:啟用 CLA 任務/中斷 (寫 MIER 暫存器)

    老張:「萬事俱備,只欠東風。最後一步,就是走到 CLA 辦公室門口,把「允許打擾」的牌子掛上去。這個動作是設定 MIER (Interrupt Enable Register) 暫存器。你把對應 Task 1 的位元設成 1,才算是真正啟用了這個任務的中斷。」

  6. 步驟六:初始化其他會觸發 CLA 任務的周邊

    例如,如果你設定 ADC 轉換完成後觸發 CLA 任務,那就要去設定 ADC 的相關參數、啟用 ADC 中斷等等。

老張:「做完這些,你的主CPU就可以去泡茶看報紙了(當然是開玩笑的,你還有別的活要幹),CLA 就會像個忠誠的僕人一樣,在背景幫你處理那些高速迴路。」

第三章:CLA 程式怎麼寫?C 語言嘛ㄟ通!

老張:「CLA 有自己的一套指令集,是專為數學運算優化的。你可以用組合語言來寫,如果你想體驗一下石器時代工程師的快感。但現在都什麼年代了,TI 早就提供了 CLA 的 C 編譯器。你可以用 C 語言的一個子集來寫 CLA 的程式。」

你只要建立一個 .cla 結尾的檔案,然後在裡面寫 C 語言函式就行了。不過,這個 C 不是你平常寫的那個萬能 C。它沒有那麼多花俏的功能,主要是做數學運算。別想在裡面搞什麼動態記憶體配置 malloc,或是印東西 printf,書呆子沒那麼多才多藝。

在你的 .cla 檔案裡,你會定義好幾個「任務」(Task)。CLA 最多可以有八個任務,從 Task1 到 Task8。每個任務都是一個獨立的函式,函式前面要加上 __attribute__((interrupt)) 這個宣告。


__attribute__((interrupt))
void Cla1Task1 ( void )
{
   // 在這裡寫你的高速控制迴路程式碼
   // 讀取 ADC 結果
   // 執行 PID 運算
   // 更新 PWM 佔空比
   __mstop(); // 告訴書呆子這件工作做完了
}
            
老張:「看到那個 __mstop() 了嗎?這非常重要!這是書呆子工作手冊的最後一頁,告訴他:『事情做完了,可以休息了。』如果你忘了加這個,他做完事之後不知道要幹嘛,就會繼續往下執行記憶體裡的垃圾數據,然後... 砰!又是『程式跑飛』套餐。這是第三個坑。」

當然,如果你是個追求極致效能的硬核玩家,直接手刻 CLA 組合語言也是可以的。

第四章:CLA 與 CPU 的「摩斯密碼」—— 訊息 RAM

CLA 埋頭苦幹,算出結果總得讓 CPU 知道吧?CPU 有新的命令或參數要給 CLA,也得有管道啊!這時候,「訊息 RAM (Message RAMs)」就登場了。

老張:「記住這個許可權,寫反了?沒事,系統會直接忽略你的寫入操作,但你就會在那裡抓破頭想說為什麼你的資料一直沒更新。」

第五章:CLA 的眉眉角角 —— 避坑指南

老張:「接下來,講點進階的,也是坑中之坑:Pipeline,管線。」

好啦,基本操作你們應該有點概念了。但江湖險惡,CLA 也不是省油的燈。有些小細節沒注意,它可是會毫不留情地把你搞死。

記憶體設定,再三確認!

EALLOW / MEALLOW 保護機制

老張:「喔喔喔!這位同學問到重點了!EALLOW / MEALLOW 保護機制,這可是 C2000 微控制器家族,尤其是 CLA 在操作時,一個非常非常重要的「安全鎖」概念。搞不懂這個,你的程式輕則跑不動,重則把系統搞到天翻地覆,到時候老闆拿著電蚊拍追殺你,別說我沒警告過你啊!」

(罐頭音效:緊張刺激的鼓點聲)

想像一下情境:你家有個保險箱,裡面放著傳家之寶(在 MCU 的世界裡,就是那些超級重要的系統控制暫存器)。平常這個保險箱是鎖上的,誰都不能亂動。

EALLOW (Enable Write Access to EALLOW-Protected Registers):這就像是總經理(也就是你的 C28x 主 CPU)拿出他的專用鑰匙,「喀啦」一聲,把保險箱打開了。打開之後,總經理才能修改保險箱裡的東西。

EDIS (Disable Write Access to EALLOW-Protected Registers):總經理修改完傳家之寶後,一定要記得「喀啦」一聲,再把保險箱鎖回去! 不然阿貓阿狗都跑進去亂搞,傳家之寶被換成狗尾巴草,你就準備回家吃自己了。

那 MEALLOW / MEDIS 又是什麼鬼?

CLA 這位特種部隊成員,它也有自己的一把「保險箱鑰匙」!

MEALLOW (CLA Enable Write Access to EALLOW Protected Registers):這是 CLA 自己要動用那些受 EALLOW 保護的暫存器時,CLA 拿出它的專用鑰匙,把保險箱打開。

MEDIS (CLA Disable Write Access to EALLOW Protected Registers):CLA 用完之後,一樣,CLA 自己要把保險箱鎖回去!

重點來了,敲黑板!

CPU 的鑰匙歸 CPU 管,CLA 的鑰匙歸 CLA 管! 這兩套是獨立的!CPU 用 EALLOW 開鎖,不代表 CLA 也能寫;CLA 用 MEALLOW 開鎖,也不代表 CPU 就能寫。各管各的!

為什麼要這麼麻煩?

這是為了「保護」。那些系統控制暫存器,一旦設錯,整個系統可能就掰掰了。所以平常把它們鎖起來,只有在「確定要修改」的時候,才短暫地打開寫入權限,改完立刻鎖上。這樣可以大幅減少因為程式意外跑飛或是一些 bug 導致重要暫存器被錯誤修改的風險。

什麼時候會用到 EALLOW / MEALLOW?

這個問題問得好!答案是:當你要寫入那些被「EALLOW 保護」的暫存器時,就必須使用!

哪些暫存器是「EALLOW 保護」的呢?

這個嘛…種類可多了!通常是那些跟系統核心功能、時脈、重置、安全、以及很多周邊模組的關鍵設定有關的暫存器。常見的例子(但不限於此,一定要查你的晶片 TRM!):

怎麼知道哪些暫存器需要 EALLOW/MEALLOW?

答案永遠是:查閱你那顆晶片的 Technical Reference Manual (TRM)! TRM 裡面描述每個暫存器的時候,通常會標註它是否受 EALLOW 保護。如果它標示了「Write Protection: EALLOW」,那恭喜你,CPU 要寫它的時候,就得乖乖用 EALLOW ... EDIS 包起來。如果是 CLA 要寫入這些受 EALLOW 保護的暫存器呢?那就在你的 CLA 程式碼裡面,用 MEALLOW ... MEDIS 把寫入操作包起來!

一個標準的 CPU 端寫入受保護暫存器的流程:


// 假設我們要設定某個受 EALLOW 保護的 GPIO MUX
// (這只是範例,具體暫存器名稱和位元請查 TRM)

// 先儲存目前的 EALLOW 狀態 (好習慣,雖然不一定每次都必要)
uint16_t eallow_status_backup = __get_EALLOW_status();

EALLOW; // 打開保險箱!

// 在這裡進行寫入操作
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // 假設 GPIO0 設定為某個周邊功能
// ... 其他需要 EALLOW 保護的寫入 ...

EDIS; // 鎖上保險箱!

// (可選) 還原 EALLOW 狀態
// __set_EALLOW_status(eallow_status_backup);
// 不過通常 EDIS 就夠了,除非你有特殊巢狀需求
            

一個標準的 CLA 端寫入受保護暫存器的流程 (CLA 組合語言或內嵌組合語言):


; 假設 CLA 要修改某個受 EALLOW 保護的 ePWM 暫存器
; (這只是範例)

    MEALLOW     ; CLA 打開保險箱!

    MMOV16 @EPwm1Regs.TBCTL.bit.CTRMODE, MR0  ; 假設 MR0 裡放著要設定的計數模式

    MEDIS       ; CLA 鎖上保險箱!
            

或者在 CLA C 程式碼中使用內建函式 (intrinsics):


#include <intrinsics.h> // 可能需要引入這個或類似的標頭檔

// ... CLA C 程式碼 ...

    __meallow(); // CLA 打開保險箱

    // 假設 EPwm1Regs 已經被正確定義且 CLA 可以存取
    EPwm1Regs.TBCTL.bit.CTRMODE = some_value_in_cla_register;

    __medis();   // CLA 鎖上保險箱

// ... CLA C 程式碼 ...
            

菜鳥常犯的錯誤(也就是林北當年踩過的坑):

總結一下,EALLOW / MEALLOW 的使用時機:

這個機制雖然看起來有點囉嗦,但它是保護你系統穩定運行的重要防線。養成好習慣,該開鎖就開鎖,該鎖門就鎖門,這樣你的 CLA 和 CPU 才能合作無間,系統也才能長治久安,你才能準時下班回家打電動啦!

(罐頭音效:遊戲勝利的音效)

老張:「懂了沒?這個 EALLOW/MEALLOW 很重要,回去多看幾遍,把它刻在腦子裡!再忘記,下次就罰你手抄 TRM 裡所有受 EALLOW 保護的暫存器清單一百遍!哼!」

管線 (Pipeline) 的愛恨情仇

老張:「你把 CLA 想像成一個工廠的流水線,一個指令從進來到完成,要經過好幾個站點...這也帶來了一些噁心人的『副作用』。」

中斷設定,層層把關

要讓一個周邊觸發 CLA 任務,你需要設定好幾層:周邊本身、CLA 的 DmaClaSrcSelRegs、CLA 的 MIER,以及 CPU 端的 PIE(如果需要)。

除錯 (Debugging) 的奇技淫巧

老張:「Debug CLA 程式碼也是一門藝術。因為 CLA 的執行是獨立的,你用傳統的方式在主CPU那邊設斷點,是斷不住 CLA 的。」

第六章:一個簡單的 CLA 應用情境

情境:ADC 即時採樣 -> 簡單濾波 -> 更新 PWM 責任週期

  1. CPU 初始化階段
    • 設定 ADC (採樣、中斷作為 CLA Task1 觸發源)。
    • 設定 ePWM。
    • 設定 CLA (載入 Task1 程式碼到程式 RAM, 係數到資料 RAM, 設定 MVECT1, DmaClaSrcSelRegs, 記憶體映射, 啟用 MIER.INT1)。
    • 啟動 ADC。
  2. CLA 執行階段 (Task1 程式):
    
    MMOVZ16 MR0, @ADCRESULTx   ; 從 ADC 結果暫存器讀值到 MR0
    ; (執行濾波演算法,可能用到 MR1, MR2, MAR0, MAR1 等)
    ; (根據濾波結果計算新的 PWM 責任週期值,存在 MRx)
    MEALLOW                    ; 如果 PWM 暫存器受保護
    MMOV16 @EPWMxRegs.CMPA, MRx ; 把新算出的責任週期值寫入 ePWM
    MEDIS
    MSTOP                      ; 任務結束
                        

這個流程裡,CPU 只需要在開頭設定好所有東西,然後就可以去做其他事情了。之後 ADC 的採樣、濾波、更新 PWM,全部由 CLA 自動完成。

第七章:CLA 的進階玩法

CLA 還有很多有趣的玩法,例如:

附錄:老張的 CLA 快速上手 SOP

喂!菜鳥,上面講那麼多,怕你記不住。這裡給你一個濃縮版的SOP,照著做,CLA 至少能跑起來。細節還是要回去看本文跟TRM啊!

  1. 撰寫 CLA 任務程式 (.cla 檔案):
    • 使用 C 語言子集或組合語言。
    • 每個任務都是一個 __attribute__((interrupt)) 函式。
    • 務必在任務結尾加上 __mstop(); (C 語言) 或 MSTOP (組合語言)。
    • 若需寫入受保護暫存器,使用 __meallow() / __medis()MEALLOW / MEDIS
  2. 主 CPU 初始化 CLA (通常在 main() 或初始化函式中):
    1. 啟用 CLA 時脈: 設定 PCLKCRn 相關位元。
    2. 複製 CLA 程式碼與資料:
      • 使用 memcpy 或類似方式將 CLA 程式從 Flash/連結器符號複製到指定的 LSxRAM (如 Cla1ProgRAM)。
      • 若有常數/表格,複製到指定的 LSxRAM (如 Cla1DataRAM)。
    3. 設定記憶體映射 (Memory Mapping):
      • 程式記憶體: 設定對應 LSxRAM 的 MemCfgRegs.LSxMSEL = 1MemCfgRegs.LSxCLAPGM = 1
      • 資料記憶體: 設定對應 LSxRAM 的 MemCfgRegs.LSxMSEL = 1MemCfgRegs.LSxCLAPGM = 0
      • 注意:這些設定通常需要 EALLOW 保護。
    4. 設定 CLA 任務向量 (Interrupt Vectors):
      • 將每個 CLA 任務函式的起始位址填入對應的 MVECTx 暫存器 (例如:MVECT1 = (uint16_t)&Cla1Task1;)。
      • MVECTx 寫入通常需要 EALLOW 保護。
    5. 選擇任務觸發源 (Interrupt Sources):
      • 參考上面嵌入的CLA 觸發源表格,設定 DmaClaSrcSelRegsCLAxTRGSEL (依晶片型號) 將周邊中斷 (如 ADC 中斷、ePWM 中斷) 連接到 CLA 任務。
      • 若為軟體觸發,設定為 CLA_SOFTWARE_TRIGGER (Select Value = 0)。
      • 此設定通常需要 EALLOW 保護。
    6. (可選) 啟用軟體觸發 (IACK): 若使用 IACK 指令觸發 CLA,設定 MCTL 暫存器的 IACKE 位元。 (MCTL 寫入需 EALLOW)
    7. (可選) 初始化訊息 RAM (Message RAMs): 若 CPU 需要傳遞初始參數給 CLA。
  3. 啟用 CLA 任務中斷:
    • 在主 CPU 端,設定 PIE 模組以允許 CLA 相關中斷送達 CPU (如果需要 CLA 完成後通知 CPU)。
    • 最重要:設定 CLA 的 MIER (Interrupt Enable Register) 中對應任務的致能位元。 例如 MIER.INT1 = 1
    • MIER 寫入通常需要 EALLOW 保護。
  4. 初始化並啟用觸發 CLA 的周邊:
    • 例如,設定 ADC 轉換模式、啟用 ADC 中斷。設定 ePWM 參數、啟用 ePWM 中斷等。
  5. 測試與除錯:
    • 在 CCS 中,連接 Debugger 到 CLA 核心。
    • 使用 MDEBUGSTOPMDEBUGSTOP1 在 CLA 程式中設定軟體斷點。
    • 觀察 CLA 暫存器 (MRx, MARx, MPC, MSTF) 和記憶體內容。
    • 注意管線效應 (延遲槽、讀寫順序)。
    • 若 CLA 卡死,嘗試使用 MCTL 中的軟體/硬體重置位元。

老張最後囉嗦一句: 這個 SOP 是骨架,肉還是要靠你自己啃 TRM 跟範例程式碼才能長出來!加油,別被 CLA 這匹野馬甩下來!

收尾:CLA 是個好東西,但你要懂得疼惜它

老張:「好了,小李。我今天說的夠多了,口水都乾了。從記憶體、程式碼、觸發、向量、啟用,到管線天坑跟除錯技巧,CLA 的精髓跟鳥事,差不多都在這裡了。」

老張:「你不要覺得這東西很麻煩。它就像一匹野馬,脾氣很壞,但一旦你馴服了它,它能帶你跑得飛快。你的主CPU可以去做更多有價值的事情,而不用被困在每秒幾萬次的無盡迴圈裡。」

老張:「回去把你那抖得跟帕金森一樣的馬達程式碼,用我今天教你的方法,把核心的 PID 運算部分,移植到 CLA 裡面去。做對了,你會看到你的主CPU佔用率,可能從 80% 瞬間掉到 10% 以下。那種成就感,就是我們這些搞嵌入式的,在無數個加班夜晚後,還能笑得出來的唯一理由。」

TRM (Technical Reference Manual) 是你們的聖經,遇到問題多拜讀幾遍。TI 官方也提供很多範例程式 (C2000Ware 裡面翻一下 driverlib/DEVICE_GPN/examples/cla 路徑)。

老張:「去吧,別讓我失望。哦對了,順便幫我把茶杯洗一下。」

(罐頭音效:掌聲 + 歡呼聲)