Cortex-M3ず亀換する䟡倀は䜕ですか

ARM Cortex-M3は、おそらく今日の組み蟌みシステムで最も人気のある32ビットプロセッサコアです。 それに基づくマむクロコントロヌラヌは、倚くのメヌカヌによっお補造されおいたす。 この理由は、普遍的でバランスのずれたアヌキテクチャであり、その結果、既補の゜フトりェアおよびハヌドりェア゜リュヌションのベヌスが垞に成長しおいたす。



䞀般的に、Scord Cortex-M3はたったくそうではありたせんが、今日、Cortex-M4F-最愛のプロセッサコアの拡匵バヌゞョンを詳现に怜蚎するこずを提案したす。 Cortex-M3に基づいたマむクロコントロヌラヌからCortex-M4Fに基づいたクリスタルにプロゞェクトを転送するのは非垞に簡単ですが、倚くのタスクにずっおこの移行は努力する䟡倀がありたす。



カッタヌの䞋には、最新のCortexの簡単な抂芁、Cortex-M4FずCortex-M3を区別するブロックずコマンドの詳现な説明、および実際のタスクでのプロセッサコアの比范がありたす。異なるコアを持぀マむクロコントロヌラのランプフリッカヌ呚波数を枬定したす。







レビュヌ郚




連続した䞖代のARMプロセッサコアが互いにどのように成功したかに぀いお、膚倧な数の蚘事ずレビュヌが曞かれおいたす。 りィキペディアにあるすべおをペむントする理由はありたせんが、基本的な事実を思い出させたす。



䌚瀟ARM Ltd. RISCアヌキテクチャを備えたマむクロプロセッサおよびマむクロコントロヌラコアを開発し、適切な技術を䜿甚しお氎晶の補造ラむセンスを電子郚品メヌカヌに販売しおいたす。 このような補造業者は䞖界䞭に䜕十、䜕癟ずあり、その䞭には囜内䌁業がありたす。

最新のARMコアは、Cortexずいう名前で統䞀されおいたす。

ちなみに、「皮質」ずいう蚀葉は「倧脳皮質」ず翻蚳されおいたす。これは、臓噚の協調䜜業、思考、および高次の神経掻動に関䞎する構造です。 私の意芋では、玠晎らしい名前です。



そのため、ARM Cortexプロセッサコアは3぀の䞻芁なグルヌプに分かれおいたす。





最埌のグルヌプを考えお、Cortex-M3 / Cortex-M4Fのペアに埐々に近づきたす。 合蚈で、2015幎末に、Cortex-M0、-M0 +、-M1、-M3、-M4、-M7の6぀のプロセッサコアが発衚されたした。

-M1はFPGA関連のアプリケヌションでのみ蚭蚈および䜿甚されるため、Cortex-M1はこのリストからしばしば「陀倖」されたす。 残りのコアには、このような特殊なアプリケヌション分野がなく、パフォヌマンスが異なりたす-最も単玔な-M0から高性胜の-M7です。







Cortex-M0ず比范しお、Cortex-M0 +には、MPUメモリ保護ナニット、デバッグプログラム甚のマむクロトレヌスバッファヌが远加で装備されおいたす。たた、呚蟺ブロックず入出力ラむンぞの3ステヌゞの単玔化されたアクセスの代わりに、2ステヌゞパむプラむンがありたす。



Cortex-M0およびCortex-M0 +にはシングルバスフォンノむマンアヌキテクチャがあり、Cortex-M3コアはすでにハヌバヌドです。 Cortex-M3は、ラむンの「若い」代衚ずはたったく異なり、さらに倚くの機胜を備えおいたす。



Cortex-M4はたったく同じアヌキテクチャで構築されおおり、「構造的に」Cortex-M3ず違いはありたせん。 違いはサポヌトされおいるコマンドシステムにありたすが、それに぀いおは埌で詳しく説明したす。 Cortex-M4Fは、FPU浮動小数点ナニットが存圚する点で-M4ず異なりたす。



Cortex-M7アヌキテクチャは比范的最近のものであり、Cortex-M3 / M4ずCortex-M0が異なるのず同様に、Cortex-M3 / M4ずは異なりたす。 6ステヌゞのスヌパヌスカラヌパむプラむン、デヌタず呜什甚の個別のキャッシュ、構成可胜なTCMメモリ、およびこのコアの他の特城的な機胜は、最高のパフォヌマンスを実珟するために「シャヌプ」になっおいたす。 実際、Cortex-M7に基づいたコントロヌラの機胜は、組み蟌みプロセッサグルヌプの他のコントロヌラよりもCortex-A5および-R5ず比范される可胜性が高くなりたす。 テクノロゞヌアプリケヌションの境界はあいたいになり続けおいたす。



Cortex-Mコアの機胜はたったく異なりたすが、各コアのコマンドセットには、䞋䜍のコアでサポヌトされおいるすべおのコマンドが含たれおいたす。 これにより、異なるコアに基づいた゜フトりェア互換マむクロコントロヌラヌを開発する機䌚が提䟛されたす。これは、ほずんどのマむクロコントロヌラヌメヌカヌが行っおいるこずです。







コアCortex-M0およびCortex-M0 +は、同じコマンドシステムです。 Cortex-M3呜什セットには、すべおのCortex-M0コマンドず玄100の远加呜什が含たれおいたす。 Cortex-M4およびCortex-M7プロセッサコアには、同じ呜什セットがありたす。Cortex-M3呜什セットず、いわゆるDSP呜什です。 Cortex-M4Fコアは、Cortex-M4 / -M7セットに加えお、浮動小数点蚈算呜什をサポヌトし、Cortex-M7F呜什セットには、倍粟床浮動小数点挔算甚の14個の呜什が含たれおいたす。



理論郚




そのため、人気のあるCortex-M3プロセッサコアの最も近い「隣接」は、DSP呜什のサポヌトが远加されたCortex-M4ず、FPUを远加しお察応するコマンドをサポヌトするCortex-M4Fです。 DSPおよびFPUコマンドを怜蚎しおください。



DSP呜什



略語DSPは、ほずんどの堎合、デゞタルシグナルプロセッサずしお解読されたす。 デゞタル信号凊理のタスク甚に蚭蚈された完党に独立した独立したコントロヌラヌたたはコプロセッサヌ。 特殊なDSPチップずDSP呜什のセットを混同しないでください。 DSPコマンドProcess たたはの代わりにデゞタル信号凊理を衚すは、倚数のARMプロセッサコアでサポヌトされおいる䞀連のコマンドであり、デゞタル信号凊理の䞀般的な操䜜に察応しおいたす。



このような操䜜の最初のグルヌプは、 环積乗算 Single-cycle Multiply Accumulateたたは単にMACです。

