TMR-FC

A STM32F4 based flight controller.

2013年7月9日 星期二

Eclipse 環境中的 NuttX 編譯和除錯 using TMR-FC board

#01 : NuttX 是什麼 ??


NuttX Real-Time Operating System

NuttX is a real-time operating system (RTOS) with an emphasis on standards compliance and small footprint. Scalable from 8-bit to 32-bit microcontroller environments, the primary governing standards in NuttX are Posix and ANSI standards. Additional standard APIs from Unix and other common RTOS's (such as VxWorks) are adopted for functionality not available under these standards, or for functionality that is not appropriate for deeply-embedded environments (such as fork()).
NuttX was first released in 2007 by Gregory Nutt under the permissive BSD license.
Nuttx 是一個實時嵌入式操作系統(RTOS),它有一個小巧是在微控制器的環境中使用。這是完全可擴展,從小型(8位)至中型嵌入式(32位)系統。它的目的還在於要完全符合標准,完全實時,並完全開放。
在 eclipse 裡要能對 Nuttx 做編譯及除錯需要預先安裝一軟體工具及設定, 說起來算是比較複雜的, 我自己摸索了好久才把環境給架設起來, 在這邊做個筆記, 方便日後參考, Nuttx 的中文資源非常非常少, 有必較多的參考資料就是官方的 Document. 要啃很多英文相對累, 自找麻煩.

過程中所遇到的問題 :    冏....

tool chain, cygwin, jlink, GDB, eclipse, .. etc. 基本上都解決了, 目前也調適得很順利.

為什麼會想用 Nuttx ?  

用過的 RTOS 有 uC/OS, FreeRTOS, RT-Thread , 這幾個用起來都蠻順利的, 也都很快就能跑 Demo code, 唯有 Nuttx 讓我覺得又愛恨, 難上手又複雜, 但是就是想用上他, 基於一個 Software Engineer 的自信, 我相信我能搞定他!! 且 Nuttx 的作者已經把我的 Project "TMR-FC" 放上了他的網站 Link, 因為我告訴他我正在使用 Nuttx, 冏 ... 為了這個面子也才有機會深入研究他. Nuttx 是個非常棒的 Real-Time RTOS !!

TSAO, CHIA-CHENG  @NTUT, TAIPEI, TAIWAN  02/07/2013



#02 : 硬體設備








     

TMR-FC 是一個開源硬體 (Open Source Hardware, OSHW) 開源電路設計及源碼, TMR-FC 板上具備 MPU6050 ( 3軸陀螺儀,3軸加速規 ) , HMC5883l 地磁  及 MS5611 大氣壓力等多種感測器, 使用 ST 義法半導體的 STM32F405RG ( ARM Cortex-M4) 的控制器, 板上具備 PWM 輸出入及超聲波模組介面, RF 介面, GPS 介面, 電流感測器介面, LED 控制介面, 等等. 其主要作為航空模型控制用途.
TMR-FC 電路圖( Schematic ) 下載連結 :   TMR_FC_HW_V1_120830.pdf


現在還是一人團隊, 自己一個在作, 希望找到好夥伴. 來信或留言.

https://code.google.com/p/tmr/http://git.oschina.net/tmr-fc/tmr-fchttp://www.segger.com/http://freedomdefined.org/https://gnu.org/licenses/


#03 : Eclipse 設定


Version : Kepler Release
http://www.eclipse.org/

需要安裝 C/C++ GDB Hardware Debugging.



--UART 除錯訊息--



 

下面是跑 ostest 過程的詳細訊息,
tmrfc/ostest - > defconfig 裡需要做設定並重新編譯
#
# Debug Options
#
CONFIG_DEBUG=y
( TMR-FC Side )
出訊息導向 USART1, 並透過藍芽模組開始傳送資料.
 (PC Side)
電腦藍芽跟TMR-FC 上的藍芽模組配對後可得到虛擬 com port ( example com3 to be found on my PC ) , 使用 terminal  打開 com3, baud rate 設定 11520 即可開始接收資料.

