NXP LPC1768 Application on FreeRTOS

IMAGE11.GIF - 980BYTES FreeRTOSの使用状況
IMAGE11.GIF - 980BYTES プログラム構成
IMAGE11.GIF - 980BYTES いくつかの事例
IMAGE12.GIF - 2,801BYTES

変更履歴
2010年10月10日11日 ほとんど新規しかし未完
2010年10月16日17日 いくつかの事例(UART&USB)
2010年11月6日 SDカード及びファイルシステムのBUG修正


動作チェックをしている様子




FreeRTOSの使用状況
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES


<現状>

現時点(10月10日時点)での最新版は、V.6.1.0です。
私はV.6.0.3をベースに使用しています。

解凍すると多くのディレクトリに展開されますが、LPC1768を使用する場合はRB1768の基板を利用したデモ用ファイルを流用します。
..\FreeRTOS.v.6.0.3\Demo\CORTEX_LPC1768_GCC_RedSuite\src

少し古い情報(2010年3月)ですが、ここに最初にインストールした内容を書き記しています。
その後の動作確認で、USB、TCP/IP等が動き始めました。

私の作成しているデータロガープログラムは、タスクを下記の様に分配しています。

タスク名 主な機能 優先付け スタックサイズ
(Byte)
起動周期
vuIP_Task TCP/IP制御及びそのアプリケーションプログラムの実行 192 常時
vUSBTask USB制御及びそのアプリケーションプログラムの実行
現時点(2010年10月)では、CDCとMSCの動作が確認出来ています
128 常時
vTask1 CAN通信に使用しますが、まだDummyプログラムを動かしています 0 128 25ms
vTask2 Micro-SD制御
GPS、CAN、ADCの各データをQueueを使って受取り、ファイルに書き込んでいます
0 144 vTask1
vTask4
vTask6
の要求にて順次起動
vTask3 モニタープログラム
デバッグ目的のタスクで、色々な情報をPCへ表示しています
0 144 PCからの文字入力毎
vTask4 GSP制御
GPSデータをUARTで受信して、Task2へQueueを使って送り出しています
0 128 GPSのパケット送出
(現設定では25ms毎程度)
vTask5 LCD制御
各種データを表示していますが、まだ暫定です
0 128 1Sec毎が基本
但し、順次
vTask6 ADC制御
Gセンサー(X、Y、Z三軸)、温度センサー及び電源電圧を計測しています
0 128 25ms
vTask7 10mSタイマー及びスイッチ状態監視
スイッチの状態に応じて、全体制御モードを変えています
0 96 10ms

モニタープログラムを使用して、各タスクの状況を観測し、表として整理すると下記のような情報が得られます。
この例は、各タスクの最大負荷を想定して計測していません。従って、あくまでも参考としてご覧ください。

タスク スタック残り
サイズ
初期値 残量
TASK/uIP 70 192 36.4%
TASK/USB 74 128 57.8%
Task1/CAN 54 128 42.2%
Task2/MSD 94 144 65.3%
Task3/MON 44 144 30.6%
Task4/GPS 80 128 62.5%
Task5/LCD 80 128 62.5%
Task6/ADC 46 128 35.9%
Task7/TIM 48 96 50.0%

タスクが占有している時間は下記の情報を参考にしてください。

task_running_condition.pdf

表で判るように、アプリケーションタスク(現在9個)以外に、システムが制御しているタスクが多く存在します。
IDLEが重要で、CPUの占有率がどんなときにも100%を越えるわけにはいきませんので、IDLE時間がどのくらい残っているかはシステムの安定性に影響します。
上記測定中は、USB経由でファイルをPCからMicro-SDへコピーしている場合で、コピー終了後はUSBタスクが23%から2%に減少しました。
その分、IDLEが18%から23%に増加しています。
現時点では、USBはPCからの要求をポーリング処理で監視し続けている為、占有率が増えていますが、割込み処理に移行出来ればもっと改善出来ると思います。
残念ながら、検討したところかなりの変更が必要で落ち着いてから再チャレンジ(多分出来ない?)とします。





<FreeRTOS提供のFunction使用例>

アプリケーションで使用しているFunctionを紹介します。
素人なので、FreeRTOSの提供する機能を充分に使いこなしていなくて、下記だけです。
機能の詳細は、FreeRTOSのホームページでpdfファイルを購入する必要があります。
但し、一般的な解説はホームページにて閲覧可能(API Reference)です(英語のみ)。
下記で確認出来るようにリアルタイムOSを簡単に使うには、それほど深い知識が無くても利用可能だと思いますので、pdfを購入して理解を深める前に先ずは使ってみることが重要だと思います。
むしろ難しいのは、スタック管理を含むメモリ管理でしょう。
私の経験では、プログラムが上手く動かない理由の多くがスタックの問題と、あるタスクがCPUを占有してリソースを解放しないでタスクがディスパッチ出来ずに動作不良を起こしていることが多いです。

No. 機能 機能名 機能の使い方
1 タスク生成 xTaskCreate
今回のアプリケーションでは、初期化の際に下記の様にタスク生成をしています。