最小の堎合环算を䌎う乗算は、匏S = S + A x Bで蚘述されたす。察応するコマンドは、2぀のレゞスタず环算噚での結果の合蚈および関連する挔算ずの乗算を蚘述したす。



16ビットおよび32ビット倉数の操䜜が提䟛され、倚くの䞀般的なデゞタル信号凊理アルゎリズムで重芁な圹割を果たしたす。 たずえば、 FIRフィルタヌ これは叀兞的な、たずえばほが平凡なは、环算を䌎う乗算のシヌケンスです。぀たり、その速床は、环算を䌎う乗算の速床に盎接䟝存したす。

Cortex-M4Fコアを備えたマむクロコントロヌラヌのすべおのMAC呜什は、単䞀マシンサむクルで実行されたす。



DSP呜什の2番目のグルヌプは、SIMDSingle Instruction Multiple Data操䜜です。これにより、䞊列蚈算によるデヌタ凊理の最適化が可胜になりたす。 独立倉数のペアは、より倧きな次元の単䞀のレゞスタにペアごずに配眮され、算術挔算は「倧きな」レゞスタですでに実行されおいたす。

たずえば、 SADD16コマンドでは、16ビットの笊号付き数倀の2぀のペアを同時に加算し、結果を第1オペランドを栌玍するレゞスタに曞き蟌みたす。



SADD16 R1, R0
      
      









汎甚レゞスタの容量は32ビットであるため、各レゞスタには2぀の16ビット倉数ハヌフワヌドだけでなく、最倧4぀の8ビット倉数バむトを含めるこずができたす。 これで、SADD8コマンドが必芁な理由を簡単に理解できたす。



次に、より耇雑な操䜜を瀺したす。䞊䜍のハヌフワヌドを乗算し、䞋䜍のハヌフワヌドを乗算し、64ビットの环積でピヌスを合蚈したす。 SMLALDコマンドはこれらすべおのアクションを蚘述し、単䞀マシンサむクルでCortex-M4によっお実行されたす。 SMLALDは、他の倚くのチヌムず同様に、SIMDに基づいお乗算ず环積およびデヌタ凊理を組み合わせたす。



 SMLALD R6, R8, R5, R1
      
      









単玔なSIMDコマンド笊号付きおよび笊号なしの8ビットおよび16ビットの加算および枛算などずSMLALDなどの耇雑なコマンドの䞡方が1マシンサむクルで実行されたす。



DSP呜什の次のグルヌプは、飜和呜什です。 これらはカットオフ操䜜ずも呌ばれ、オヌバヌフロヌ保護を衚したす。 暙準コマンドを䜿甚する堎合、結果を栌玍するレゞスタは、オヌバヌフロヌ時に最初から「リロヌド」され、飜和を提䟛するコマンドはオヌバヌフロヌ時に、蚱容最倧容量で結果を修正したす。 これにより、プログラマがオヌバヌフロヌフラグを凊理する必芁がなくなりたす。







Cortex-M4プロセッサコアの呜什には、「通垞の」算術挔算ず飜和を䌎う同じ挔算の䞡方がありたす。 埌者の䜿甚は、速床のために蚈算の粟床を犠牲にする可胜性のある問題で特に需芁がありたす。 DSPにはこのようなタスクが倚数ありたす。



FPU呜什



浮動小数点蚈算たたは任意のポむントのハヌドりェアサポヌトは、Cortex-M4FコアずCortex-Mラむンの叀い代衚の機胜です。



浮動小数点蚈算コマンドを䜿甚するず、実数に察しお最倧のパフォヌマンスで操䜜を実行できたす。 䞀般に、珟圚、実数の衚珟には固定小数点ず浮動小数点の2぀の圢匏が䜿甚されおいたす。 前者の堎合、敎数郚ず小数郚を蚘録するためのビット数は固定されおおり、蚈算は敎数の挔算に削枛されたす。埌者の堎合、数は笊号ビット、次数ず仮数郚の組み合わせずしお衚されたす。



-1 s * m×b e 、

ここで、sは笊号、b-base、eは次数、mは仮数です。



浮動小数点圢匏の倉数の倀の範囲がはるかに広いため、信号を凊理する堎合は、浮動小数点圢匏を䜿甚するこずをお勧めしたす。 FPU操䜜を䜿甚するず、開発者がビット深床を監芖する必芁もなくなりたす。 単粟床浮動小数点数圢匏はIEEE 754暙準で蚘述されおおり、この衚珟はCortex-M4Fコアを備えたマむクロコントロヌラヌで䜿甚されたす。 蚱容倀の範囲は10 –38 ... 10 38 であり、10進数ぞの近䌌倉換が行われたす。







ずころで、Cortex-M7Fは、倍粟床浮動小数点数圢匏に察しお同じ原理を䜿甚したすが、32ビット衚珟の代わりに64ビット衚珟を䜿甚したす。 桁は11ビット、仮数52になりたす。



浮動小数点圢匏がHabréで曞かれた耇数回䜿甚される理由ず理由に぀いお ここでは、優れた蚘事など。 おそらく私はこれ以䞊曞くこずができないので、先に進みたしょう。



組み立おられたDSPおよびFPUコマンドのリスト



Cortex-M4を䜿甚したデヌタ凊理の量を理解するために、芏暡の感芚を぀かむために、DSPおよびFPU呜什の完党なリストを孊ぶこずができたす。 これらのテヌブルの実甚的な䟡倀に぀いおは倧きな疑問がありたすが、興味深いものです。

すべおのDSPおよびほずんどのFPU呜什は、単䞀マシンサむクルで実行されたす。



Cortex-M4カヌネルDSP呜什
チヌム 運営
PKHTB、PKHBT 必芁に応じお、「受信」レゞスタの内容をシフトしお、あるレゞスタから別のレゞスタにハヌフワヌドを曞き換えたす
QADD 飜和した笊号付き加算
QADD16 2぀のオペランドの察応するハヌフワヌドの笊号加算飜和あり
QADD8 2぀のオペランドの察応するバむトの笊号付き加算飜和あり
QASX 第2オペランドの䞋䜍ハヌフワヌドず第1オペランドの䞊䜍ハヌフワヌドの笊号付き加算、第1オペランドの䞋䜍ハヌフワヌドからの第2オペランドの最䞊䜍ハヌフワヌドの笊号付き枛算飜和あり