ABCDF
stdio_test: write fd=1
stdio_test: Standard I/O Check: printf
stdio_test: write fd=2
stdio_test: Standard I/O Check: fprintf to stderr
ostest_main: Started user_main at PID=2
ostest_main: Exitting

user_main: Begin argument test
user_main: Started with argc=5
user_main: argv[0]="ostest"
user_main: argv[1]="Arg1"
user_main: argv[2]="Arg2"
user_main: argv[3]="Arg3"
user_main: argv[4]="Arg4"

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: /dev/null test
dev_null: Read 0 bytes from /dev/null
dev_null: Wrote 1024 bytes to /dev/null

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: task_restart test

Test task_restart()
restart_main: Started restart_main at PID=3
restart_main: Started with argc=4
restart_main: argv[0]="ostest"
restart_main: argv[1]="This is argument 1"
restart_main: argv[2]="Argument 2 here"
restart_main: argv[3]="Lastly, the 3rd argument"
restart_main: I am still here
restart_main: I am still here
restart_main: Started with argc=4
restart_main: argv[0]="ostest"
restart_main: argv[1]="This is argument 1"
restart_main: argv[2]="Argument 2 here"
restart_main: argv[3]="Lastly, the 3rd argument"
restart_main: Exitting

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: mutex test
Initializing mutex
Starting thread 1
Starting thread 2
                Thread1 Thread2
        Loops   32      32
        Errors  0       0

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: cancel test
cancel_test: Test 1: Normal Cancelation
cancel_test: Starting thread
start_thread: Initializing mutex
start_thread: Initializing cond
start_thread: Starting thread
thread_waiter: Taking mutex
thread_waiter: Starting wait for condition
start_thread: Yielding
cancel_test: Canceling thread
cancel_test: Joining
cancel_test: waiter exited with result=ffffffff
cancel_test: PASS thread terminated with PTHREAD_CANCELED
cancel_test: Test 2: Cancelation of detached thread
cancel_test: Re-starting thread
restart_thread: Destroying cond
restart_thread: Destroying mutex
restart_thread: Re-starting thread
start_thread: Initializing mutex
start_thread: Initializing cond
start_thread: Starting thread
thread_waiter: Taking mutex
thread_waiter: Starting wait for condition
start_thread: Yielding
cancel_test: Canceling thread
cancel_test: Joining
cancel_test: PASS pthread_join failed with status=ESRCH
cancel_test: Test 3: Non-cancelable threads
cancel_test: Re-starting thread (non-cancelable)
restart_thread: Destroying cond
restart_thread: Destroying mutex
restart_thread: Re-starting thread
start_thread: Initializing mutex
start_thread: Initializing cond
start_thread: Starting thread
thread_waiter: Taking mutex
thread_waiter: Starting wait for condition
thread_waiter: Setting non-cancelable
start_thread: Yielding
cancel_test: Canceling thread
cancel_test: Joining
thread_waiter: Releasing mutex
thread_waiter: Setting cancelable
cancel_test: waiter exited with result=ffffffff
cancel_test: PASS thread terminated with PTHREAD_CANCELED

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: semaphore test
sem_test: Initializing semaphore to 0
sem_test: Starting waiter thread 1
sem_test: Set thread 1 priority to 191
waiter_func: Thread 1 Started
waiter_func: Thread 1 initial semaphore value = 0
waiter_func: Thread 1 waiting on semaphore
sem_test: Starting waiter thread 2
sem_test: Set thread 2 priority to 128
waiter_func: Thread 2 Started
waiter_func: Thread 2 initial semaphore value = -1
waiter_func: Thread 2 waiting on semaphore
sem_test: Starting poster thread 3
sem_test: Set thread 3 priority to 64
poster_func: Thread 3 started
poster_func: Thread 3 semaphore value = -2
poster_func: Thread 3 posting semaphore
waiter_func: Thread 1 awakened
waiter_func: Thread 1 new semaphore value = -1
waiter_func: Thread 1 done
poster_func: Thread 3 new semaphore value = -1
poster_func: Thread 3 semaphore value = -1
poster_func: Thread 3 posting semaphore
waiter_func: Thread 2 awakened
waiter_func: Thread 2 new semaphore value = 0
waiter_func: Thread 2 done
poster_func: Thread 3 new semaphore value = 0
poster_func: Thread 3 done

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: condition variable test
cond_test: Initializing mutex
cond_test: Initializing cond
cond_test: Starting waiter
cond_test: Set thread 1 priority to 128
waiter_thread: Started
cond_test: Starting signaler
cond_test: Set thread 2 priority to 64
thread_signaler: Started
thread_signaler: Terminating
cond_test: signaler terminated, now cancel the waiter
cond_test:      Waiter  Signaler
cond_test: Loops        32      32
cond_test: Errors       0       0
cond_test:
cond_test: 0 times, waiter did not have to wait for data
cond_test: 0 times, data was already available when the signaler run
cond_test: 0 times, the waiter was in an unexpected state when the signaler ran

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: timed wait test
thread_waiter: Initializing mutex
timedwait_test: Initializing cond
timedwait_test: Starting waiter
timedwait_test: Set thread 2 priority to 177
thread_waiter: Taking mutex
thread_waiter: Starting 5 second wait for condition
timedwait_test: Joining
thread_waiter: pthread_cond_timedwait timed out
thread_waiter: Releasing mutex
thread_waiter: Exit with status 0x12345678
timedwait_test: waiter exited with result=12345678

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: message queue test
mqueue_test: Starting receiver
mqueue_test: Set receiver priority to 128
receiver_thread: Starting
mqueue_test: Starting sender
mqueue_test: Set sender thread priority to 64
mqueue_test: Waiting for sender to complete
sender_thread: Starting
receiver_thread: mq_receive succeeded on msg 0
sender_thread: mq_send succeeded on msg 0
receiver_thread: mq_receive succeeded on msg 1
sender_thread: mq_send succeeded on msg 1
receiver_thread: mq_receive succeeded on msg 2
sender_thread: mq_send succeeded on msg 2
receiver_thread: mq_receive succeeded on msg 3
sender_thread: mq_send succeeded on msg 3
receiver_thread: mq_receive succeeded on msg 4
sender_thread: mq_send succeeded on msg 4
receiver_thread: mq_receive succeeded on msg 5
sender_thread: mq_send succeeded on msg 5
receiver_thread: mq_receive succeeded on msg 6
sender_thread: mq_send succeeded on msg 6
receiver_thread: mq_receive succeeded on msg 7
sender_thread: mq_send succeeded on msg 7
receiver_thread: mq_receive succeeded on msg 8
sender_thread: mq_send succeeded on msg 8
receiver_thread: mq_receive succeeded on msg 9
sender_thread: mq_send succeeded on msg 9
sender_thread: returning nerrors=0
mqueue_test: Killing receiver
receiver_thread: mq_receive interrupted!
receiver_thread: returning nerrors=0
mqueue_test: Canceling receiver
mqueue_test: receiver has already terminated

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: timed message queue test
timedmqueue_test: Starting sender
sender_thread: Starting
sender_thread: mq_timedsend succeeded on msg 0
sender_thread: mq_timedsend succeeded on msg 1
sender_thread: mq_timedsend succeeded on msg 2
sender_thread: mq_timedsend succeeded on msg 3
sender_thread: mq_timedsend succeeded on msg 4
sender_thread: mq_timedsend succeeded on msg 5
sender_thread: mq_timedsend succeeded on msg 6
sender_thread: mq_timedsend succeeded on msg 7
sender_thread: mq_timedsend succeeded on msg 8
timedmqueue_test: Waiting for sender to complete
sender_thread: mq_timedsend 9 timed out as expected
sender_thread: returning nerrors=0
timedmqueue_test: Starting receiver
receiver_thread: Starting
receiver_thread: mq_timedreceive succeeded on msg 0
receiver_thread: mq_timedreceive succeeded on msg 1
receiver_thread: mq_timedreceive succeeded on msg 2
receiver_thread: mq_timedreceive succeeded on msg 3
receiver_thread: mq_timedreceive succeeded on msg 4
receiver_thread: mq_timedreceive succeeded on msg 5
receiver_thread: mq_timedreceive succeeded on msg 6
receiver_thread: mq_timedreceive succeeded on msg 7
receiver_thread: mq_timedreceive succeeded on msg 8
timedmqueue_test: Waiting for receiver to complete
receiver_thread: Receive 9 timed out as expected
receiver_thread: returning nerrors=0
timedmqueue_test: Test complete

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: signal handler test
sighand_test: Initializing semaphore to 0
sighand_test: Starting waiter task
sighand_test: Started waiter_main pid=21
waiter_main: Waiter started
waiter_main: Unmasking signal 17
waiter_main: Registering signal handler
waiter_main: oact.sigaction=0 oact.sa_flags=0 oact.sa_mask=0
waiter_main: Waiting on semaphore
sighand_test: Signaling pid=21 with signo=17 sigvalue=42
wakeup_action: Received signal 17
wakeup_action: sival_int=42
wakeup_action: si_code=1
wakeup_action: ucontext=0
waiter_main: sem_wait() successfully interrupted by signal
waiter_main: done
sighand_test: done

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: POSIX timer test
timer_test: Initializing semaphore to 0
timer_test: Unmasking signal 17
timer_test: Registering signal handler
timer_test: oact.sigaction=0 oact.sa_flags=0 oact.sa_mask=0
timer_test: Creating timer
timer_test: Starting timer
timer_test: Waiting on semaphore
timer_expiration: Received signal 17
timer_expiration: sival_int=42
timer_expiration: si_code=2 (SI_TIMER)
timer_expiration: ucontext=0
timer_test: sem_wait() successfully interrupted by signal
timer_test: g_nsigreceived=1
timer_test: Waiting on semaphore
timer_expiration: Received signal 17
timer_expiration: sival_int=42
timer_expiration: si_code=2 (SI_TIMER)
timer_expiration: ucontext=0
timer_test: sem_wait() successfully interrupted by signal
timer_test: g_nsigreceived=2
timer_test: Waiting on semaphore
timer_expiration: Received signal 17
timer_expiration: sival_int=42
timer_expiration: si_code=2 (SI_TIMER)
timer_expiration: ucontext=0
timer_test: sem_wait() successfully interrupted by signal
timer_test: g_nsigreceived=3
timer_test: Waiting on semaphore
timer_expiration: Received signal 17
timer_expiration: sival_int=42
timer_expiration: si_code=2 (SI_TIMER)
timer_expiration: ucontext=0
timer_test: sem_wait() successfully interrupted by signal
timer_test: g_nsigreceived=4
timer_test: Waiting on semaphore
timer_expiration: Received signal 17
timer_expiration: sival_int=42
timer_expiration: si_code=2 (SI_TIMER)
timer_expiration: ucontext=0
timer_test: sem_wait() successfully interrupted by signal
timer_test: g_nsigreceived=5
timer_test: Deleting timer
timer_test: done

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: round-robin scheduler test
rr_test: Set thread priority to 1
rr_test: Set thread policy to SCHED_RR
rr_test: Starting first get_primes_thread
         First get_primes_thread: 22