// Web
xTaskCreate( vuIP_Task, ( signed char * ) "uIP", ( ( unsigned short )192 ), ( void * ) NULL, mainUIP_TASK_PRIORITY, NULL );
// USB Task (Selected function only)
#if (USB_DISK == 1)
// Mass Storage Class
xTaskCreate( vUSBTask, ( signed char * ) "USB", ( ( unsigned short ) 128 ), ( void * ) NULL, ( tskIDLE_PRIORITY +1 ), NULL );
#elif (USB_UART == 1)
// Serial
xTaskCreate( vUSBTask, ( signed char * ) "USB", ( ( unsigned short ) 128 ), ( void * ) NULL, ( tskIDLE_PRIORITY +1 ), NULL );
#endif
// CAN Task
xTaskCreate( vTask1, ( signed char * ) "Task1", ( ( unsigned short ) 128 ), ( void * ) NULL, tskIDLE_PRIORITY, NULL );
// SD Card Control Task
xTaskCreate( vTask2, ( signed char * ) "Task2", ( ( unsigned short ) 144 ), ( void * ) NULL, tskIDLE_PRIORITY, NULL );
// Monitor Task
xTaskCreate( vTask3, ( signed char * ) "Task3", ( ( unsigned short ) 144 ), ( void * ) NULL, tskIDLE_PRIORITY, NULL );
// GPS Task
xTaskCreate( vTask4, ( signed char * ) "Task4", ( ( unsigned short ) 128 ), ( void * ) NULL, tskIDLE_PRIORITY, NULL );
// LCD Control Task
xTaskCreate( vTask5, ( signed char * ) "Task5", ( ( unsigned short ) 128 ), ( void * ) NULL, tskIDLE_PRIORITY, NULL );
// ADC Control Task
xTaskCreate( vTask6, ( signed char * ) "Task6", ( ( unsigned short ) 128 ), ( void * ) NULL, tskIDLE_PRIORITY, NULL );
// Operation mode control Task
xTaskCreate( vTask7, ( signed char * ) "Task7", ( ( unsigned short ) 96 ), ( void * ) NULL, tskIDLE_PRIORITY, NULL );
2 キュー生成 xQueueCreate
タスク間の同期を保っての情報伝達に使用するキューを生成します。

今回は、下記のようにGPS情報、LCD表示、ADC情報用に3つのキューを用意しました。
// Create Queue buffer and Semaphore
 sdcardQueue = xQueueCreate(4, 8); // 8Byte x 4
 LcdQueue = xQueueCreate(4, 8); // 8Byte x 4
 adctrgrQueue = xQueueCreate(4, 8); // 8Byte x 4
3 キュー送信 xQueueSendToBack
キューにデータをセットして、発行します。

例えば、
if (rec_status == RECD){
  xQueueSendToBack(sdcardQueue, "ADC", portMAX_DELAY);
}
では、TASK6がADCデータの準備が出来たことを知らせています(TASK2のSDカード制御タスクが記録中あれば)。
4 キュー受信 xQueueReceive
キューにデータがセットされるまで、タスクは待ち状態となります。

