裏PowerPlug

日々感じたことや、ぼやき、PowerPlugプロダクト開発中の備忘録など、とりとめもなく書いてます。
<< May 2012 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 >>

NTPも動く

 前回のmallocが失敗する件は無事解決し、現在は某プロトコルを実装するための下地作りをしております。

その一つが、SNTP(Simple Network Time Protocol)です。
先週まで動作していなかったように見えたのですが、今日その理由が判明しました。

コールバック関数の入り口で、ポインタのNULLチェックを行うのに。

if ( NULL == *pHoge )

とやっていました。

ポインタのチェックをしたいのだから、正しくは、

if ( NULL == pHoge )

ですよね。
何をやってんだか。

SNTPプロトコルそのものは動作していて、このコールバック(デバッグ用のログ出力)だけが出力されていなかったのでした。

最近、こういうアホなミスが多くなってきた気がします…。
初心に戻らねばいかんのか。
ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

STM32とmallocと_sbrk_rとFreeRTOS

 引き続き、STM32のお話。

OSにFreeRTOSを採用し、プロトコルスタックはuIPという構成ですが、
C言語の基本であるmalloc/realloc/freeを使いたく、_sbrk()/_sbrk_r()を実装する必要に迫られ、他のサイト等も参考にして実装しました。

が、リンカスクリプトを追加してヒープを16kB取っているにもかかわらず、64バイトの領域確保すら失敗します。



いろいろ調査した結果、malloc()が呼ばれると_sbrk_r()が呼ばれるのですが、その中で

if (スタックポインタ<(現在のヒープの確保量+メモリの要求量))
{
  エラーだ!
}

という比較をしていて、常にエラー条件になっていることが判明。

はて?
ヒープ領域は正しく設定されているし・・・?

しばらく悩み、「あ、FreeRTOSのタスク…」と思ってググってみたら、まさにドンピシャのサイトを見つけました。

マイコン風雲録と言うサイトを運営していらっしゃるaudin様が、詳しく説明してくださっています。

スタックポインタの位置関係が逆転しちゃうから、常にエラーになるのね…。
てっきり最後尾のuserstackエリアから配分されるもんかと思ってたんですけど、違ったんですね。
勉強不足だ。

これ、参考にさせていただきます。


ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

STM32のSPIに注意されたし


などを参考に、STM32のSPIとENC424J600を接続しています。

当初、書籍に書いてあった手順通り、SPI1を使用して接続に成功しました。
後にSPIが占めているポートを別の目的で使いたくなったので、SPI2を使うことにしたのですが、
「単純に初期化の手順を、SPI2に変更すれば良いだろう」と思っていたのが大間違い。

書籍にあるコードでは、SPI1を初期化する場合、以下のようにしろとのことだったので、

RCC_APB2PeriphClockCmd(SPI1_RCC | SPI1_GPIO_RCC, ENABLE);

SPI2がAPB2ではなくAPB1を使用していることを確認し、単純に、

RCC_APB1PeriphClockCmd(SPI2_RCC | SPI2_GPIO_RCC, ENABLE);

としました。

ところがこれが間違いで、全く動きません。
そこで、改めて定義をよく見ると…。

#define  SPI1_RCC                        RCC_APB2Periph_SPI1
#define  SPI1_GPIO_RCC             RCC_APB2Periph_GPIOA

#define  SPI2_RCC                        RCC_APB1Periph_SPI2
#define  SPI2_GPIO_RCC             RCC_APB2Periph_GPIOB

なんと、SPI1_RCCとSPI1_GPIO_RCCは、両方ともRCC_APB2Periphに属していますが、
SPI2_RCCとSPI2_GPIO_RCCは、それぞれRCC_APB1PeriphとRCC_APB2Periphに属しています。

なので、書くならこう書かなければダメ、ということですね。

RCC_APB1PeriphClockCmd(SPI2_RCC, ENABLE);
RCC_APB2PeriphClockCmd(SPI2_GPIO_RCC, ENABLE);

ちゃんと確認しないとダメですねー。

反省。

ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

STM32でもFreeRTOSを動かしてみた

 久々にblog更新。

最近はPIC18の他、STM32(ARM Cortex-M3)やiPhoneアプリにも手を出しています。