QDADD 第2オペランドを2倍にし、結果を第1オペランドず加算する笊号付き、飜和
QDSUB 第2オペランドを2倍にし、第1オペランドから結果を枛算笊号付き、飜和あり
QSAX 第1オペランドの最䞊䜍ハヌフワヌドからの第2オペランドの副ハヌフワヌドの有意な枛算+第1オペランドの副ハヌフワヌドず第2オペランドの䞊䜍ハヌフワヌドの有意な加算飜和あり
QSUB 笊号付き枛算飜和あり
QSUB16 2぀のオペランドの察応するハヌフワヌドの有意な枛算飜和あり
QSUB8 2぀のオペランドの察応するバむトの有意な枛算飜和あり
SADD16 2぀のオペランドの察応するハヌフワヌドの倧幅な远加
SADD8 2぀のオペランドの察応するバむトの笊号付き加算
サックス 第1オペランドの䞊䜍ハヌフワヌドず第2オペランドの䞋䜍ハヌフワヌドの笊号付き加算、結果の䞊䜍ハヌフワヌドのレコヌド、結果の䞋䜍ハヌフワヌドの゚ントリを持぀第1オペランドの䞊䜍ハヌフワヌドからの第2オペランドの䞋䜍ハヌフワヌドの笊号付き枛算

SEL GE [30]のビットに応じたオペランドからのバむトの遞択算術挔算の実行時に「以䞊」などのさたざたな条件が蚭定されたずきに蚭定される「フラグ」
SHADD16 オペランドの察応するハヌフワヌドの笊号加算、2぀の結果の右ぞの1ビットのシフト
SHADD8 オペランドの察応するバむトの笊号付き加算、4぀の結果を右に1ビットシフト
SHASX 第1オペランドの最䞊䜍ハヌフワヌドず第2オペランドの䞋䜍ハヌフワヌドの笊号付き加算、指定されたレゞスタの最䞊䜍ハヌフワヌドに結果を1ビット右シフトで曞き蟌み、第1オペランドの䞋䜍ハヌフワヌドから第2オペランドの最䞊䜍ハヌフワヌドを倧幅に枛算し、右シフト1で指定レゞスタの䞋䜍ハヌフワヌドに結果を蚘録する少し
SHSAX 第1オペランドの最䞊䜍ハヌフワヌドから第2オペランドの䞋䜍ハヌフワヌドを有意に枛算し、指定したレゞスタの䞋䜍ハヌフワヌドに結果を1ビット右シフトしお曞き蟌み、第2オペランドの䞊䜍ハヌフワヌドず第1オペランドの䞋䜍ハヌフワヌドを有意に加算し、指定したレゞスタの䞊䜍ハヌフワヌドに右シフト1で結果を曞き蟌む少し
SHSUB16 第1オペランドの察応するハヌフワヌドから第2オペランドの䞊䜍および䞋䜍ハヌフワヌドを倧幅に枛算し、結果を1ビット右にシフトしたす。
SHSUB8 第1オペランドの察応するバむトから第2オペランドの䞊䜍および䞋䜍バむトを倧幅に枛算し、結果を1ビット右にシフトしたす
SMLABB、SMLABT、SMLATB、SMLATT 2぀のオペランドの䞊䜍たたは䞋䜍ハヌフワヌドず32ビット环積の乗算
SMLAD、SMLADX 2぀のオペランドのハヌフワヌドのペアワむズ乗算、32ビット环積で2぀の積を合蚈
SMLALBB、SMLALBT、SMLALTB、SMLALTT 2぀のオペランド高たたは䜎のシンボリックハヌフワヌドず64ビットの环積および64ビットの結果の乗算
SMLALD、SMLALDX 第1オペランドから取埗した2バむトず第2オペランドから取埗した2バむトのペアワむズ乗算、受信した2぀の積の合蚈ず64ビットの环積および64ビットの結果
SMLAWB、SMLAWT 第1オペランドの䞊䜍ハヌフワヌドたたは䞋䜍ハヌフワヌドず32ビット环積の第2オペランドを乗算するず、48ビットの結果の最初の32ビットが結果レゞスタに曞き蟌たれたす
SMLSD 2぀のオペランドの䞊䜍ハヌフワヌドず32ビット环積の2぀のオペランドの䞋䜍ハヌフワヌドの積の枛算
SMLSLD 2぀のオペランドの䞊䜍ハヌフワヌドず64ビット环算の2぀のオペランドの䞋䜍ハヌフワヌドの積の枛算
SMMLA 2぀のオペランドず32ビット环算の乗算積の䞊䜍32ビットのみが取埗されたす
SMMLS、SMMLR 2぀のオペランドの乗算、指定されたレゞスタヌからの結果の枛算積の䞊䜍32ビットのみが取埗されたす
SMMUL、SMMULR オペランドの乗算結果-䞊䜍32ビット補品
SMUAD 2぀のオペランドの䞊䜍ハヌフワヌドの乗算、2぀のオペランドの䞋䜍ハヌフワヌドの乗算、積の加算
SMULBB、SMULBT SMULTB、SMULTT 2぀のオペランドの䞊䜍たたは䞋䜍ハヌフワヌドの乗算
SMULWB、SMULWT 第1オペランドに第2オペランドの䞊䜍たたは䞋䜍ハヌフワヌドを乗算するず、48ビットの結果の最初の32ビットが結果レゞスタに曞き蟌たれたす
SMUSD、SMUSDX 2぀のオペランドの䞊䜍ハヌフワヌドの乗算、2぀のオペランドの䞋䜍ハヌフワヌドの乗算、2番目のオペランドから最初の積の枛算
SSAT16 指定された倀ぞのハヌフワヌドの笊号付き飜和
SSAX 結果の䞋䜍ハヌフワヌドに曞き蟌みを行う第1オペランドの最䞊䜍ハヌフワヌドから第2オペランドの䞋䜍ハヌフワヌドを有意に枛算し、結果の䞊䜍ハヌフワヌドに曞き蟌みを行う第1オペランドの䞊䜍ハヌフワヌドず第2オペランドの䞋䜍ハヌフワヌドを加算する
SSUB16 2぀のオペランドの察応するハヌフワヌドの有意な枛算
SSUB8 2぀のオペランドの察応するバむトの有意な枛算
SXTAB レゞスタからビット[70]を抜出し、それらを笊号を考慮しお32ビットワヌドに倉換し、結果をワヌドたたはハヌフワヌドに远加したす
SXTAB16 レゞスタからビット[70]および[23:16]を抜出し、笊号を考慮しおそれらをハヌフワヌドに倉換し、結果をワヌドたたはハヌフワヌドに远加する
SXTAH レゞスタからビット[150]を抜出し、それらを笊号を考慮しお32ビットワヌドに倉換し、結果をワヌドたたはハヌフワヌドに远加したす
SXTB16 笊号を考慮しお2バむトを2぀のハヌフワヌドに倉換し、結果をワヌドたたはハヌフワヌドに远加する
UADD16 2぀のオペランドの察応するハヌフワヌドの笊号なし加算
UADD8 2぀のオペランドの察応するバむトの笊号なし加算
USAX 結果の䞋䜍ハヌフワヌドに結果を曞き蟌むこずによる、第1オペランドの䞋䜍ハヌフワヌドず第2オペランドの䞊䜍ハヌフワヌドの加算、結果の䞊䜍ハヌフワヌドの゚ントリを持぀第1オペランドの䞊䜍ハヌフワヌドからの第2オペランドの䞋䜍ハヌフワヌドの笊号なし枛算
UHADD16 2぀のオペランドの察応するハヌフワヌドの笊号なし加算ず結果の1ビット右ぞのシフト
UHADD8 2぀のオペランドの察応するバむトの笊号なし加算ず結果の右ぞの1ビットのシフト
りハクス 加算結果を1ビット右にシフトしお、第1オペランドの最䞊䜍ハヌフワヌドず第2オペランドの䞋䜍ハヌフワヌドを笊号なし加算し、結果を最䞊䜍ハヌフワヌドに曞き蟌む、第1オペランドの䞋䜍ハヌフワヌドから第2オペランドの最䞊䜍ハヌフワヌドを笊号なし枛算で右に1ビット枛算し、䞋䜍ハヌフワヌドに曞き蟌む結果
UHSax 第1オペランドの最䞊䜍ハヌフワヌドから第2オペランドの最埌のハヌフワヌドを笊号なし枛算し、枛算結果を1ビット右にシフトし、結果を最䞊䜍ハヌフワヌドに曞き蟌み、第1オペランドの䞋䜍ハヌフワヌドず第2オペランドの䞊䜍ハヌフワヌドの笊号なし加算を1ビット右に加算し、䞋䜍ハヌフワヌドに曞き蟌む結果
UHSUB16 2぀のオペランドの察応するハヌフワヌドの笊号なし枛算、結果を右に1ビットシフト
UHSUB8 2぀のオペランドの察応するバむトの笊号なし枛算。結果を1ビット右にシフトしたす
りマヌル ダブル32ビット环積ず64ビット結果の笊号なし乗算
UQADD16 16ビット倉数の笊号なし加算飜和あり
UQADD8 8ビット倉数の笊号なし加算飜和あり
UQASX 第1オペランドの最䞊䜍ハヌフワヌドからの第2オペランドの最小ハヌフワヌドの笊号なし枛算、第1オペランドの最小ハヌフワヌドず第2オペランドの最䞊䜍ハヌフワヌドの笊号なし加算飜和あり
UQSAX 第1オペランドの最䞊䜍ハヌフワヌドからの第2オペランドの最小ハヌフワヌドの笊号なし枛算、第1オペランドの最小ハヌフワヌドず第2オペランドの最䞊䜍ハヌフワヌドの笊号なし加算飜和あり
UQSUB16 2぀のオペランドの察応するハヌフワヌドの笊号なし枛算飜和あり
UQSUB8 2぀のオペランドの察応するバむトの笊号なし枛算飜和あり
USAD8 2぀のオペランドの察応するバむトの笊号なし枛算、絶察差の加算
USADA8 2぀のオペランドの察応するバむトの笊号なし枛算、絶察差の加算、挔算結果ずバッテリヌの内容の加算
USAT16 指定された倀ぞのハヌフワヌドの笊号なし飜和
Uasx 結果の䞋䜍ハヌフワヌドぞの曞き蟌みを䌎う第1オペランドの最䞋䜍ハヌフワヌドからの第2オペランドの最䞊䜍ハヌフワヌドの笊号なし枛算、結果の䞊䜍ハヌフワヌドぞの結果の曞き蟌みを䌎う第1オペランドの最䞊䜍ハヌフワヌドず第2オペランドの䞋䜍ハヌフワヌドの加算
USUB16 2぀のオペランドの察応するハヌフワヌドの笊号なし枛算
USUB8 2぀のオペランドの察応するバむトの笊号なし枛算
UXTAB レゞスタからビット[70]を抜出し、笊号に関係なく32ビットワヌドに倉換し、結果をワヌドたたはハヌフワヌドに远加したす
UXTAB16 レゞスタからビット[70]および[23:16]を抜出し、それらを笊号に関係なくハヌフワヌドに倉換し、結果をワヌドたたはハヌフワヌドに远加する
UXTAH レゞスタからビット[150]を抜出し、それらを笊号に関係なく32ビットワヌドに倉換し、結果をワヌドたたはハヌフワヌドに远加したす
UXTB16 笊号を考慮せずに2バむトを2぀のハヌフワヌドに倉換し、結果をワヌドたたはハヌフワヌドに远加する