例えば、上記に対応する部分では、
while(1){
  xQueueReceive(sdcardQueue, qbuf, portMAX_DELAY);
  if ( rec_status == RECD ){
    if (memcmp(qbuf, "ADC", 3) == 0){
      f_puts(MsgBuf_ADC, &File1);
    } else if (memcmp(qbuf, "CAN", 3) == 0){
      f_puts(MsgBuf_CAN, &File1);
    } else if (memcmp(qbuf, "GGA", 3) == 0){
      f_puts(MsgBuf_GGA, &File1);
    } else if (memcmp(qbuf, "GSA", 3) == 0){
      f_puts(MsgBuf_GSA, &File1);
    }
    f_sync(&File1);
    vParTestToggleLED( LED2 ); // Show on logging
  }

となって、データが送出されてくるまで待っています。
5 一定時間待ち vTaskDelay
指定した時間、タスクの制御が中断されます。

例えば、
// Get one character
uint8_t Uart_GetC2(void){
   while(ring_getc (&ring_rx2)){
     vTaskDelay(1/portTICK_RATE_MS ); // Wait 1mS
   }
   return ring_rx2.dt_got;
}
の場合は、リングバッファにデータが入っていない時に、1ms毎にタスクは制御を中断して、他のタスクを実行出来ることになる。
7 一定時間待ち vTaskDelayUntil
vTaskDelayとの違いも含め、ここに書いた内容を参照ください。ここも参照ください。











プログラム構成
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES


<ソースファイル構成>

現時点(2010年10月10日)で、私の作成しているデータロガーで使用しているファイルの構成を下記に示します。現在も開発完了していませんので、今後も変更する予定です。

gccのDirectoryには、
生成されるObjectが格納されます。
docは関係資料が入っていますが、
ソフトウェア開発には関係しません

より詳しい内容は、このファイルリストを参照ください。






<オリジナルファイル>

下記の多くのプログラムを直接もしくは間接的に参考にさせていただきました。

利用したプログラム一覧
プログラム名 作者
(管理者もしくは供給者)
入手先 ライセンス条件 コメント
FreeRTOS Richard Barry
(FreeRTOS V6.0.3 - Copyright (C) 2010 Real Time Engineers Ltd.)
SourceForge

FreeRTOS Real Time Kernel

by richardbarry

Modified GPL (Open Source) Licensing

FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
***NOTE*** The exception to the GPL is included to allow you to distribute a combined work that includes FreeRTOS without being obliged to provide the source code for proprietary components outside of the FreeRTOS kernel.
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details. You should have received a copy of the GNU General Public License and the FreeRTOS license exception along with FreeRTOS; if not it can be viewed here:
http://www.freertos.org/a00114.html and also obtained by writing to Richard Barry, contact details for whom are available on the FreeRTOS WEB site.
RTOS関連ファイルは全てこの場所から入手後、一部修正して使用しています
LPCUSB

LPC214x USB stack

Bertrik Sikken (bertrik@sikken.nl)

(LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken)
SourceForge

LPC214x USB stackbeta by bertrik

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ソース以外の関係情報に辿りつくことが出来ませんでした。
FatFsとの結合のために修正をしています
uIP
Adam Dunkels
(Ph D)


(Copyright (c) 2001, Adam Dunkels. All rights reserved.)
Adam Dunkels' Homepage

Download page
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
FreeRTOSにDemoとして添付されているソースコードを利用して、間接的に利用しています
FatFs ChaN(English)

ChaN(日本語)
FatFs 汎用FATファイルシステム・モジュール

FatFs Generic File System Module
/*----------------------------------------------------------------------------/
/ FatFs - FAT file system module R0.08a (C)ChaN, 2010
/-----------------------------------------------------------------------------/
/ FatFs module is a generic FAT file system module for small embedded systems.
/ This is a free software that opened for education, research and commercial
/ developments under license policy of following trems.
/
/ Copyright (C) 2010, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-----------------------------------------------------------------------------/

/*----------------------------------------------------------------------------/
/ FatFs - FAT file system module R0.08a (C)ChaN, 2010
/-----------------------------------------------------------------------------/
/ FatFsモジュールは、小規模な組み込みシステム向けの汎用FATファイルシステム・
/ モジュールです。これはフリー・ソフトウェアとして、教育・研究・開発のために
/ 以下のライセンス・ポリシーの下で公開されています。
/
/ Copyright (C) 2010, ChaN, all right reserved.
/
/ * FatFsモジュールはフリー・ソフトウェアであり、また無保証です。
/ * 用途に制限はありません。あなたの責任の下において、個人的・非営利的な
/ ものから商用製品の開発に及ぶ目的に使用・改変・再配布することができます。
/ * ソース・コードを再配布するときは、上記の著作権表示を保持しなければなりません。
/
/-----------------------------------------------------------------------------/
NXPのアプリケーションノートAN10916で紹介されていて、使用し始めましたが、まさか日本人の方が作成したソフトウェアとは、2009年暮れまで知りませんでした。
このGPSデータロガーはすごいです。
NXP
Sample program
NXP All microcontrollers support documents for LPC1768


LPC1769_68_67_66_65_64.zip

lpc17xx.cmsis.driver.library.zip

LPCXpresso support

library.cmsis.lpc17xx.zip
Terms of Use .
Code Red
Sample
program
Code Red RDB1768 CMSIS-based Example Projects

RDB1768cmsis.zip
Software License Agreement
The software is owned by Code Red Technologies and/or its suppliers, and is protected under applicable copyright laws. All rights are reserved.
Any use in violation of the foregoing restrictions may subject the user to criminal sanctions under applicable laws, as well as to civil liability for the breach of the terms and conditions of this license.

THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
USE OF THIS SOFTWARE FOR COMMERCIAL DEVELOPMENT AND/OR EDUCATION IS SUBJECT TO A CURRENT END USER LICENSE AGREEMENT (COMMERCIAL OR EDUCATIONAL) WITH CODE RED TECHNOLOGIES LTD.
.
ring.c
ring.h
Copyright (C) 2003 Project Majingaa. (http://majingaa.dyndns.org/) . Copyright (C) 2003 Project Majingaa. (http://majingaa.dyndns.org/)
This file is part of majingaa-hos
majingaa-hos is free software; you can redistribute it and/or modify it under the terms of the GNU General PublicLicense as published by the Free Software Foundation; either version 2, or (at your option) any later version.
majingaa-hos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with majingaa-hos; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
2005年頃、Webで入手。現在情報がありません
printf-stdarg.c Copyright 2001, 2002 Georges Menie (www.menie.org)
stdarg version contributed by Christian Ettinger
. Copyright 2001, 2002 Georges Menie (www.menie.org)
stdarg version contributed by Christian Ettinger

This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
FreeRTOSのダウンロードによって入手
spilcd.c
spilcd.h
font8.h

http://mbed.org/users/Sim/

http://blog.goo.ne.jp/sim00/

http://blog.goo.ne.jp/sim00
/c/5ea7bba8b30eb2dfb492f7289aa217d1


http://hamayan.ddo.jp
/~hamayan/so-net/font.html
http://mbed.org/users/Sim/programs/FontTest/gpdz3d . 特にコメントを見つけ出せなせんでした










いくつかの事例
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES

<ROM&RAM使用方法>

LPC1768には下記の様に、ROMとRAMがアサインされています。

種類 サイズ アドレス
ROM 512KB 0x0 -> 0x7ffff
RAM 32KB 0x10000000 -> 0x1007fff
RAM 16KB 0x2007c000 -> 0x2007ffff
RAM 16KB 0x20080000 -> 0x20083fff

問題は、RAMが合計64KBあるのも関わらず連続していないことです。
従って、64KBのRAMと言っても実際には使いずらい仕様になっており、最初使い始めた時には戸惑いました。

とは言っても今更ユーザーの立場で動的に配置変更出来ませんので、現実を直視して下記の作業をしました。
先ずは、Cソースファイル内で下記の様に宣言します。RAMの割付けにセクション指定します。


    //      Queue data buffer for LCD display
    uint8_t         GpsQBuff[20]    __attribute__((section(".ex_ram2")));
    uint8_t         FileQBuff[20]   __attribute__((section(".ex_ram2")));
    uint8_t         Othr1QBuff[20]  __attribute__((section(".ex_ram2")));
    uint8_t         Othr2QBuff[20]  __attribute__((section(".ex_ram2")));

Makeファイル(rtos_lpc1768_Debug.ld)では、下記のように設定し、先のセクション指定した場所を指定します。

    MEMORY
    {
         FLASH (rx) : ORIGIN = 0x0 LENGTH = 0x80000
         SRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 0x8000
         AHBRAM0(rwx)   : ORIGIN = 0x2007c000, LENGTH = 0x4000
         AHBRAM1(rwx)   : ORIGIN = 0x20080000, LENGTH = 0x4000
    }

          ------- 途中省略 ----------

    SECTIONS
    {               
            .ETHRAM (NOLOAD) :
            {
                    *(.ex_ram1*)
                    _ex_ram1_end = .;
            } > AHBRAM0
            __eahb1_data_end =.;
        
            .USBRAM (NOLOAD) :
            {
                    *(.ex_ram2*)
            } > AHBRAM1

    }


この設定で、0x20080000からからのRAM領域16KBを色々な目的に使うことが出来ます。
初めに、0x2007c000からの16KBも使おうとしたのですが、ここは既にLAN制御で下記の様な宣言で使っていました。
uIPを利用してLAN制御する場合には、0x2007c000からは使用しないでください。
ファイル EthDev_LPC17xx.h内には、0x2007c00からの使用宣言が書かれています。
但し、この宣言ではRAM配置にリンカが関与しませんので、*.mapファイルを見ても使用の有無が判りません。
これに絡んだBugで悩みました。


/* EMAC Memory Buffer configuration for 16K Ethernet RAM. */
#define NUM_RX_FRAG         3           /* Num.of RX Fragments. */
#define NUM_TX_FRAG         2           /* Num.of TX Fragments. */
#define ETH_FRAG_SIZE       1536        /* Packet Fragment size 1536 Bytes   */
#define ETH_MAX_FLEN        1536        /* Max. Ethernet Frame Size          */

          ------- 途中省略 ----------   

/* EMAC variables located in AHB SRAM bank 1*/
#define AHB_SRAM_BANK1_BASE  0x2007c000UL
#define RX_DESC_BASE        (AHB_SRAM_BANK1_BASE         )
#define RX_STAT_BASE        (RX_DESC_BASE + NUM_RX_FRAG*(2*4))     /* 2 * uint32_t, see RX_DESC_TypeDef */
#define TX_DESC_BASE        (RX_STAT_BASE + NUM_RX_FRAG*(2*4))     /* 2 * uint32_t, see RX_STAT_TypeDef */
#define TX_STAT_BASE        (TX_DESC_BASE + NUM_TX_FRAG*(2*4))     /* 2 * uint32_t, see TX_DESC_TypeDef */
#define ETH_BUF_BASE        (TX_STAT_BASE + NUM_TX_FRAG*(1*4))     /* 1 * uint32_t, see TX_STAT_TypeDef */

/* RX and TX descriptor and status definitions. */
#define RX_DESC_PACKET(i)   (*(unsigned int *)(RX_DESC_BASE   + 8*i))
#define RX_DESC_CTRL(i)     (*(unsigned int *)(RX_DESC_BASE+4 + 8*i))
#define RX_STAT_INFO(i)     (*(unsigned int *)(RX_STAT_BASE   + 8*i))
#define RX_STAT_HASHCRC(i)  (*(unsigned int *)(RX_STAT_BASE+4 + 8*i))
#define TX_DESC_PACKET(i)   (*(unsigned int *)(TX_DESC_BASE   + 8*i))
#define TX_DESC_CTRL(i)     (*(unsigned int *)(TX_DESC_BASE+4 + 8*i))
#define TX_STAT_INFO(i)     (*(unsigned int *)(TX_STAT_BASE   + 4*i))
#define ETH_BUF(i)          ( ETH_BUF_BASE + ETH_FRAG_SIZE*i )
#define ETH_NUM_BUFFERS     ( NUM_TX_FRAG + NUM_RX_FRAG + 1 )
   /* There are in fact 2 more buffers than descriptors as the two Tx descriptors use the same buffer to speed up the uip Tx. */

上記で判ることは、
NUM_RX_FRAG*(2*4) = 3*2*4 = 24B
などから、
24+24+16+8+(1536*i)
だけ、使用されるようです。'i' はemac.c内でETH_NUM_BUFFERSに設定されていますので、2+3+1=6となり、
RAM合計=24+24+16+8+(1536*6)=9288B
が使用されています。
16KBの領域で約9KBですから、(上記計算が間違ってなく、且つ他に使っていなければ)残り7KBはまだ上手く使えば利用可能です。

現時点での、データロガーでのROM/RAM使用状況は下記の様な状況です。
種類 サイズ アドレス 使用量 サイズ 使用率
ROM 512KB 0x0 -> 0x7ffff 0x0 -> 0x00016584 91524B 17.5%
RAM 32KB 0x10000000 -> 0x1007fff 0x10000000 -> 0x10006f8c 28556B 87.1%
RAM 16KB 0x2007c000 -> 0x2007ffff . 9288B 56.7%
RAM 16KB 0x20080000 -> 0x20083fff 0x20080000 -> 0x2008125c 4700B 28.7%







<MONプログラム>

今回、一つのタスクとしてモニタープログラムを動作させて利用しています。
PCとはシリアル通信をしていますが、①UARTと②USBのどちらかを選択できるようにしています(別項UARTとUSBを参照)。
使用例を下記に示します。

現在対応しているコマンドを下記に示します。
No. 分類 コマンド コマンド形式 解説
Help Help コマンドのヘルプ
2 d? Help
3 f? Help
4 r? Help
5 s? Help
6 m>? Help(メモリモードに入ってから)
7 メモリ
関連
m m - Enter Memory Mode メモリコマンドモードへ
8 m>d d <address> [<count>] - Dump memory メモリ内容の128バイト毎のダンプ
9 m>s s - Show memory structure メモリ構造表示
10 m>(RET) <RET> - Dump memory / next 128 bytes 単純に<RET>=”Enter"で次の128バイト表示
11 m>(BS) <BS> - Dump memory / same as before 128 bytes 前の128バイト表示
12 m>(ESC) <BS> - Dump memory / same as before 128 bytes メモリコマンドモード終了
13 ADC
変換データ
a a - Show ADC data ADCデータ表示
14 GPS
情報
g g - Show GPS latest data GPSデータ表示
15 スイッチ
状態
p p - Show Port status スイッチ3個のON/OFF状況表示
16 1秒毎表示 / / - Show data every one second /a, /g, /p, /t 一秒間毎に同じコマンドを自動的に実行し表示する
このコマンドでは、ADC、GPS、スイッチ、時間を繰り返し表示
17 時間表示
設定
t t [<year> <mon> <mday> <hour> <min> <sec>]
  e.g. 2010/8/13 13:5:20 -> t 2010 8 13 13 5 20<ENT>
時間表示と設定
18 UART
設定状況
u u - Show UART condition UARTの使用状況、ボーレート表示
19 FreeRTOS ri ri - Task information タスク状況表示
20 rs rs - Stack status スタック消費状況表示
21 rt rt - Run-Time statistics CPU占有率表示
22 CPU sc sc - System CPU information CPUの種類表示
23 sf sf - System Clock CPU動作周波数表示
24 DISK dd dd [<lba>] - Dump sector オリジナルのソースファイルに入っていたものを
そのまま使用しています。
但し、FatFsのリエントラント機能を使用していないために、
データロガーとして使用中にコマンドを実行するとフリーズ
してしまいます。
従って、ほとんど使用していません。
25 di di - Initialize disk
26 ds ds - Show disk status
27 FILE fc fc - Close a file
28 fd fd <len> - read and dump file from current fp
29 fi fi - Force initialized the logical drive
30 fk fk <name> - Create a directory
31 fl fl [<path>] - Directory listing
32 fn fn <old_name> <new_name> - Change file/dir name
33 fo fo <mode> <file> - Open a file
34 fr fr <len> - read file
35 fs fs - Show logical drive status
36 fu fu <name> - Unlink a file or dir
37 fv fv - Truncate file
38 fw fw <len> <val> - write file
39 fx fx <src_name> <dst_name> - Copy file
40 fz fz [<rw size>] - Change R/W length for fr/fw/fx command
41 DISK IO bd bd <addr> - Dump R/W buffer
42 be be <addr> [<data>] ... - Edit R/W buffer
43 bf bf <val> - Fill working buffer
44 br br <lba> [<num>] - Read disk into R/W buffer

このモニタープログラムの原型は、
NXPのサイト
All microcontrollers support documents for LPC1768

"AN10916 FAT library EFSL and FatFs port on NXP LPC1700 V2 (Jul 6, 2010) with software (Feb 3, 2010)"
の中に入っている、
   ..\an10916\LPC1700_FatFs_Prj\Main\main.c (time stamp 2010/02/03 16:24)
を参考にしています。

モニタープログラムに使用するソースファイルを下記に示します。
No. ソースファイル名
1 monitor_main.c
2 monitor.h
3 monitor.c










<UARTプログラム>
シリアル通信に使用するモジュールは下記です。
No. ソースファイル名
1 uart.c
2 uart.h
3 ring.c
4 ring.h
現在は、下記のように設定しています。
UART2は、モニタープログラム(上記のようにPCとの通信)用に使っています。
ボーレートは、115200baudの目標で実際には、116062baud(誤差+0.74%)となっています。
UART3は、GPSのデータ受信と初期設定値送信に使用しています。
ボーレートは、4800baudの目標に対して、4818baud(誤差+0.38%)です。

UART2の送受信関係を下記に示します。
受信は、割込みを使用してリングバッファにデータを蓄えていますが、送信はバッファなしでそのまま書き込んでいます。
LPC1768のUARTには、16バイトのFIFOが付いており、送信には割込みなしで対応しても大きな問題はないでしょう。
UART3はGPSの受信が主で送信はコマンドのみなので、このままで良いでしょうが、UART2は、送信するデータ量が多いので、ボーレートを遅くする場合には、下記のようにプログラムを変えたほうが良いかもしれません。

現在のプログラム

// Output one character
void Uart_PutCharBuf2(uint8_t c) {
        /* THRE status, contain valid data */
        while ( !(( LPC_UART2->LSR ) & LSR_THRE ));     // Polling for write action
        LPC_UART2->THR = (uint16_t)c & 0xFF;
}
修正版
例えば、4800baudとするなら、1バイト送信に2.08ms(1/4800 x 10 (1 start + 8 data + 1 stop))ですから、下記のようにします。
115200baudであれば、1バイト送信は86.8μsですのでポーリングで充分でしょう。

void Uart_PutCharBuf2(uint8_t c) {
        /* THRE status, contain valid data */
        while ( !(( LPC_UART2->LSR ) & LSR_THRE )){
             vTaskDelay(3/portTICK_RATE_MS );           // Wait 3mS
        }
        LPC_UART2->THR = (uint16_t)c & 0xFF;
}
受信の場合にはデータが無い時には、FreeRTOSに制御を渡しています。

// Get one character
uint8_t Uart_GetC2(){
        while(ring_getc (&ring_rx2)){
                vTaskDelay(1/portTICK_RATE_MS );        // Wait 1mS
        }
        return ring_rx2.dt_got;
}
UART3も同様な構造で、受信用にリングバッファを用意しています。
リングバッファに対する操作は、下記の図のようになっています。













<LPCUSB関連>

LPCUSBで出来ること


私が、現時点(2010年10月16日)で動作確認したのは、下記の二つのクラスです。
  • CDC (Comunication Device Class)
  • MSC (Mass Storage Class)
CDCは、USB経由の仮想COMとしてPCとのシリアル通信が可能です。
今回はモニタープログラムの入出力をUART2経由かこの仮想COM経由かを切り替えて使っています。
MSCは、PCから見たときにUSBメモリとして、Micro-SDカードの入出力を制御します。

具体的には、FreeRTOSConfig.hの中で、下記のように選択します。
この設定で、USBはCDCとなります。

/*-----------------------------------------------------------
 * USB MODE
 *-----------------------------------------------------------*/
#define USB_HID         0
#define USB_CSTM        0
#define USB_UART        1
#define USB_DISK        0

/*-----------------------------------------------------------
 * Monitor interface
 *-----------------------------------------------------------*/
// Monitor On or Off
#define SET_MON         1
// Monitor via USB COM
#define MON_VIA_USB     1
// Monitor via UART
#define MON_VIA_UART    0

仮想COMでモニターを起動した画面と、コンパイルし直してMSCとしてMicro-SDをPCから覗けるようにした時の画面です。
USBをCDCに設定して、仮想COMとしてPCへ接続。
Tera TermでCOM9を開けてモニタープログラムとの接続を設定する。
Tera TermでUARTの状況を確認して、UART2が使われていないことを確認。


USBをMSCとして設定しLPCXpresso(1768)に接続したMicro-SDをPCから覗けるようにした

CDCの設定

注意点:
FreeRTOSのデモファイルには、元々USB_CDC.cが入っていました。
しかし、他のクラスも動作させたかったので、

LPC214x USB stack
をダウンロードしてUSB部分を再構築しました。
その際に、CDC関連のソースファイルは、main_serial.cの名称になっていました。
現在は、このファイルを修正して使っています。
従って、今後の説明には両方のファイル名が出てきますので注意願います。


サンプルの原型は、下記のようになっていました。
ファイル main_serial.c

int main(void)
{
        int c;

        // PLL and MAM
        Initialize();
    
    途中省略

        enableIRQ();

        // connect to bus
        USBHwConnect(TRUE);

        // echo any character received (do USB stuff in interrupt)
        while (1) {
                c = VCOM_getchar();
                if (c != EOF) {
                        // show on console
                        if ((c == 9) || (c == 10) || (c == 13) || ((c >= 32) && (c <= 126))) {
                                DBG("%c", c);
                        }
                        else {
                                DBG(".");
                        }
                        VCOM_putchar(c);
                }
        }

        return 0;
}
当初は、mon()の入出力に、上記のVCOM_getchar()とVCOM_putchar()をそのまま使おうとしましたが、使えませんでした。
理由は、VCOM_getchar()が下記のようにデータ受信(PCからLPC1768)の際にキューを待ってしまい。制御が戻ってこない点です。

ファイル USB_CDC.c

uint16_t VCOM_getchar(void)
{
        uint8_t c;
        
        /* Block the task until a character is available. */
        xQueueReceive( xRxedChars, &c, portMAX_DELAY );
        return c;
}
更に、USBのタスクとMONタスクが別々に動作しているので、両タスク間でのデータやり取りの方法を考えなければなりません。
そこで、下記の様にリングバッファを多用して各制御を同期させました。
リングバッファを3つ用意して対応しました。
仮想COMということで直接関係ありませんが、プログラムはuart.c内に入れました。VCOM_getchar()とVCOM_putchar()を基準に、二つのタスクの同期をuart.cの中で吸収しています。
monitor.c内(上記赤の四角部分)で、UART2と仮想COMを条件によって使い分けています。
下記は、xputs()の例です。

void xputs (const char* str)
{
#if (MON_VIA_UART == 1)
        while (*str)
                xputc(*str++);
#elif (MON_VIA_USB == 1)
        USB_PutStrBuf((char *)str);
#endif
}
更に、VCOM_getchar()が制御を戻さない問題も、下記のようにUSB_ChkESnd()を追加して解決しています。

ファイル main_serial.c内の無限ループ

        for( ;; ){
#if (MON_VIA_UART == 1)
    省略
#elif (MON_VIA_USB == 1)
                c = VCOM_getchar();
                if ( c != 0 ){
                        USB_PutRcvBuf(c);
                } else {
                        vTaskDelay( 1 / portTICK_RATE_MS );
                }
                while (!USB_ChkESnd()){
                        c = USB_GetSndBuf();
                        if ( c != 0 ){
                                VCOM_putchar( c );
                        } else {
                                break;
                        }
                }
                uxHiWtrMrk_usb = uxTaskGetStackHighWaterMark( NULL );
#endif
        }

ファイル uart.c

// Check output
uint16_t USB_ChkESnd( void ){
        return ring_is_empty (&ring_txu);
}






MSCの設定

USB経由で、PCからLPC1768システム上のMicro-SDカードをマスストレージと認識させることが目標です。
プログラムのメインとなるのは、main_msc.cのファイルです。このプログラムを解析していくと下記の様な関係が判ります。
小さくて見づらいと思いますので、pdfファイルがリンクしてあります。参照ください。
表の中で判りづらいところがありますので、下記コメントも参照ください。
  • この表は、全てのファンクションを網羅することを目的としていません。
    作表の目的は、SDカードを制御しているFatFsとどのように共存させるかを目的としています。
  • 結果として、オレンジ色のファンクションがFatFsと関係するモジュールとなりました。
    BlockDevInit()、BlockDevGetSize()、BlockDevWrite()、BlockDevRead()の各ファンクションで全てblockdev_sd.c内です。
  • 結果として、黄色のファンクション(Check_Idle())を新規作成して、usbhw_lpc.c内に収めました。
  • USBHwISR()には、階層化表現として何も書かれていませんが、色々な機能が登録されています。この部分は別項を参照ください。
  • 'x'が書かれているのは、FatFSとのインターフェイス解析の目的では、それ以上の階層化解析は不要とした結果です。
FatFsモジュールとの(実際には、FatFsとではなく、よりハードウェアに近いドライバーとの)インターフェイスを作るために、blockdev_sd.cの中で修正した内容を下記に示します。
No. ファンクション名 機能 修正のポイント
1 BlockDevInit() SDカードとのインターフェイス初期化
SPI機能の初期化に続いて初期化コマンドを実行
FatFsには、disk_initialize()が実装されているので、それを呼び出すように修正
..\fat_sd\lpc17xx_sd.c内既存
2 BlockDevGetSize() SDカードのサイズを返す 初期化の際に、
 static SDCFG SDCfg;
の中にある情報を取り出すファンクションを新設しました
..\fat_sd\lpc17xx_sd.c内に新規
3 BlockDevWrite() 512バイト単位の書込み disk_write()があるので、それを呼び出し
..\fat_sd\lpc17xx_sd.c内既存
4 BlockDevRead() 512バイト単位の読出し disk_read()があるので、それを呼び出し
..\fat_sd\lpc17xx_sd.c内既存

USBHwISR()の機能


CDCの場合には、USBHwISR()は割込み処理として呼び出されます。
ファイル main_serial.c

void USB_IRQHandler(void)
{
        USBHwISR();
}

void vUSBTask( void *pvParameters ){
        省略
        // register descriptors            // 割込み処理の呼出しルーチンの登録(ここから)
        USBRegisterDescriptors(abDescriptors);
        省略
        // enable bulk-in interrupts on NAKs
        USBHwNakIntEnable(INACK_BI);
                                           // 割込み処理の呼出しルーチンの登録(ここまで)
        NVIC_SetPriority( USB_IRQn, configUSB_INTERRUPT_PRIORITY );
        NVIC_EnableIRQ( USB_IRQn );        // ここで割込み許可
        // connect to bus
        USBHwConnect(TRUE);
        // echo any character received (do USB stuff in interrupt)
        c = '0';
        for( ;; ){                        // ここではUSBHwISR()は当然、呼ばれない → 上記USB_IRQHandler()内
                c = VCOM_getchar();
                if ( c != 0 ){
                        USB_PutRcvBuf(c);
                } else {
                        vTaskDelay( 1 / portTICK_RATE_MS );
                }
                while (!USB_ChkESnd()){
                        c = USB_GetSndBuf();
                        if ( c != 0 ){
                                VCOM_putchar( c );
                        } else {
                                break;
                        }
                }
                uxHiWtrMrk_usb = uxTaskGetStackHighWaterMark( NULL );
        }
}
これに対して、MSCでは、下記のように呼び出しています。

ファイル main_msc.c

void vUSBTask( void *pvParameters ){
     省略
         // enable bulk-in interrupts on NAKs
        // these are required to get the BOT protocol going again after a STALL
        USBHwNakIntEnable(INACK_BI);
        // register descriptors
        USBRegisterDescriptors(abDescriptors);
        // register class request handler
        USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);
        // register endpoint handlers
        USBHwRegisterEPIntHandler(MSC_BULK_IN_EP, MSCBotBulkIn);
        USBHwRegisterEPIntHandler(MSC_BULK_OUT_EP, MSCBotBulkOut);
        // connect to bus
        USBHwConnect(TRUE);
        // call USB interrupt handler continuously   // 割込みを登録していない
        while (1) {
                if (Check_Idle()){
                        vTaskDelay(1/portTICK_RATE_MS);                 // Wait
                }
                USBHwISR();              // ここで呼び出している
                uxHiWtrMrk_usb = uxTaskGetStackHighWaterMark( NULL );
        }
}
SPI経由で512バイト単位の読み書きもあり、割込み処理では対応できないとの判断だと思います。
FreeRTOSの機能を使って割込みとの協調で対応するのが良いと思います。

