jserv: hack myself

在 TI OMAP4 控制 ARM Cortex-M3

| Comments

TI OMAP 系列除了內建 ARM Cortex-A 處理器以外,OMAP33x 搭配 ARM Cortex-M3 系列處理器,OMAP4 搭配兩個 Cortex-M3,OMAP5 則搭配兩個 Cortex-M4,用途是低功耗處理和針對多媒體系統的即時反應需求,輔助 ARM Cortex A8 (OMAP3) / A9 (OMAP4) / A15 (OMAP5) 進行底層相關控制。本文以 Pandaboard ES 為參考硬體平台,說明如何對 TI OMAP4460 內建的兩個 Cortex-M3 進行控制。


Pandaboard ES 的網站可得知硬體規格:

  • Core Logic OMAP4460 applications processor
    • Dual-core ARM® Cortex™-A9 MPCore™ with Symmetric Multiprocessing (SMP) at upto 1.2 GHz each

其中兩個 Cortex-M3 單元特稱為 "Ducati Cortex-M3 sub-system",詳細的運作可參考 wiki:Ducati For Dummies,主要控制 Ducati Imaging Sub System (ISS) 和 Ducati Image Video Accelerator - High Definition (IVA-HD) 這兩個子系統,運作圖例如下:

任職於 IBM 的 Linux 核心工程師 Alistair Popple 日前在 GitHub 發布了 Pandaboard-FreeRTOS,展示從 u-boot 或 Linux (都運作於 Cortex-A9 之上) 環境中,將特製的 FreeRTOS 載入到其中一個 Cortex-M3 中並執行。

Pandaboard-FreeRTOS 具體原理是,預先整合 FreeRTOS 和示範程式碼到 Demo.bin 檔案中,隨後交由 u-boot 載入到記憶體,一個名為 loader.img 的檔案運作於 Cortex-A9 並且為 Cortex-M3 設定 L2 MMU,之後將稍早由 u-boot 載入到記憶體的 Demo.bin 之位址映射到 Cortex-M3 虛擬位址 0x0,而 GPIO 位址也連同映射到 Cortex-M3 虛擬位址中,這樣示範的程式碼可藉由每秒閃爍 LED 來確認已控制 Cortex-M3。

目前的程式碼中,作為示範性質,並沒有太多處理,只是簡單地從物理位址的 0xb0000000 映射 1 M 範圍到裝置位址的 0x0,這樣的用意是保存 Cortex-M3 程式的 text 和 data section,而為了能讓 LED 閃爍,系統也映射包含 GPIO1 週邊暫存器 (實體位址 0x4a300000) 的 1 M 空間到裝置位址的 0xfff00000

以下是我在 Ubuntu Linux 上測試的指令:

export PATH=/usr/local/csl/arm-2013.11/bin:$PATH
cd /tmp
git clone git@github.com:apopple/Pandaboard-FreeRTOS.git
cd Pandaboard-FreeRTOS
make

這裡選用 Sourcery CodeBench 的 ARM EABI Release 2013.11 (Lite edition),預先安裝於 /usr/local/csl 目錄。將 Demo.binloader.img 兩個檔案複製到 SD 卡的第一個分割區 (boot):

cp -f Demo.bin loader.img /media/$USER/boot

當然,我們需要一個可正確運作的 u-boot,注意,在 OMAP4 的架構下,除了 Boot ROM 外,還有 X-loader 或 SPL 作為第二階段的 boot loader (檔名: MLO),而 u-boot 本體則是第三階段。筆者在 2009 年發表 Qi -- Lightweight Boot Loader Applied in Mobile and Embedded Devices 則縮減到兩階段啟動,但為了簡便起見,這裡仍沿用 u-boot,只要參照 wiki:Panda How to MLO & u-boot,就可很容易建構 MLOu-boot.img 這兩個檔案。操作指令如下:

cd /tmp
git clone git://git.linaro.org/boot/u-boot-linaro-stable.git
cd u-boot-linaro-stable
make CROSS_COMPILE=arm-none-eabi- omap4_panda_config
make CROSS_COMPILE=arm-none-eabi-

同樣複製到 SD 卡的第一個分割區:

cp -f MLO u-boot.img /media/$USER/boot

接著就準備要測試了。

我使用 Openmoko 開發的 neocon 工具來操作 Pandaboard ES 對外的終端機連線:

neocon /dev/ttyUSB0

以下是參考的執行輸出:

[Open /dev/ttyUSB0]

U-Boot SPL 2013.01.-rc1-00003-g43ee87a (Jan 01 2014 - 21:38:53)
OMAP4460 ES1.1
OMAP SD/MMC: 0
reading u-boot.img

U-Boot 2013.01.-rc1 (Jan 24 2013 - 09:32:22)

CPU  : OMAP4460 ES1.1
Board: OMAP4 Panda
I2C:   ready
DRAM:  1 GiB
MMC:   OMAP SD/MMC: 0
Using default environment

In:    serial
Out:   serial
Err:   serial
Net:   No ethernet found.
mmc0 is current device
reading boot.scr
159 bytes read
Loaded script from boot.scr
Running bootscript from mmc0 ...
## Executing script at 82000000
reading loader.img
752 bytes read
reading Demo.bin
12828 bytes read
## Booting kernel from Legacy Image at 82000000 ...
   Image Name:   
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    688 Bytes = 688 Bytes
   Load Address: 83000000
   Entry Point:  83000244
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK

Starting kernel ...

然後應該可見 D2 這個 LED (SD 插座旁) 以每秒一次的頻率閃爍。讓我們來看看運作於 Cortex-M3 的 FreeRTOS 程式作什麼,可參見 Application/main.c 檔案,首先是 LedFlash 這個 FreeRTOS task 實作:

volatile int *GPIO1_DATAOUT;
volatile int *GPIO1_OE;
static void LedFlash(void *Parameters)
{
    portTickType LastWake;
    *GPIO1_OE &= ~(1 << 8);
    LastWake = xTaskGetTickCount();
    while (1) {
        *GPIO1_DATAOUT ^= (1 << 8);
        vTaskDelayUntil(&LastWake, 1000);
    }
}

藉由呼叫 vTaskDelayUntil,達到等待的效果,而本範例中,已在 FreeRTOSConfig.h 定義 configTICK_RATE_HZ 的值為 1000,期中 ledFlash task 將會持續等待,直到一秒過後,才會 unblock。

main 函式的實作相對單純,主要是建立前述 task:

int main()
{
    volatile int i;
    GPIO1_DATAOUT = (int *) 0xfff1013c;
    GPIO1_OE = (int *) 0xfff10134;
    *GPIO1_OE &= ~(1 << 8);
    if (*GPIO1_DATAOUT & (1 << 8)) {
        while(1);
    }
    *GPIO1_DATAOUT |= (1 << 8);
    xTaskCreate(LedFlash, (signed char *) "LedFlash", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    vTaskStartScheduler();

    /* Just sit and flash the LED quickly if we fail */
    while (1) {    
        for (i = 0; i < 100000; i++);
        *GPIO1_DATAOUT ^= (1 << 8);
    }
}

注意:if (*GPIO1_DATAOUT & (1 << 8)) 是避免兩個 Cortex-M3 的 race condition 所作的 hack。

除了透過 u-boot,事實上也能在 Linux 環境下,藉由 remoteproc (Remote Processor Framework) 來載入針對 Cortex-M3 的程式,其設計就是針對 OMAP4 這樣的 AMP (asymmetric multiprocessing) 環境,允許相互存取資源。以下引述 Linux 核心文件:

The remoteproc framework allows different platforms/architectures to control (power on, load firmware, power off) those remote processors while abstracting the hardware differences, so the entire driver doesn't need to be duplicated. In addition, this framework also adds rpmsg virtio devices for remote processors that supports this kind of communication. This way, platform-specific remoteproc drivers only need to provide a few low-level handlers, and then all rpmsg drivers will then just work.

關於低階處理的部份,又涉及另一個 framework: Remote Processor Messaging (rpmsg),我們必須確保 Cortex-A9 上運作的 Linux 的 remoteproc / rpmsg 定義與 Cortex-M3 上的 FreeRTOS 程式相符,為此需要修改 Application/startup.c

Comments

comments powered by Disqus