Rockchip RKNanoD について調べてみた

Rockchip RKNanoD の基本的な情報についてまとめました。

RKNanoDは携帯型メディアプレイヤー用のSoCです。
自分的には、Cortex-M3がデュアルなのと、SRAMが合計1MB搭載されているのがポイント高いです。
TRMもあるので、がんばればいろいろできます。

# Spec

|  |  |
|:-:|:-:|
| CPU  | ARM Cortex M3 Dual core (SYS_CORE:250MHz , CAL_CORE:500MHz)  |
| RAM  | Total 1MB SRAM  |
| USB  | OTG with phy|
| Audio | 192kHz/24bit stereo dac|
| SD/MMC | 1xmemory , 1xSDIO for Wi-Fi|
| Peripheral | I2C I2S PWM SPI UART LCD|


* Fireduino のページには最大動作周波数が 250MHz, 500MHzとあるがソースコードをみると200MHz, 400MHzが最大みたいです。

# Board
* [FireFly Fireduino](http://en.t-firefly.com/en/firesmart/fireduino/) 35USD
* RKNanoD 搭載のメディアプレイヤーがあります。

# SDK
* RockchipからオープンなSDKはリリースされていませんが、githubにはSDKがアップロードされている。
 * https://github.com/averyling82/wifi-bt-audio
 * https://github.com/wjw890912/RK_NanoD_WIFI_demo
 * MDK-ARM でコンパイルできる。
 * FreeRTOS
 * lwIP
* ArduinoベースのSDKをFireFlyが提供している
 * https://github.com/FireflyTeam/Fireduino-SDK
 * gcc用のライブラリとWindowsとLinuxのダウンロードツールが提供されている。

# Document
* [Rockchip RKNanoD Technical Reference Manual 1.0](http://wiki.t-firefly.com/images/0/0b/Fireduino_MCU_TRM.pdf)
* [Rockchip RKNanoD Datasheet 1.2](http://wiki.t-firefly.com/images/a/a6/Fireduino_MCU_datesheet.pdf)
* 評価ボードの回路図
 * https://github.com/averyling82/wifi-bt-audio/blob/master/bt-nano/App/all/rknanod_sdk_main_v22_20150908_n.pdf 
* Fireduinoの回路図
 * https://drive.google.com/drive/folders/0B7HO8lbGgAqAWGVQWnQwSF9Wc28 

# MemoryMap
* SYS_COREから見たメモリマップです。

| start | end | name | description |
|:-:|:-:|:-:|:-:|
| 0x00000000 | 0x00000FFF | PMU DRAM | 4KB SRAM for DATA |
| 0x00001000 | 0x00001EFF | PMU IRAM | 3KB SRAM for CODE  |
| 0x01000000 | 0x0101FFFF | CAL_CORE IRAM | 128KB SRAM for CODE  |
| 0x01020000 | 0x0105FFFF | CAL_CORE DRAM | 256KB SRAM for DATA  |
| 0x30000000 | 0x3004FFFF | SYS_CORE DRAM | 320KB SRAM for DATA  |
| 0x30050000 | 0x3007FFFF | SYS_CORE IRAM | 256KB SRAM for CODE  |
| 0x40000000 | 0x5FFFFFFF | Peripherals   | on chip peripharals  |

* スキャッタロード記述ファイル [BuildAll_SPI.sct](https://github.com/averyling82/wifi-bt-audio/blob/master/bt-nano/App/all/Scatter/BuildAll_SPI.sct) とか、リンカスクリプト [flash.ld](https://github.com/FireflyTeam/Fireduino-SDK/blob/master/variants/fireduino/linker_scripts/gcc/flash.ld)
にメモリマップの情報がある。

# GPIO
* GPIOの仕様
 *　GPIOはGPIO0, GPIO1, GPIO2 の３つのグループがある。各グループ32個のピンが割り当てられている。 
 *　プルアップとプルダウンかはピン毎に決まっている。
 *　起動時、GPIOは入力に設定されている。
* CH1 PortB Pin1 に Highを出力する。 
 * Grf は General Register File　のこと。
 * Grf_GpioMuxSet()でピンのマルチプレクサを設定し、Gpio_SetPinDirection()でGPIOの向きを設定し、Grf_GPIO_SetPinPull()でPullUP/PullDownの設定をする。
 * Gpio_SetPinLevel（）で出力の電圧を設定する。

```c
    Grf_GpioMuxSet(GPIO_CH1,GPIOPortB_Pin1,IOMUX_GPIO1B1_IO);
    Gpio_SetPinDirection(GPIO_CH1,GPIOPortB_Pin1, GPIO_OUT);
    Grf_GPIO_SetPinPull(GPIO_CH1, GPIOPortB_Pin1, ENABLE);

    Gpio_SetPinLevel(GPIO_CH1,GPIOPortB_Pin1, GPIO_HIGH);
```

* CH1 PortB Pin1 の入力を取得する

```c
    Grf_GpioMuxSet(GPIO_CH1,GPIOPortB_Pin1,IOMUX_GPIO1B1_IO);
    Gpio_SetPinDirection(GPIO_CH1,GPIOPortB_Pin1, GPIO_IN);

    level = Gpio_GetPinLevel(GPIO_CH0, GPIOPortB_Pin1);
``` 

* GPIOのベースアドレス (hw_memap.h)

```
#define GPIO0_BASE          ((UINT32)0x40160000)
#define GPIO1_BASE          ((UINT32)0x40170000)
#define GPIO2_BASE          ((UINT32)0x50030000)
```

# Frequency
* 周波数はCRU (Clock and Reset Unit) という名前のハードウェアが管理する。
* パワーマネージャという電源管理制御機能経由で設定する場合
 * 周波数は syssever/PowerManager.c の g_CruAPPTabel に設定する。
 * syssever/PowerManager.c の FREQ_EnterModule()を呼ぶ。
* CRUを直接設定する場合
 * Cpu/NanoD/lib/cru.c の SetPllFreq（） を呼ぶ。
 * でもレジスタの資料が無いので、どう設定して良いのか分からない。
 
* CRUのベースアドレス

```
#define CRU_BASE            ((UINT32)0x40180000)
```

# TIMER
* タイマの仕様
 * 64ビットタイマが２個ある 
 * タイマはダウンカウントする
 * ロードカウントに値を設定して、タイマをスタートするとダウンカウントする。0になると割り込みを発生することができる。
 * タイマの入力クロックは24MHzとPCLKを選択できる。PCLKの最大周波数はSYS_COREのCLKの1/2です。
* タイマを設定するサンプルコード
 * RKDev_Create()経由でTimerDev_Create()を呼ぶ。
 * タイマへクロックを供給する
 * タイマをリセットする。
 * CRUにタイマへの入力するクロックの設定をする。
 * タイマのカウントを止める。
 * タイマをフリーランモードで初期化する。
 * タイマにロードカウントを設定
 * タイマのカウントを開始する。
 * タイマの値を読む。

```c
RKDev_Create(DEV_CLASS_TIMER,TIMER0,NULL);
ScuClockGateCtr( CLK_TIMER0_GATE, 1);
ScuClockGateCtr( PCLK_TIMER_GATE, 1);
ScuSoftResetCtr(TIMER0_SRST, 0);
SetTimerFreq(TIMER0 ,XIN24M,24*1000*1000);
TimerStop(TIMER0);
TimerInit(TIMER0 ,TIMER_FREE_RUNNING);
TimerCount(TIMER0 ,0xFFFFFFFFFFFFFFFF);
TimerStart(TIMER0);

val = TimerGetCount(TIMER0);
```

* タイマのクロックソースをPCLK_LOGICにした場合
 * PCLK_LOGICは ペリフェラルのバスクロック
 * PCLK_LOGICの設定は SetPclkLogicPreFreq()で行う
 * PCLK_LOGICはhclk_sys_coreを分周して生成する。


# I2S
* I2Sの設定
* I2Sの初期化コード
 * I2S0 を 内蔵 ACODECに接続する。
 * I2S0 を初期化する。マスターモード 48KHz 24bit
```c
Grf_I2S0_Sel(I2S_SEL_ACODEC);
I2SInit（I2S_DEV0,
        I2S_MASTER_MODE, 
        I2S_EXT,
        I2S_FS_48KHz,
        I2S_FORMAT,
        I2S_DATA_WIDTH24,
        I2S_NORMAL_MODE,
        I2S_FORMAT,
        I2S_DATA_WIDTH24,
        I2S_NORMAL_MODE);
```

* I2Sは起動後はデフォルト有効みたいなので、使わない場合は止めておく。

```c
I2SDeInit(I2S_DEV0);
I2SDeInit(I2S_DEV1);
```

# WDT
* ウォッチドッグタイマの仕様
 * ３２ビットダウンカウンタ 
 * タイマの周波数は設定できないようです。PCLKでカウントダウンするのでしょうか？
 * エクスパイア時のリセット動作は、すぐシステムリセットする、または、割り込みを発生して１秒以内にクリアされない場合はシステムリセット の二つから選べる。
 * タイムアウト期間は16種類ある。 0xFFFF から 0x7FFFFFFF まで。
* ウォッチドッグタイマの設定
 * 初期化する。　エクスパイア時のリセット動作、リセット発生時のパルス長、タイムアウト期間
 * タイマを起動する。

```c
WatchDogInit(RESP_MODE_INT_RESET, PCLK_CYCLES_128, PERIOD_RANGE_0X7FFFFFFF);
WatchDogStart();
```

* 定期的にタイマをリロードする。

```c
WatchDogReload();
```

# UART
* UARTの仕様
 *　６個のUARTがある。
 *　DMAと割り込みをサポート
 *　UARTの速度は110bps から ９２１６００bps
*　UARTの設定
 * 初期化する UART2を 115200bps 8N1に設定。

```c
ScuSoftResetCtr(UART2_SRST, 1);
DelayMs(1);
ScuSoftResetCtr(UART2_SRST, 0);

ScuClockGateCtr(CLK_UART2_GATE, 1);
ScuClockGateCtr(PCLK_UART2_GATE, 1);
SetUartFreq(UART_CH2,XIN24M,24*1000*1000);

IntRegister(INT_ID_UART2 ,UartDevShellBspIsrHandle2);
IntPendingClear(INT_ID_UART2);
IntEnable(INT_ID_UART2);

UARTInit(UART_DEV2, UART_BR_115200, UART_DATA_8B, UART_ONE_STOPBIT, UART_PARITY_DISABLE);
UARTEnableFlowControl(UART_DEV2);
```