USBHwISR内では、様々な割込み要因で機能分岐しています。
最上位のものは、下記の3つです。
  • MSCBotBulkIn()
  • MSCBotBulkOut()
  • HandleClassRequest()
USBHwISR()を割込みにしなかったことで、常に"USB Device Interrupt Status register (USBDevIntSt)"をポーリングして素早い対応をする必要があります。
今回は、Check_Idle()を新規作成して、割込み要因の有無を判定して要因が無ければ1msの待ちをタスクに与えています。
この対応で、USBタスクのCPU占有率を下げることが出来ました。

USBの問題点

現時点でいくつかの問題点があります。
  • CDC使用時、USBケーブルをPCに接続したまま立ち上げると、その後PCに仮想COMとして認識してもらえません。
    USBケーブルを抜いた状態でLPC1768側を立ち上げて、その後PCと接続してTera Termを立ち上げています。
  • MSC使用時、8GBメモリが認識されません。->2010年11月6日 一様解決済(下記MicroSDを参照ください)
    カードのサイズを返す関数のオーバーフローが原因と思われます。プログラム修正が必要です。
    但し、8GBのMicro-SDでもFatFsがデータロガーとして書き込む動作には支障が出ていません。






<MicroSD(ファイル)プログラム>

SDカード(MicroSD)の制御プログラムは、下記のファイルにて構成されています。
No. ファイル名 コメント
1 ff.c FatFs-ELM by ChaN