rr_test: Starting second get_primes_thread
get_primes_thread id=1 started, looking for primes < 10000, doing 10 run(s)
         Second get_primes_thread: 23
rr_test: Waiting for threads to complete -- this should take awhile
         If RR scheduling is working, they should start and complete at
         about the same time
get_primes_thread id=2 started, looking for primes < 10000, doing 10 run(s)
get_primes_thread id=1 finished, found 1230 primes, last one was 9973
get_primes_thread id=2 finished, found 1230 primes, last one was 9973
rr_test: Done

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

user_main: barrier test
barrier_test: Initializing barrier
barrier_func: Thread 0 started
barrier_test: Thread 0 created
barrier_func: Thread 1 started
barrier_test: Thread 1 created
barrier_func: Thread 2 started
barrier_test: Thread 2 created
barrier_func: Thread 0 calling pthread_barrier_wait()
barrier_func: Thread 1 calling pthread_barrier_wait()
barrier_func: Thread 2 calling pthread_barrier_wait()
barrier_func: Thread 2, back with status=PTHREAD_BARRIER_SERIAL_THREAD (I AM SPECIAL)
barrier_func: Thread 0, back with status=0 (I am not special)
barrier_func: Thread 1, back with status=0 (I am not special)
barrier_func: Thread 2 done
barrier_func: Thread 0 done
barrier_func: Thread 1 done
barrier_test: Thread 0 completed with result=0
barrier_test: Thread 1 completed with result=0
barrier_test: Thread 2 completed with result=0

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0