さて。

先日、STM32 + FreeRTOS + uIPという構成でPingが通り、サンプルのWebServerが動作しました。

なかなかいい感じです。
容量的にもスピード的にも文句なしですし、PIC18から全面移行しちゃおうか?(笑)

ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

Microchip USBスタックは扱いが難しい?

FreeRTOSを載せたPIC18J67J50のシステムですが、メインのタスクで

USBDeviceTasks();

を定期的にコール(ポーリング)しています。

ここ1週間ばかりランニングさせていますが、連続して2〜3日動き続けるときもあれば、1日くらいで接続が切れてしまうときもありますね・・・。

つまり、USBGetDeviceState( )関数がCONFIGURED_STATEを返してこなくなってしまうので、延々と送信不可能となってしまうのです。

もう少しUSBDeviceTasks();を短い間隔でコールしてやった方が良いのかな。

別のタスクで時間食ってるのかも。
ちょっと試してみるか。
ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

FreeRTOSをPIC18F87J50/67J50に載せる 〜割り込みプライオリティ変更〜

FreeRTOS(PIC18版)の割り込みは、1箇所のベクタで「タイマ1(タスクスイッチやTickカウント等に使用)」「シリアル受信」「シリアル送信」を判別してそれぞれ振り分けてます。(他のプロセッサの実装はまだ見ていない)

PIC18では、高位のと低位の2段階の割り込みプライオリティをつけられるのですが、FreeRTOSでは割り込みプライオリティモードを使わない設定(従来のPIC16シリーズと同じ=PIC16CXXXX互換モード)を使用しています。

普段はそれでも良いのですが、今回のシステムではタイマ1より優先度の高い割り込みを使用したく、LowベクタとHighベクタを設定して割り込みプライオリティモードを使用できるようにOSを修正することにします。

■まずは、FreeRTOS側の「port.c」

・static関数「prvLowInterrupt」を変更

//#pragma code high_vector=0x08
#pragma interruptlow prvLowInterrupt ← #pragmaはこのように変更
static void prvLowInterrupt( void )
{
 /* Was the interrupt the tick? */
 if( PIR1bits.CCP1IF )
 {
 prvTickISR(); ← インラインasmから通常の関数コールに変更
// _asm
// goto prvTickISR
// _endasm
 }

 /* Was the interrupt a byte being received? */
 if( PIR1bits.RCIF )
 {
 vSerialRxISR(); ← インラインasmから通常の関数コールに変更
// _asm
// goto vSerialRxISR
// _endasm
 }

 /* Was the interrupt the Tx register becoming empty? */
 if( PIR1bits.TXIF )
 {
  if( PIE1bits.TXIE )
  {
   vSerialTxISR(); ← インラインasmから通常の関数コールに変更
// _asm
// goto vSerialTxISR
// _endasm
  }
 }
}

・prvLowInterruptの直下に低優先度の割り込みベクタを追加

#pragma code _LOW_INTERRUPT_VECTOR = 0x001018

void _low_ISR (void)
{
 _asm goto prvLowInterrupt _endasm ← prvLowInterruptへジャンプ
}

#pragma code

・・・

■次に、ユーザー関数側(mainなど)で高位のベクタとレジスタの設定。

//高優先度の割り込み関数
#pragma interrupt HighISR
void HighISR(void)
{
 if( PIRnbits.割り込みフラグ ) ← ここはユーザー環境に合わせて
 {
  タイマ1より優先度の高い割り込み関数名();
 }
}

// スタートアップ
#pragma code _RESET_INTERRUPT_VECTOR = 0x001000
void _reset (void)
{
  _asm goto _startup _endasm
}

//高優先度の割り込みベクタ
#pragma code high_vector=0x01008

void _high_ISR (void)
{
 _asm goto HighISR _endasm ← HighISRへジャンプ
}

#pragma code

・・・


■割り込みプライオリティモードを有効にするために、OSのスケジューリングを有効にする前にレジスタ設定をします。
FreeRTOSのタイマ割り込みはCCP1なので、以下のように設定すればOKです。
これで、CCP1の割り込みプライオリティが「低」に設定されます。
(ちなみにデフォルトは「高」となっていますので気をつけて下さい)