http://elm-chan.org/fsw/ff/00index_j.html にて提供されているモジュール
2 ff.h
3 ffconf.h
4 integer.h
5 diskio.h
6 option/cc932.c
7 option/cc936.c
8 option/cc949.c
9 option/cc950.c
10 option/ccsbcs.c
11 option/syscall.c
12 lpc17xx_sd.c NXP
All microcontrollers support documents for LPC1768
AN10916 FAT library EFSL and FatFs port on NXP LPC1700 V2(Jul 6,2010) with software (Feb 3,2010)
内にあるサンプルプログラムベース
13 lpc17xx_sd.h
14 lpc17xx_spi.c
15 lpc17xx_spi.h
ChaNさん提供のソースファイルに対して、SPI経由のSDカード制御プログラムを下位レイヤ・インターフェイスを提供する必要があります。
今回は、NXP提供のサンプルプログラムを修正して使用させていただきました。

ハードウェアとしては、下記SPIを利用しています。
LPC1768信号名 LPC1768ピン配置 mbed信号名 mbedピン配置
P0[18]/DCD1/MOSI0/MOSI 60 SPI/mosi p11
P0[17]/CTS1/MISO0/MISO 61 SPI/miso p12
P0[15]/TXD1/SCK0/SCK 62 SPI/sck
Serial/tx
p13
P0[16]/RXD1/SSEL0/SSEL 63 Serial/rx p14
速度は、まだ改良すべき課題です。現状は、537,400,028バイトの1つのファイルをPCからUSB経由でMicroSDに書き込んだところ45分かかった。