Final memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena       2f140    2f140
ordblks         3        3
mxordblk    1e840    1e840
uordblks     1870     1870
fordblks    2d8d0    2d8d0
user_main: Exitting

--Environment 設定--
PATH 設定到 Cygwin 及 GNU ARM toolchain 的安裝目錄 
--Settings 設定--
 
--Tool Chain Editor 設定--
 
這裡因為 Nuttx 的 make 過程就會設定 tool chain ( 詳細請看 deconfig )所以在這裡不做設定
--External Tool 設定--
1 )  Make config for tmrfc ostest
   
2 )  Run Segger GDB Server
  
其他頁面設定同步驟 1 )
--除錯介面 --
--Debug Configurations 設定--
環境架設好後相當好用, 對 Nuttx 也可以開始深入了解, 最重要的是可以很自由的設定斷點來一窺究竟. 日後加入的程式碼也可以同此操作. 
做完後會發現對於其他的 ARM 平台只要 Jlink 有支援都可以用這一招在 Eclipse 裡做編譯除錯. 管用!!

#04 : USB Composite ( CDC+ MSC )在 Nuttx 的實現

在 defconfig 中的除錯項目設定. 設定 debug symbols 後才能對應到 C code, 否則只能看組譯程式碼.
# # Debug Options # CONFIG_DEBUG=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEBUG_VERBOSE=yCONFIG_DEBUG_USB=y
CDC : Communication Device Class ( VCP : Virtual COM Port)
今天試了一下沒能成功... 希望有高手可以幫忙看一下..感謝, 下面是輸出的 Log
ABCDF
conn_main: Performing architecture-specific intialization
composite_archinitialize: Initializing SDIO slot 0
composite_archinitialize: Bind SDIO to the MMC/SD driver, minor=0
composite_archinitialize: Successfully bound SDIO to the MMC/SD driver
board_cdcclassobject: Initializing USB serial driver
uart_register: Registering /dev/ttyACM0
board_mscclassobject: Configuring with NLUNS=1
board_mscclassobject: MSC handle=10001ed0
board_mscclassobject: Bind LUN=0 to /dev/mmcsd0
Assertion failed at file:usbdev/usbmsc.c line: 422 task: init
sp:         10001a30
stack base: 10001b48
stack size: 000007fc
10001a20: 10001a20 10001a20 10001a40 08009985 00000000 00000000 10001a40 080015f1
10001a40: 10001a30 10000f80 000007fc 10001b48 10001a58 08001665 000001a6 08019cb8
10001a60: 00010000 10000f80 10001a70 0800e7e9 2000045c 10001f64 00001a80 00000040
10001a80: 00000005 2000045c 10001ed0 0f260000 00011a98 08009985 10001aa0 0800e76f
10001aa0: 2000045c 10001f64 00000000 10001c64 00601ab8 10001ed0 00000004 ffffffed
10001ac0: 00001ac8 00000000 10001ad0 08012005 2000045c 10001bd4 10001bc0 00000000
10001ae0: 10001ae8 0800a541 00000000 10001bd4 00000008 2000045c 10001b00 0801270d
10001b00: 00000000 10001bd4 10001bc0 10001bc0 10001b18 0800b131 10001064 00000001
10001b20: 00000000 00000000 10001b30 08002169 00000000 00000000 10000f80 00000001
10001b40: 00000000 00000000 00000000 00000000 00000000 00000000 00000030 80000810
Updated : 2013/07/08
USB composite MSC 部分已經可以正常讀寫小檔案, 寫大檔案會有 CRC failed, 這個問題待解決.
如果要測試的話請使用有加入 Composite MSC 修改之後的版本.
Updated : 2013/07/010
USB Composite CDC/ACM 測試終於成功了!!
under construction

#05 : PWM driver for input capture and output

under construction

#06 : Flight Control