Cortex-M4FカヌネルFPU呜什






チヌム 運営
VABS.F32 オペランドの絶察倀を取埗する
VADD.F32 オペランドの远加
VCMP.F32 2぀のオペランドたたはオペランドずれロの比范
VCMPE.F32 誀ったオペランドNaNをチェックしお、2぀のオペランドたたはオペランドずれロを比范する
VCVT.S32.F32 デヌタ型間の倉換浮動小数点/敎数
VCVT.S16.F32 デヌタ型間の倉換浮動小数点/固定小数点
VCVTR.S32.F32 䞞めを䜿甚したデヌタ型浮動小数点/敎数間の倉換
VCVT <B | H> .F32.F16 デヌタ型間の倉換浮動小数点付きのハヌフワヌド-「半粟床数」/浮動小数点でもありたす
VCVTT <B | T> .F32.F16 デヌタ型間の倉換浮動小数点/ハヌフワヌド浮動小数点
VDIV.F32 オペランドの分割
VFMA.F32 2぀の倉数の乗算、乗算の結果を指定されたレゞスタの内容に远加
VFNMA.F32 第1オペランドを反転し、結果に第2オペランドを乗算し、積ず指定されたレゞスタの反転倀を加算したす
VFMS.F32 第1オペランドを反転し、結果に第2オペランドを乗算し、指定されたレゞスタの積ず倀を加算したす
VFNMS.F32 2぀のオペランドの乗算、積の加算、指定されたレゞスタからの反転倀
VLDM.F <32 | 64> プログラムメモリからいく぀かの指定されたレゞスタの内容を抜出する
VLDR.F <32 | 64> 指定されたレゞスタの内容をプログラムメモリから抜出する
VLMA.F32 环積乗算
VLMS.F32 指定されたレゞスタから2぀のオペランドの積を枛算したす
Vmov 「暙準」ARMレゞスタずFPSCR浮動小数点ステヌタスおよび制埡レゞスタレゞスタ間のデヌタ転送、浮動小数点圢匏レゞスタFPUレゞスタ間のデヌタ転送、FPUレゞスタぞの定数の曞き蟌みなど。
VMOV、VMRS、VMSR 「暙準」ARMレゞスタずFPSCR浮動小数点ステヌタスおよび制埡レゞスタ間のデヌタ転送
VMUL.F32 オペランドの乗算
VNEG.F32 反転
VNMLA.F32 2぀のオペランドの乗算、結果のむンベントリ、指定されたレゞスタからの反転積ず反転倀の远加
VNMLS.F32 指定されたレゞスタの2぀のオペランド、積、および反転倀の乗算
ノンムル 2぀のオペランドの乗算、結果のむンベントリ
VPOP ただポップ
VPUSH 抌す
VSQRT.F32 平方根抜出
Vstm 指定された耇数のレゞスタの内容をプログラムメモリに保存する
VSTR.F <32 | 64> 指定されたレゞスタの内容をプログラムメモリに保存する
VSUB.F <32 | 64> オペランドの枛算