199037バイト/1秒 (194KB/sec)

2回目に同じファイルで実行した場合の実測値は、
537,400,028バイト 40分
223916バイト/1秒 (218KB/sec)

となった。
ちなみに手持ちのUSB2.0 CardReader BUFFALO BSCRA26U2にて同じファイルを転送すると、30秒で完了しました。
(HSモード(最大転送速度480Mbps)を使用するには、バファロー製USBインターフェイスを取り付けるように書かれていますが、使用していません)

17913334バイト/1秒 (17493KB/sec 17MB/SEC)

512バイト単位でのDMA転送が出来そうですが、これも課題ですが当分(永遠に)解決できそうにありません。


ファイルシステムのBUG修正

2010年10月17日時点で、”MSC使用時、8GBメモリが認識されません”と書きましたが問題点がはっきりしたので、現時点(11月6日)での対応内容を残します。

問題点
4GBのMicroSDを装備して、USB経由でPCと接続すると正しく認識されるが、8GBではPCから正しく認識されずエクスプローラでドライブ内部を観ることが出来ない。
初めに判明した点は、lpc17xx_sd.h内で、
typedef struct tagSDCFG{
 uint32_t   sernum;   // serial number
 uint32_t   size;    // size=sectorsize*sectorcnt
 uint32_t   sectorcnt;  //
 uint32_t   sectorsize;  // 512
 uint32_t   blocksize;  // erase block size
 uint8_t    ocr[4];    // OCR
 uint8_t    cid[16];   // CID
 uint8_t    csd[16];   // CSD
} SDCFG;
となっており、sizeが32bitで表現している点です。
これでは、8GBではオーバーフローしてしまいます。