IPR1bits.CCP1IP = 0;

最後に、割り込み優先順位を有効するためのレジスタを設定します。
RCONレジスタのIPENを1にすることで、割り込みプライオリティモードが設定されます。
(IPEN=0で、PIC16CXXXX互換モード)

RCONbits.IPEN = 1;


ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

FreeRTOSをPIC18F87J50/67J50に載せる 〜コンテキストスイッチ〜

FreeRTOSConfig.hで定義されている「configUSE_PREEMPTION」
この値が1になっていると、タイマ1の割り込みが入る度に優先度の高いタスクにコンテキストスイッチングを行ないます。

どうも当方のシステムではこれが良くないらしく、しばらく動かしていると止まってしまいます。

「configUSE_PREEMPTION」を0にして、必要な箇所で「taskYIELD()※」をコールするようにしたら、格段に安定するようになりました。

まあ、割り込みの中で強制的にコンテキストの切り替えを行なうわけですから、何かあってもおかしくはないですよね・・・。

というわけで、「configUSE_PREEMPTION」は0で使用することにします。

※強制的にコンテキストスイッチングを行なうマクロ


ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

FreeRTOSをPIC18F87J50/67J50に載せる その3

FreeRTOS/PIC18用ですが、キュー制御関数「xQueueReceive」のウエイト時間に「0」を指定すると、頻繁にハングアップやリセットを起こします。

STM32でFreeRTOSを動かしている方のページを見ると「0」を指定しても問題なさそうなので、PIC18あるいは私の環境特有の問題かもしれません。

仕方が無いので、以下のように回避。

// キューにデータが格納されているか確認
if ( 0 < uxQueueMessagesWaiting( xHogeQueue ) )
{
 xQueueReceive( xHogeQueue, (void*)buffer, 少し待ち );
}

PICだけの問題かもしれないけど、腫れ物に触るようなOSだ(笑)
ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

FreeRTOSをPIC18F87J50/67J50に載せる その2

FreeRTOSをPIC18F67J50のシステムの載せて動かし始めてからトラブルが続出しています。
まあ、ほぼ全部がメモリ関係なのですが。

タスクに乏しいRAMを割り振ってスタック領域を確保しているので、

・printf系の関数は使えない(使えない事もないが、スタックオーバーフローを起こしてすぐハングアップするので使わない方が無難)

・関数のネストは極力浅く

・タスク自体のローカル変数はなるべく使わず

といったところでしょうか。

自前でsprintfもどきの関数を久々に書きました・・・。
なんか懐かしい(笑)
ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)

FreeRTOSをPIC18F87J50/67J50に載せる

巷で話題のFreeRTOS
商用利用も可能でPIC18シリーズにも対応しているということで、PIC18F87J50/67J50を使ったシステムに採用してみようかと思い、ビルドしてみました。

んが。

CPU依存部、「port.c」の「prvSetupTimerInterrupt」でエラーが発生してビルドが止まってしまいました。

調査してみると、この関数内でコールしている「OpenTimer1」に与える定数「T1_CCP1_T3_CCP2」がPIC18F87J50/67J50では定義されていないのでした。

そこでOpenTimer1の実装を調べてみると、「T1_CCP1_T3_CCP2」の定数を見てCCPを操作しているわけではなく、T1CONレジスタしか操作していないので、以下のようにすれば良いことが判明。

元のFreeRTOSのタイマ1スタート関数の実装:
 OpenTimer1( T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_1 & T1_CCP1_T3_CCP2 );

PIC18F87J50/67J50用に変更したタイマ1スタート関数の実装
 OpenTimer1( T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_1 & T1_OSC1EN_OFF );


これで再ビルドしたらめでたくNo Error。

OSを載せようとしているシステムはMicrochip製ブートローダが書き込んであるので、割り込みベクタ「prvLowInterrupt」を0x08→0x1008へ変更する。

簡単なテスト用タスクを書いてブートローダ経由で書き込んでみたところ、見事に動作しました。
これでブートローダ対応FreeRTOSの載ったシステムになりましたね。v(^^)

後はタスクや関数を増やしていった時に、どこまでメモリが持つかが勝負ですね(笑)
ソフトウェア/電子工作 | permalink | comments(0) | trackbacks(0)