ただし、実際には、カヌネル呜什自䜓はあたり䜿甚されたせん。 通垞、開発時には、コアおよびクリスタルメヌカヌのコントロヌラヌおよびラむブラリラむブラリのドキュメントを凊理するだけで十分です。 特に、Cortexコアには、異なるメヌカヌのCortex-Mプロセッサに䜿甚されるCMSISラむブラリのARMセットがありたす。 CMSISにはCMSIS-DSPラむブラリも含たれおいたす。







実甚的な郚分






原則ずしお、Cortex-M3ずCortex-M4Fコアの比范は矎しいグラフで終わりたす-DSPタむプの䞀般的な操䜜FIRフィルタヌ、FFT、マトリックス蚈算、PID -レギュレヌタなど。 䜿甚するコントロヌラヌからの指瀺なしで、蚈算および枬定手順。



しかし、朮ず通垞の掗剀を比范するのではなく、実際のハヌドりェアず゜フトりェアのプラットフォヌムを䜿甚したす。



この時点で、Cortex-M4F数孊装眮が関連するタスクに぀いお少し泚意をそらし、熟考するこずは理にかなっおいたす。 Cortex-M4コアのパフォヌマンスだけではストリヌミングデヌタやマルチメディアを扱うのに十分ではないこずは明らかです。デヌタ管理および凊理システムに぀いお詳しく説明しおいたす。

たずえば、䞀郚のテレメトリデヌタが収集されおいたす。 , , «» . — , .

. - -. bluetooth ? もちろん違いたす。 .

. , « »? ! , .




EFM32 Wonder Gecko SiLabs. . -.



EFM32WG — Cortex-M4F. EFM32, . Cortex-M3 Cortex-M4F.



:



EFM32WG-STK3800 — Cortex-M4F

EFM32GG-STK3700 — Cortex-M3

.







Simplicity Studio. SiLabs- , , , , Silabs. — IDE, energy profiler, user guide .





. , , , 0,5 : 512 . ProcessFFT().

, . .







Simplicity Studio, Simplicity IDE, .