8GB容量  7,998,623,856バイト = 0x1dcc15070 -> 00000001-11011100-11000001-01010000-01110000 (4バイトでは赤字部分がオーバーフローしてしまう)

64bitでsizeを構成する必要があります。そこで下記変更を加えました。
変更ファイル 変更前 変更内容 コメント
lpc17xx_sd.c uint32_t disk_size_inf ( void ) uint64_t disk_size_inf ( void ) 64ビットでディスク容量を返すように

unit64_tunsigned long longU32などが混在していますが、流用元の流儀をあまり変えないようにしている為です。
FreeRTOSの形式(portBASE_TYPEなど)やDDWORDの表現も入っていて、全体としてはかなり混沌としています。
lpc17xx_sd.h /* MMC device configuration */
typedef struct tagSDCFG{
 uint32_t sernum; // serial number
 uint32_t size;   // size=sectorsize*sectorcnt
/* MMC device configuration */
typedef struct tagSDCFG{
 uint32_t sernum; // serial number
 uint64_t size;   // size=sectorsize*sectorcnt
blockdev.h U32 BlockDevGetSize(void) unsigned long long BlockDevGetSize(void)
blockdev_sd.c U32 BlockDevGetSize(void) unsigned long long BlockDevGetSize(void)
msc_scsi.c U32 dwDevSize, dwMaxBlock; U32 dwMaxBlock;
unsigned long long dwDevSize;
これで直ったと思ったのですが、下記の様な表示になります。
修正後に(私のPCの場合には)F:ドライブとして正しく認識されるようになりましたが、モニタープログラムで"fl"コマンドを実行すると未だ正しく表示されません。
更に追加修正した部分を下記に示します。
変更ファイル 変更前 変更内容
monitor_main.c static long p1, p2, p3;
UINT s1, s2, cnt;

xprintf("%4u File(s),%10lu bytes total\n%4u Dir(s)", s1, p1, s2);
static long p1, p2, p3;
DDWORD pf;

p1 = pf%100;
xprintf("%4u file(s),%10lu%02lu bytes total\n%4u Dir(s)", s1, (DWORD)(pf/100), p1, s2);
blockdev_sd.c int BlockDevGetSize(U32 *pdwDriveSize){
    .....
extern unsigned long long disk_size_inf( void );

// Get Device media size
unsigned long long BlockDevGetSize(){
 return disk_size_inf();
}
これでようやく解決しました。少し気持ち悪いのは、PC(Windows XP)の認識容量とモニタープログラムの容量表示が微妙に違う!?









<uIP関連プログラム>

内容検討中











<GPSプログラム>

内容検討中









<ADCプログラム>

内容検討中









<RTCプログラム>

内容検討中








<LCDプログラム>

内容検討中