プログラムリスト
, — , Simplicity IDE, IAR, Keil .



 /***************************************************************************//** * @file lightsensefft.c * @brief FFT transform example * @details * Use ADC in order to capture and analyse input from the * light sensor on the STK. Runs floating point FFT algorithm from the CMSIS * DSP Library, and estimate the frequency of the most luminous light source * using sinc interpolation. The main point with this example is to show the * use of the CMSIS DSP library and the floating point capability of the CPU. * * @par Usage * Connect the light sensor output to the ADC input by shorting pins * 15 and 14 on the EXP_HEADER of the STK. * Direct various light sources to the light sensor. Expect no specific * frequency from daylight or from a flashlight. Mains powered incandescent * bulbs should give twice the mains frequency. Using another STK running the * "blink" example modified to various blink rates is an excellent signal * source. The frequency bandwidth is approximately 10-500 Hz. * The frequency shows in the 4 digit numerical display upper right on * the LCD. The LCD also displays the number of CPU cycles used to do * the FFT transform. * * @author Silicon Labs * @version 1.04 ******************************************************************************* * @section License * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> ******************************************************************************* * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no * obligation to support this Software. Silicon Labs is providing the * Software "AS IS", with no express or implied warranties of any kind, * including, but not limited to, any implied warranties of merchantability * or fitness for any particular purpose or warranties against infringement * of any proprietary rights of a third party. * * Silicon Labs will not be liable for any consequential, incidental, or * special damages, or any other relief, or for any claim by any third party, * arising from your use of this Software. * ******************************************************************************/ #include "em_common.h" #include "em_emu.h" #include "em_cmu.h" #include "em_chip.h" #include "em_adc.h" #include "em_gpio.h" #include "em_rtc.h" #include "em_acmp.h" #include "em_lesense.h" #include "segmentlcd.h" #include "arm_math.h" #include "math.h" /** * Number of samples processed at a time. This number has to be equal to one * of the accepted input sizes of the rfft transform of the CMSIS DSP library. * Increasing it gives better resolution in the frequency, but also a longer * sampling time. */ #define BUFFER_SAMPLES 512 /** (Approximate) sample rate used for sampling data. */ #define SAMPLE_RATE (1024) /** The GPIO pin used to power the light sensor. */ #define EXCITE_PIN gpioPortD,6 /* Default configuration for alternate excitation channel. */ #define LESENSE_LIGHTSENSE_ALTEX_DIS_CH_CONF \ { \ false, /* Alternate excitation enabled.*/ \ lesenseAltExPinIdleDis, /* Alternate excitation pin is disabled in idle. */ \ false /* Excite only for corresponding channel. */ \ } /* ACMP */ #define ACMP_NEG_REF acmpChannelVDD #define ACMP_THRESHOLD 0x38 /* Reference value for the lightsensor. * Value works well in office light * conditions. Might need adjustment * for other conditions. */ /* LESENSE Pin config */ #define LIGHTSENSE_CH 6 #define LIGHTSENSE_EXCITE_PORT gpioPortD #define LIGHTSENSE_EXCITE_PIN 6 #define LIGHTSENSE_SENSOR_PORT gpioPortC #define LIGHTSENSE_SENSOR_PIN 6 #define LCSENSE_SCAN_FREQ 5 #define LIGHTSENSE_INTERRUPT LESENSE_IF_CH6 /** Buffer of uint16_t sample values ready to be FFT-ed. */ static uint16_t lightToFFTBuffer[BUFFER_SAMPLES]; /** Buffer of float samples ready for FFT. */ static float32_t floatBuf[BUFFER_SAMPLES]; /** Complex (interleaved) output from FFT. */ static float32_t fftOutputComplex[BUFFER_SAMPLES * 2]; /** Magnitude of complex numbers in FFT output. */ static float32_t fftOutputMag[BUFFER_SAMPLES]; /** Flag used to indicate whether data is ready for processing */ static volatile bool dataReadyForFFT; /** Indicate whether we are currently processing data through FFT */ static volatile bool processingFFT; /** Instance structures for float32_t RFFT */ static arm_rfft_instance_f32 rfft_instance; /** Instance structure for float32_t CFFT used by the RFFT */ static arm_cfft_radix4_instance_f32 cfft_instance; /**************************************************************************//** * Interrupt handlers prototypes *****************************************************************************/ void LESENSE_IRQHandler(void); /**************************************************************************//** * Functions prototypes *****************************************************************************/ void setupCMU(void); void setupACMP(void); void setupLESENSE(void); /**************************************************************************//** * @brief LESENSE_IRQHandler * Interrupt Service Routine for LESENSE Interrupt Line *****************************************************************************/ void LESENSE_IRQHandler(void) { /* Clear interrupt flag */ LESENSE_IntClear(LIGHTSENSE_INTERRUPT); } /***************************************************************************//** * @brief Enables LFACLK and selects osc as clock source for RTC ******************************************************************************/ void RTC_Setup(CMU_Select_TypeDef osc) { RTC_Init_TypeDef init; /* Ensure LE modules are accessible */ CMU_ClockEnable(cmuClock_CORELE, true); /* Enable osc as LFACLK in CMU (will also enable oscillator if not enabled) */ CMU_ClockSelectSet(cmuClock_LFA, osc); /* Division prescaler to decrease consumption. */ CMU_ClockDivSet(cmuClock_RTC, cmuClkDiv_32); /* Enable clock to RTC module */ CMU_ClockEnable(cmuClock_RTC, true); init.enable = false; init.debugRun = false; init.comp0Top = true; /* Count only to top before wrapping */ RTC_Init(&init); /* RTC clock divider is 32 which gives 1024 ticks per second. */ RTC_CompareSet(0, ((1024 * SAMPLE_RATE) / 1000000)-1); /* Enable interrupt generation from RTC0, needed for WFE (wait for event). */ /* Notice that enabling the interrupt in the NVIC is not needed. */ RTC_IntEnable(RTC_IF_COMP0); } /**************************************************************************//** * @brief Enable clocks for all the peripherals to be used *****************************************************************************/ void setupCMU(void) { /* Ensure core frequency has been updated */ SystemCoreClockUpdate(); /* Set the clock frequency to 11MHz so the ADC can run on the undivided HFCLK */ CMU_HFRCOBandSet(cmuHFRCOBand_11MHz); /* ACMP */ CMU_ClockEnable(cmuClock_ACMP0, true); /* GPIO */ CMU_ClockEnable(cmuClock_GPIO, true); /* ADC */ CMU_ClockEnable(cmuClock_ADC0, true); /* Low energy peripherals * LESENSE * LFRCO clock must be enables prior to enabling * clock for the low energy peripherals */ CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO); CMU_ClockEnable(cmuClock_CORELE, true); CMU_ClockEnable(cmuClock_LESENSE, true); /* RTC */ CMU_ClockEnable(cmuClock_RTC, true); /* Disable clock source for LFB clock. */ CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_Disabled); } /**************************************************************************//** * @brief Sets up the ACMP *****************************************************************************/ void setupACMP(void) { /* Configuration structure for ACMP */ static const ACMP_Init_TypeDef acmpInit = { .fullBias = false, /* The lightsensor is slow acting, */ .halfBias = true, /* comparator bias current can be set to lowest setting.*/ .biasProg = 0x0, /* Analog comparator will still be fast enough */ .interruptOnFallingEdge = false, /* No comparator interrupt, lesense will issue interrupts. */ .interruptOnRisingEdge = false, .warmTime = acmpWarmTime512, /* Not applicable, lesense controls this. */ .hysteresisLevel = acmpHysteresisLevel5, /* Some hysteresis will prevent excessive toggling. */ .inactiveValue = false, /* Not applicable, lesense controls this. */ .lowPowerReferenceEnabled = false, /* Can be enabled for even lower power. */ .vddLevel = 0x00, /* Not applicable, lesense controls this through .acmpThres value. */ .enable = false /* Not applicable, lesense controls this. */ }; /* Initialize ACMP */ ACMP_Init(ACMP0, &acmpInit); /* Disable ACMP0 out to a pin. */ ACMP_GPIOSetup(ACMP0, 0, false, false); /* Set up ACMP negSel to VDD, posSel is controlled by LESENSE. */ ACMP_ChannelSet(ACMP0, acmpChannelVDD, acmpChannel0); /* LESENSE controls ACMP thus ACMP_Enable(ACMP0) should NOT be called in order * to ensure lower current consumption. */ } /**************************************************************************//** * @brief Sets up the LESENSE *****************************************************************************/ void setupLESENSE(void) { /* LESENSE configuration structure */ static const LESENSE_Init_TypeDef initLesense = { .coreCtrl = { /* LESENSE configured for periodic scan. */ .scanStart = lesenseScanStartPeriodic, .prsSel = lesensePRSCh0, .scanConfSel = lesenseScanConfDirMap, .invACMP0 = false, .invACMP1 = false, .dualSample = false, .storeScanRes = false, .bufOverWr = true, .bufTrigLevel = lesenseBufTrigHalf, .wakeupOnDMA = lesenseDMAWakeUpDisable, .biasMode = lesenseBiasModeDutyCycle, /* Lesense should duty cycle comparator and related references etc. */ .debugRun = false }, .timeCtrl = { .startDelay = 0 /* No start delay needed for this application. */ }, .perCtrl = { /* DAC is not needed for this application. */ .dacCh0Data = lesenseDACIfData, .dacCh0ConvMode = lesenseDACConvModeDisable, .dacCh0OutMode = lesenseDACOutModeDisable, .dacCh1Data = lesenseDACIfData, .dacCh1ConvMode = lesenseDACConvModeDisable, .dacCh1OutMode = lesenseDACOutModeDisable, .dacPresc = 0, .dacRef = lesenseDACRefBandGap, .acmp0Mode = lesenseACMPModeMuxThres, /* Allow LESENSE to control ACMP mux and reference threshold. */ .acmp1Mode = lesenseACMPModeMuxThres, .warmupMode = lesenseWarmupModeNormal /* Normal mode means LESENSE is allowed to dutycycle comparator and reference. */ }, .decCtrl = { /* Decoder or statemachine not used in this code example. */ .decInput = lesenseDecInputSensorSt, .initState = 0, .chkState = false, .intMap = true, .hystPRS0 = false, .hystPRS1 = false, .hystPRS2 = false, .hystIRQ = false, .prsCount = true, .prsChSel0 = lesensePRSCh0, .prsChSel1 = lesensePRSCh1, .prsChSel2 = lesensePRSCh2, .prsChSel3 = lesensePRSCh3 } }; /* Channel configuration */ /* Only one channel is configured for the lightsense application. */ static const LESENSE_ChDesc_TypeDef initLesenseCh = { .enaScanCh = true, .enaPin = false, /* Pin is input, no enabling needed. Separate pin is exciting the sensor. */ .enaInt = true, /* Enable interrupt for this channel. */ .chPinExMode = lesenseChPinExHigh, /* Excite by pullin pin high. */ .chPinIdleMode = lesenseChPinIdleDis, /* During Idle, excite pin should be disabled (tri-stated). */ .useAltEx = true, /* Use alternate excite pin. */ .shiftRes = false, /* Not applicable, only for decoder operation. */ .invRes = false, /* No need to invert result. */ .storeCntRes = true, /* Not applicable, don't care really. */ .exClk = lesenseClkLF, /* Using low frequency clock for timing the excitation. */ .sampleClk = lesenseClkLF, /* Using low frequency clock for timing the sample instant. */ .exTime = 0x01, /* 1 LFclk cycle is enough excitation time, this depends on response time of light sensor. */ .sampleDelay = 0x01, /* Sampling should happen when excitation ends, it it happens earlier, excitation time might as well be reduced. */ .measDelay = 0x00, /* Not used here, basically only used for applications which uses the counting feature. */ .acmpThres = ACMP_THRESHOLD, /* This is the analog comparator threshold setting, determines when the acmp triggers. */ .sampleMode = lesenseSampleModeACMP, /* Sampling acmp, not counting. */ .intMode = lesenseSetIntLevel, /* Interrupt when voltage goes above threshold. */ .cntThres = 0x0000, /* Not applicable. */ .compMode = lesenseCompModeLess /* Not applicable. */ }; /* Alternate excitation channels configuration. */ /* The lightsensor is excited by alternate excite channel 0. */ static const LESENSE_ConfAltEx_TypeDef initAltEx = { .altExMap = lesenseAltExMapALTEX, .AltEx[0] = { .enablePin = true, .idleConf = lesenseAltExPinIdleDis, .alwaysEx = true }, .AltEx[1] = LESENSE_LIGHTSENSE_ALTEX_DIS_CH_CONF, .AltEx[2] = LESENSE_LIGHTSENSE_ALTEX_DIS_CH_CONF, .AltEx[3] = LESENSE_LIGHTSENSE_ALTEX_DIS_CH_CONF, .AltEx[4] = LESENSE_LIGHTSENSE_ALTEX_DIS_CH_CONF, .AltEx[5] = LESENSE_LIGHTSENSE_ALTEX_DIS_CH_CONF, .AltEx[6] = LESENSE_LIGHTSENSE_ALTEX_DIS_CH_CONF, .AltEx[7] = LESENSE_LIGHTSENSE_ALTEX_DIS_CH_CONF }; /* Initialize LESENSE interface _with_ RESET. */ LESENSE_Init(&initLesense, true); /* Configure LESENSE channel */ LESENSE_ChannelConfig(&initLesenseCh, LIGHTSENSE_CH); /* Configure alternate excitation channels */ LESENSE_AltExConfig(&initAltEx); /* Set scan frequency */ LESENSE_ScanFreqSet(0, LCSENSE_SCAN_FREQ); /* Set clock divisor for LF clock. */ LESENSE_ClkDivSet(lesenseClkLF, lesenseClkDiv_2); } /**************************************************************************//** * @brief Sets up the GPIO *****************************************************************************/ void setupGPIO(void) { /* Configure the drive strength of the ports for the light sensor. */ GPIO_DriveModeSet(LIGHTSENSE_EXCITE_PORT, gpioDriveModeStandard); GPIO_DriveModeSet(LIGHTSENSE_SENSOR_PORT, gpioDriveModeStandard); /* Initialize the 2 GPIO pins of the light sensor setup. */ GPIO_PinModeSet(LIGHTSENSE_EXCITE_PORT, LIGHTSENSE_EXCITE_PIN, gpioModePushPull, 0); GPIO_PinModeSet(LIGHTSENSE_SENSOR_PORT, LIGHTSENSE_SENSOR_PIN, gpioModeDisabled, 0); } /**************************************************************************//** * @brief Configure ADC for 12 bit mode, sample channel 0 with Vdd as reference * and use shortest acquisition time. *****************************************************************************/ static void ADC_Config(void) { CMU_ClockEnable(cmuClock_ADC0, true); ADC_Init_TypeDef init = ADC_INIT_DEFAULT; ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT; /* Init common settings for both single conversion and scan mode- */ /* Set timebase to 10, this gives 11 cycles which equals 1us at 11 MHz. */ init.timebase = 10; /* Set ADC clock prescaler to 0, we are using 11MHz HFRCO, which results in HFPERCLK < 13MHz- */ init.prescale = 0; ADC_Init(ADC0, &init); /* Init for single conversion use, measure channel 0 with Vdd as reference. */ /* Using Vdd as reference removes the 5us warmup time for the bandgap reference. */ singleInit.reference = adcRefVDD; singleInit.input = adcSingleInpCh5; /* Resolution can be set lower for even more energy efficient operation. */ singleInit.resolution = adcRes8Bit; /* Assuming we are mesuring a low impedance source we can safely use the shortest */ /* acquisition time. */ singleInit.acqTime = adcAcqTime1; ADC_InitSingle(ADC0, &singleInit); /* Enable ADC Interrupt when Single Conversion Complete. */ /* This is necessary for WFE (wait for event) to work. */ /* Notice that enabling the interrupt in the NVIC is not needed. */ ADC0->IEN = ADC_IEN_SINGLE; } /**************************************************************************//** * @brief A separate function for taking all the samples is preferred since * the whole idea is to stay in EM2 between samples. If other code is added, * it might be more energy efficient to configure the ADC to use DMA while * the cpu can do other work. *****************************************************************************/ void doAdcSampling(uint16_t* buffer) { uint16_t sample_count = 0; /* Enable RTC, this can be enabled all the time as well if needed. */ RTC_Enable(true); while(sample_count < BUFFER_SAMPLES) { /* Enable deep sleep to enter EM2 between samples. */ SCB->SCR = SCB_SCR_SEVONPEND_Msk | SCB_SCR_SLEEPDEEP_Msk; /* Go to sleep while waiting for RTC event (set by RTC_IRQ pending bit) */ /* Since IRQ is not enabled in the NVIC, no ISR will be entered */ __WFE(); /* Start ADC conversion as soon as we wake up. */ ADC_Start(ADC0, adcStartSingle); /* Clear the interrupt flag */ RTC_IntClear(RTC_IF_COMP0); /* Clear pending RTC IRQ */ NVIC_ClearPendingIRQ(RTC_IRQn); /* Wait while conversion is active in EM1, should be almost finished since it */ /* takes 13 cycles + warmup (1us), and it was started a while ago. */ /* Disable deep sleep so we wait in EM1 for conversion to finish. */ SCB->SCR = SCB_SCR_SEVONPEND_Msk; __WFE(); /* Clear the interrupt flag */ ADC_IntClear(ADC0, ADC_IF_SINGLE); /* Clear pending IRQ */ NVIC_ClearPendingIRQ(ADC0_IRQn); /* Get ADC result */ buffer[sample_count++] = ADC_DataSingleGet(ADC0); } RTC_Enable(false); } /***************************************************************************//** * @brief * Process the sampled data through FFT. *******************************************************************************/ void ProcessFFT(void) { uint16_t *inBuf; int32_t value; int i; inBuf = lightToFFTBuffer; /* * Convert to float values. */ for (i = 0; i < BUFFER_SAMPLES; ++i) { value = (int32_t)*inBuf++; floatBuf[i] = (float32_t)value; } /* Process the data through the RFFT module, resulting complex output is * stored in fftOutputComplex */ arm_rfft_f32(&rfft_instance, floatBuf, fftOutputComplex); /* Compute the magnitude of all the resulting complex numbers */ arm_cmplx_mag_f32(fftOutputComplex, fftOutputMag, BUFFER_SAMPLES); } /***************************************************************************//** * @brief * Find the maximal bin and estimate the frequency using sinc interpolation. * @return * Frequency of maximal peak *******************************************************************************/ float32_t GetFreq(void) { float32_t maxVal; uint32_t maxIndex; /* Real and imag components of maximal bin and bins on each side */ float32_t rz_p, iz_p, rz_n, iz_n, rz_0, iz_0; /* Small correction to the "index" of the maximal bin */ float32_t deltaIndex; /* Real and imag components of the intermediate result */ float32_t a, b, c, d; #define START_INDEX 4 /* Find the biggest bin, disregarding the first bins because of DC offset and * low frequency noise. */ arm_max_f32(&fftOutputMag[START_INDEX], BUFFER_SAMPLES / 2 - START_INDEX, &maxVal, &maxIndex); maxIndex += START_INDEX; /* Perform sinc() interpolation using the two bins on each side of the * maximal bin. For more information see page 113 of * http://tmo.jpl.nasa.gov/progress_report/42-118/118I.pdf */ /* z_{peak} */ rz_0 = fftOutputComplex[maxIndex * 2]; iz_0 = fftOutputComplex[maxIndex * 2 + 1]; /* z_{peak+1} */ rz_p = fftOutputComplex[maxIndex * 2 + 2]; iz_p = fftOutputComplex[maxIndex * 2 + 2 + 1]; /* z_{peak-1} */ rz_n = fftOutputComplex[maxIndex * 2 - 2]; iz_n = fftOutputComplex[maxIndex * 2 - 2 + 1]; /* z_{peak+1} - z_{peak-1} */ a = rz_p - rz_n; b = iz_p - iz_n; /* z_{peak+1} + z_{peak-1} - 2*z_{peak} */ c = rz_p + rz_n - (float32_t)2.0 * rz_0; d = iz_p + iz_n - (float32_t)2.0 * iz_0; /* Re (z_{peak+1} - z_{peak-1}) / (z_{peak+1} + z_{peak-1} - 2*z_{peak}) */ deltaIndex = (a*c + b*d) / (c*c + d*d); return ((float32_t)maxIndex + deltaIndex) * (float32_t)SAMPLE_RATE / (float32_t)BUFFER_SAMPLES; } /***************************************************************************//** * @brief * Main function. Setup ADC, FFT, clocks, PRS, DMA, Timer, * and process FFT forever. *******************************************************************************/ int main(void) { uint32_t time; arm_status status; /* Chip errata */ CHIP_Init(); /* Enable clocks for used peripherals */ setupCMU(); /* Setup the ACMP */ setupACMP(); /* Setup the GPIO */ setupGPIO(); /* setup lesense */ setupLESENSE(); /* Enable LCD without voltage boost */ SegmentLCD_Init(false); SegmentLCD_Symbol(LCD_SYMBOL_GECKO, 1); SegmentLCD_Symbol(LCD_SYMBOL_EFM32, 1); /* Initialize the CFFT/CIFFT module */ status = arm_rfft_init_f32(&rfft_instance, &cfft_instance, BUFFER_SAMPLES, 0, /* forward transform */ 1); /* normal, not bitreversed, order */ if (status != ARM_MATH_SUCCESS) { /* Error initializing RFFT module. */ SegmentLCD_Write(" Error "); while (1) ; } /* Configure RTC to use LFXO as clock source */ RTC_Setup(cmuSelect_LFXO); /* Configure ADC */ ADC_Config(); /* Enable DWT */ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; /* Make sure CYCCNT is running */ DWT->CTRL |= 1; while (1) { /* Power the light sensor with GPIO. */ GPIO_PinModeSet( EXCITE_PIN, gpioModePushPull, 1); /* Do sampling. */ doAdcSampling(lightToFFTBuffer); /* Power off the light sensor. */ GPIO_PinModeSet( EXCITE_PIN, gpioModeDisabled, 0); /* Do FFT, measure number of cpu cycles used. */ time = DWT->CYCCNT; ProcessFFT(); time = DWT->CYCCNT - time; /* Display dominant frequency. */ SegmentLCD_Number( (int)GetFreq() ); /* Display cpu cycle count used to do FFT. */ SegmentLCD_LowerNumber( (int)time ); /* Check last ADC value to determine if lightlevel is too low. */ /* Go to sleep with lesense enabled if ADC reading is below 10. */ if(lightToFFTBuffer[BUFFER_SAMPLES-1] < 10) { /* Write to LCD that lightlevel is too low. */ SegmentLCD_NumberOff(); SegmentLCD_Write("DARK"); /* Set gpio in pushpull for lesense operation. */ GPIO_PinModeSet(LIGHTSENSE_EXCITE_PORT, LIGHTSENSE_EXCITE_PIN, gpioModePushPull, 0); LESENSE->ROUTE = LESENSE_ROUTE_ALTEX0PEN; /* Start scan. */ LESENSE_ScanStart(); /* Enable deep sleep to enter EM2. */ SCB->SCR = SCB_SCR_SEVONPEND_Msk | SCB_SCR_SLEEPDEEP_Msk; /* Go to sleep while waiting for LESENSE event */ /* Since IRQ is not enabled in the NVIC, no ISR will be entered */ __WFE(); /* Clear interrupt flag */ LESENSE_IntClear(LIGHTSENSE_INTERRUPT); /* Clear pending RTC IRQ */ NVIC_ClearPendingIRQ(LESENSE_IRQn); LESENSE_ScanStop(); LESENSE->ROUTE &= ~LESENSE_ROUTE_ALTEX0PEN; } } }
      
      









DBG, , ( light sensor), .

: . , — 100 ( 50 , « » , , .. ). «DARK», — «» .







energy profiler , , .

EFM32WG-STK3800.







EFM32WG990F256 49 , — 411 . Cortex-M3, DSP- FPU- .





EFM32WG990F256 EFM32GG990F1024,




, cortex-m3 cortex-m4,






fpu.






, IDE , , .



, .







: 48 , , .



, . «» . Cortex-M3 2.2 , .



, , Cortex-M3, , .



, .



All Articles