ソフトウェアラジオの自作!dsPICで計算した音を聴く

ソフトウェアラジオの自作!dsPICで計算した音を聴く

ソフトウェアラジオは、ストレートやスーパーラジオなんかとっくの昔に作った電子工作の中上級者が、次に取り組むラジオの一つと言えるのではないでしょうか。

本作は、当方のようなソフトウェアラジオ初心者が、いきなりダイレクトコンバージョン広帯域レシーバーのようなものを作るのではなくて、その足がかりとなるべくまずはAMラジオでソフトウェアラジオの直交検波をPIC1個、ブレボで作ってみる自作実験です。

きっかけは、dsPICに100MIPSで、しかもデュアルコアなシリーズが出たことを知ったことでした。ADCのスピードも3.5MSPSと、dsPIC33F より大幅に向上しています。これなら、455KHzの中間波でもサンプリングすることができます。

とはいえ、ソフトウェアラジオの基本的な仕組みを形にしただけだったので、きっとザラザラしたようなノイジーな音になるんだろう、でも鳴れば上出来だと思ってたんですね。

ところがどっこい!スピーカーから再生された深夜放送は、アナログのスーパーラジオより低ノイズでクリーンなパーソナリティーのトークだったのです。

ソフトウェアラジオとは

閉じたアナログ信号処理は、全て計算にて行うことができます。受信した電波を、音声やデジタルデータに復調することだって、数式で示すことができます。

ソフトウェアラジオは、受信波の復調過程の一部をソフトウェアで計算して復調結果を得ます。受信するものは、普通のFM・AMラジオに限りません。短波帯やデジタルTV、エアバンドや携帯、GPSなど、とにかくデジタル的にソフトウェアで計算して結果を得ます。

また、計算処理を入れ替えたりパラメータを変更することで、様々な変調方式への対応や細かい復調設定が簡単にできてしまうのもアナログ回路にはできない芸当で、これがSDR「Software Defined Radio(ソフトウェア定義ラジオ)」と呼ばれる理由です。

実際のソフトウェアラジオ

ソフトウェアラジオという用語に対して現在認知度が高いのは、パソコンにUSBで接続しフリーウェアを利用して音声を聴くというもので、次のようなものがあります。

RTL-SDR.COM V3 RTL2832U R820T2 TCXO/1PPM SMA-J( HF Direct Sampling Mode Q-branch)Software Defined RadioRTL-SDR.COM V3
周波数範囲は24MHz~1.7GHz。AM/FM/SSB が復調可能。別売の周波数コンバーターを使えば24MHz以下の帯域も聴けます。
R820T2 & SDR+TCXO(温度補償型水晶発信器±0.5PPM)実装カスタムチューナー単品BlueR820T2カスタムチューナー
周波数範囲は25MHz~1.7GHz。この手のチューナーで知られるR820T2チップ搭載なので他と遜色ない仕様となってます。

これらは、元々はワンセグ用のチューナーを制御して、広帯域ソフトウェアラジオとして機能させることに成功した、というところから始まったようですが、今では専用の受信機材の商品も増えてきている状況です。

USBドングルタイプのソフトウェアラジオ受信安価で小型なUSBワンセグチューナーを利用する、いわゆるUSBドングルタイプのSDR。

安くで試せるため手を付けやすい。

フリーのソフトウェアラジオソフト HDSDR上のドングルをUSBに接続し、フリーのソフトウェアラジオ「HDSDR」を利用して受信しているところ。

このようなフリーウェアが(ほとんど海外製ですが)他にもいくつかあります。
The BIG List of RTL-SDR Supported Software

これらは、一般に海外のワンセグTV用なので付属のTVアプリでは日本のテレビ放送は見れません。また、付属のアンテナもTV放送用なので、それ以外の周波数帯域(特に低い周波数帯)ではほとんど役に立ちません。ですので、短波帯やAM放送なども含めた広帯域を実際に受信するためには、それなりのアンテナを接続する必要があります。

そういったノウハウを伝授してくれる定番の書籍があります。

ワンセグUSBドングルで作るオールバンド・ソフトウェア・ラジオ: 周波数コンバータやプリアンプを手作り! 1200MHzまでバッチリ受信! (電子工作Hi‐Techシリーズ) オールバンドソフトウェアラジオ
受信性能アップのためのプリセレクタや広帯域プリアンプ、周波数コンバーターやアンテナ自作方法などが分かりやすい。

小型・高感度受信! オールバンド室内アンテナの製作 (電子工作Hi-Techシリーズ)オールバンド室内アンテナ
プリアンプの製作などで上の書籍と一部内容が被っていますが、こちらは色々なアンテナの自作方法が解説されています。

それから、本格的なソフトウェアラジオとしては次のようなものがあります。復調はパソコン側のソフトウェアで行うので、これ単体で音声を聴けるわけではありません。

 PERSEUS 短波帯受信機PERSEUS
有名なソフトウェアラジオ。10kHz~30MHzまでしか受信できませんが、良い評判しか聞こえてこない高性能受信機です。

デジタル信号処理(DSP)

計算は何もソフトウェアじゃなくても出来ますよね。ハードウェアによるデジタル回路を使えば、より省エネで小型化することができます。ハードウェアで信号を処理すること、又は、その専用のハードウェアのことをDSPと呼びます。

専用チップやFPGA上に実装されたハードウェアを使って、同じように計算で復調結果を得る受信機に、次のようなものがあります。

LINCO HFオールモードデスクトップレシーバー DX-R8ALINCO DX-R8
受信周波数は150KHz~34.999MHz。AM/FM/CW が受信可能。パソコンに繋いでソフトウェアラジオすることも出来ます。

いや、こういう、いかにも的なものじゃなくたって、Wi-FiやBluetoothも、ソコにあるスマホもそうですし、aitendoなどで売っている安い中国製のDSPラジオもそうでした。

一体いつの間にこうなってしまったんでしょうか・・・アナログ時代が懐かしいです。

ソフトウェアラジオキット

今のところ、一つだけ、USBタイプのソフトウェアラジオキットがあります。

100KHz〜1.7GHz フルバンドレシーバ ソフトウェア無線 USBチューナレシーバ RTL2832U + R820T U/Vアンテナ DIYキット ブラックソフトウェアラジオキット
100KHz~1.7GHzまで受信できる受信機のキット。パソコンとUSBで接続して多くの変調波を復調できます。アンテナ付き。

他には少々古いんですが、付録に基板付きの本も一応あります。部品は付いていません。ディスコンの品種が含まれているかも知れないので注意が必要です。

ソフトウェア・ラジオの実験ソフトウェアラジオキット
ソフトウェア・ラジオの実験―手軽にできる!はんだ付け工作にチャレンジ! (プリント基板付き電子工作解説書SERIES)。

ソフトウェアラジオのキット分野はまだ新しいので、今後も出てくるかも知れません。

原理と基礎知識

さて、先の閉じたアナログ信号処理は、全て計算にて行うことができるという話に戻ります。これは、例えば、同調回路もそうですし、局発信号の生成や混合処理も、ローパスフィルタも、増幅だってできます。

まずは放送波をADCで取り込んで一旦数値化します。そして計算を施したら、その結果をDACに流してやれば、検波後の音声信号が再生できるという仕組みです。

ということは、こんな感じで作れば理論的にはラジオができることになります。

理想的なソフトウェアラジオブロック図
でも、実際には電波はとても微小ですし周波数も高いので、全てをデジタル化しようとするとコストが上がり難しくなってしまう部分もあります。なので、ソコはこれまで通りアナログ回路にやってもらいます。

どこをアナログでやって、どこをデジタルでやるかといったことは決まっているわけではなく、モノによってまちまちなんですが、少なくとも検波の部分は計算で処理するのが普通です。その検波方式には「直交検波」が用いられます。

直交検波って何よ?

直交復調とかIQ復調などとも呼ばれ、今や多くのデジタル通信の基本ともなる検波方式です。例えば、スマホのLTE通信は、16QAM や QPSK といった変調方式を利用しており、それらの復調では直交検波が欠かせません。デジタルTVのOFDMもそうです。それどころか、どんな変調波にも応用できるため、AMラジオなどの検波にも利用されています。

変調には3つの基本的な方式があって、AMラジオでお馴染み振幅変調(AM)、FMラジオでお馴染み周波数変調(FM)、そして位相変調(PM)があります。

デジタル通信では、振幅(AM)と位相(PM)を両方とも変調することで、より多くの情報を送っています。

直交検波では、両方が変調された信号から、振幅や位相をそれぞれ同時に効率よく取り出すことができます。もちろん片方だけ変調された信号でも、もう片方は一定になるだけなので、AMラジオでもちゃんと検波することが可能なんですね。

周波数変調(FM)と位相変調(PM)は厳密には異なりますが、位相の変化が分かれば周波数を求めることができるため、FMも復調できることになります。

振幅復調の数学的根拠とシュミレーション

1N60 を使った包絡線検波なら図を見ただけですぐに原理を理解できますが、直交検波はそうはいきません。でも、実はそんなに難しくもなくて、高校の数学が多少分かるくらいなら理屈はともかく、とりあえず数式は理解できます。

直交検波のブロック図

直交検波のブロック図

受信した変調信号に対し、直交する2つの局発(sin波/cos波)を混合して出てきたIQ信号から、元の信号(ベースバンド)の振幅と位相を復調します。

以下に振幅の復調について数式と波形で示します。

搬送波の波形

元になる搬送波の波形。
搬送波を表す式
Ac:搬送波振幅(=1)
Fc:搬送波の周波数

信号波の波形

送信する信号波の波形。
信号波を表す式
As:信号波振幅(=1)
Fs:信号波の周波数
変調率を0.7としています。

振幅変調は、搬送波の振幅を信号で変化させることであり、三角関数の和積公式を使って次のようにまとめることができます。

振幅変調波を表す式

搬送波と、それに信号波を±した成分が含まれます。高い方は上側帯波(USB)、低い方は下側帯波(LSB)と呼ばれます。(波形の見た目の上側下側ではない)
ちなみに、ダイオードで検波した音声は、USBとLSBが混ざりあった信号です。

変調波の波形
振幅変調後の波形。

ここでは、縦軸の最大値を2としています。変調率に応じてこの範囲の最大値と最小値が決まります。

次に、受信した変調波に混合(乗算)する、2つの直交した局発信号を示します。局発の周波数は理論的には何でもよく、振幅は一定のため1とします。

IQ局発信号の波形

局発信号波の波形。
IQ局発信号を表す式
Fi:局発の周波数

変調波と局発信号の混合は、三角関数の積和公式により次のようになります。

変調波と局発信号の混合式

周波数の高い方(Fc+Fi)の成分は、ローパスフィルタで取り除きます。これが、直交ミクサの出力として通常扱われるIQ信号です。

ローパスフィルタ後の変調波と局発信号の混合式

IQ信号の波形
変調信号と局発信号を混合(乗算)してローパスフィルタで低い成分だけを取り出したIQ信号。

IQ信号からベクトル長を算出すると、元の信号波が取り出せることが分かります。

IQ信号のベクトル長を求める式
ここで注目すべきは、三角関数の基本的な性質 三角関数の基本公式 により、局発信号の成分がルートの中で「1」となって消えてくれるというイリュージョンです。

復調後の波形

振幅復調後の波形。

Ac/2というDC成分が含まれており、信号レベルは1/2になります。

なお、IQ信号から角度を算出すると、位相が得られます。

IQ信号から位相を求める式

実はもっと凄い直交検波

しかし、直交検波を使うことの意義はこんなもんじゃありません。これくらいならアナログ回路でもなんとかできます。

最もその真価を発揮するのは、IQ信号同士のミキシングによる周波数変換です。イメージ信号を発生させない周波数変換や、イメージ除去などの高度な応用ができるんです。

でも本作ではまだ序の口なので、そこまでの応用はやっていません。

サンプリング定理

標本化定理やシャノンの定理とも言われます。ある周波数の信号を正確にサンプリングするためには、その信号の2倍を超えるサンプリング周波数が必要だという話です。サンプリング周波数の1/2の周波数を、ナイキスト周波数といいます。

まあ、高い周波数信号を低いレートでサンプリングしようとしたって、無理があることは直感的にも分かりますよね。しかも、原信号の周波数がナイキスト周波数より高くなると「折り返し雑音(エイリアシング)」が発生してしまいます。

折返し雑音の例折り返し雑音の例。
青の信号を低レート(灰)でサンプリングすると、元の信号とは異なる成分(赤)が現れる。

ちなみに、ネット上ではどこでも「2倍以上」または「1/2以下」と書かれているんですが、正確には「超える」または「未満」だと思います。ナイキスト周波数と同じ周波数をサンプルした場合、折り返し雑音は0になりますが、取得されるレベルも0(DC)になります。現実的には、元の信号の少なくとも4倍以上のサンプリング周波数にするのが良さそうです。

デジタルフィルタ

数値化された信号にある計算を施すことで、フィルタリングを行うことができます。しかも、与えるパラメータを変えるだけでLPF/HPF/BPFなども作れます。

例えば、ある信号をADCで定期的に計測し過去5回分の数値を保存していく、という処理を繰り返すとします。保存するのと同時に、過去5つの数値を全部足して5で割った値を毎回出力していくと(いわゆる移動平均)、得られる結果は平均化された変化の穏やかな数列になります。つまり、ローパスフィルタになります。

実際には足して割るのではなく、あらかじめ用意した係数を掛けてから足す(割り算は不要)ということをします。この係数がポイントで、これを変えることで色々な特性を持たせることができるんですが、算出するのは難しいので普通はツールを使って求めます。

この掛けて足すという基本処理を「タップ」といい、回数は「タップ数」になります。
また、係数はタップの数だけ必要で、それぞれが違う値になっています。

タップ数は多いほど急峻で切れ味の良いフィルタになるんですが、当然処理コストも上がるので落とし所を見つけないといけません。

そして、これを原理とする基本的なデジタルフィルタとしてFIRIIRがあり、特徴をまとめると次のようになります。

FIRフィルタ(有限インパルス応答)

・急峻な特性を求めると多くのタップ数が必要になる。
・多少無理しても安定した特性が得られる。
・歪が少ない。
・IIRより原理や実装が簡単。

FIRフィルタフィルタの積和演算は一般的にこのような図で、組み合わせと手順を示します。
□が遅延(前のデータ)、△が乗算、◯が加算を表しています。

IIRフィルタ(無限インパルス応答)

・少ないタップ数で傾きの大きい特性が得られる。
・不安定さをはらんでいて扱いが難しい。
・歪が多い。
・FIRより原理や実装が難しい。

IIRフィルタIIRフィルタでは、絶対的な組み合わせ手順が決まっているわけではなく、代表的な組み合わせ方がいくつかあります

このような組み合わせを一つの単位(セクション)として、それをさらに組み合わせていくという方法もあります。

IIRフィルタは、一般にFIRよりも少ないタップ数で済むとされていますが、実際のプログラムではその複雑さゆえに、FIRよりも必要な命令ステップが多くなってしまうため、数十タップくらいまでの規模であれば、むしろFIRの方が効率が良いことが多いです。

また、最近ではデバイスの処理能力が高くなっているため、タップ数が多くなるとしてもFIRを使う例が多いようです。

初心者やよく分からん場合は、とりあえずFIRにしておくと失敗が少ないと思われます。
本作でも16タップのFIRを利用しています。実装例:ソフトウェア-FIRフィルタ

フィルタ設計の方法

係数の算出方法にはいくつかの手法があり、多くのフィルタ設計ツールではそれを選択できるようになっています。代表的なものとして次のようなものがあります

FIR:窓関数法

基本的なアルゴリズムで、大抵の設計ツールでサポートされています。

FIR:Parks-McClellan法(Remez法、等リプル近似法)

窓関数法よりも減衰量が多く取れるため、通常はこちらがおすすめ。複数の帯域を設定し、それぞれの帯域についてゲイン(減衰量)を指定します。例えば、2つの帯域を設定し低い方にゲイン1、高い方にゲイン0を指定するとローパスフィルタになります。

IIR:バタワース特性、チェビシェフ特性

IIRの場合、オペアンプの多重帰還型フィルタなどでも出てくる特性を指定します。あのアナログフィルタも、無限インパルス応答の一種なんですね。

フィルタ設計ツール

大抵は無料で公開されているツールで事足りるでしょう。このようなフィルタ設計ツールは、探すと他にも見つかります。

DSPLinks
Windowsにインストールして使うフリーウェアがあります。このサイトには、デジタルフィルタに関する初心者向けの解説もあります。本作でもこのツールを利用しました。

Digital Filter Design Services
知る人ぞ知る設計ツールで、結構有名なようです。Web上で使えるので便利。

TFilter
FIRしかなくParks-McClellan法のみですが、きれいなグラフが特徴。ベータ版です。

構成と回路図

ソフトウェアAMラジオブロック図

ソフトウェアAMラジオブロック図

今回使うdsPICのADC速度だけを考えるとダイレクトコンバージョンもギリギリいけそうな気がしますが、安定性の確保やソフト処理が厳しくなるのでヘテロダイン方式でいくことに。中間周波数を低くする方法もありますが、ここはあえて馴染みのある455KHzにしています。なので、フロントエンド部分はスーパーラジオそのものです。

自作の直交検波では、4066などのアナログスイッチを用いた回路でIQ信号を生成することが多いようですが、本作の条件ではソフトウェアで算出する余裕があったので計算することにしました。なので、直交ミクサとIQサンプリングの精度を気にしなくても良いですし、手持ちの受信機から455KHzのIFだけ取り出して入力することもできます。

デュアルコアdsPICでは、どちらのコアにもDSPエンジンが載っているので、2つのDSPエンジンを駆使してソフトウェア復調処理を行っています。

スレーブコアで455KHzを2.326MSでサンプリングし、291KHzの局発信号を乗算してIQ信号を得ます。FIRのLPFを通したら、マスターコアでベクトル長を計算して内蔵DACへ出力。本来はベースバンドに適したサンプリングまで落とす(デシメーション)のがセオリーかもしれませんが、手間を省くためにそのまま出力したら問題ありませんでした。

AMラジオIC LA1600

LA1600AMフロントエンド部分を簡単にするため、今回は LA1600 を利用することにしました。データシート

今はなきサンヨーのAMラジオICで30年以上も前のものですが、簡単なわりに性能の良いスーパーラジオが作れるし、短波帯まで使えるので、電子工作派の中では人気のICです。

また、局発部の発振器が結構優秀で、低い周波数から高い周波数まできれいな波形を維持し、レベル変動も少ないのが特徴。混合部にはダブルバランスドミキサ(DBM)採用でキャリア漏れも少なく、1.8Vから使えるというスグレモノです。

ただ、増幅後の中間波が取り出せないので、外付けの中間波増幅回路と併用します。

LA1600ブロック図LA1600ブロック図

IFは検波回路(Det)に直接接続されているだけで外部に取り出せません。

幸いAGCは、高周波増幅段のRF部にも効いているので、なんとか恩恵を受けられます。

もちろんアナログ出力も備えているので、本作ではこれを受信確認やトラッキング調整、ソフトウェア検波結果との比較検証用に使います。

ただし、作っている途中でアナログ音声が聞こえてきたら「もうこれでイイじゃん!」と思ってしまって、一瞬先に進む気が無くなってしまうというデメリットもあります。

DSP計算に使用するマイコン

DSP用のチップにも色々ありますが、ここは電子工作らしく? dsPICを使います。

dsPICは、初めて発売された dsPIC30 シリーズからすでに15年以上が経っており、現在のものは性能も飛躍的に向上しています。

dsPICシリーズまとめ
シリーズFosc/MIPS12bit ADC概要
dsPIC30系30MHz/30MIPS200kSPS2003年初登場、ディスコン
dsPIC33F80MHz/40MIPS1.1MSPSdsPIC30Fの改良版
dsPIC33E140MHz/70MIPS1.1MSPSdsPIC33Fの改良版
dsPIC33CK200MHz/100MIPS3.5MSPSdsPIC33Eの改良版
dsPIC33CH200MHz/100MIPS3.5MSPSデュアルコア

ちなみに、dsPIC33C シリーズから、とうとうDIPパッケージがラインナップされなくなったようです。これも時代の流れですね。

dsPIC33CH64MP202をSSOP-28変換基板にはんだ付けしたところ本作では、最新のデュアルコア dsPIC33CH シリーズの中で、最も少ピン(SSOP-28)の dsPIC33CH64MP202 を使います。

秋月のSSOP-28ピンのDIP変換基板にハンダ付けしたところ。

デュアルコアの各コアはマスターコアとスレーブコアと呼ばれ、dsPIC33CHシリーズの場合、マスター側が90MIPS、スレーブ側が100MIPSという仕様になっています。

より詳しく⇒デュアルコアdsPIC33CHシリーズの使い方まとめ

PIC32はどうよ?

今の所 PIC32 シリーズにはDSPエンジンは搭載されていないのですが、処理速度が早いし、PIC32用のDSPライブラリも用意されているので、ひょっとしたらこっちの方がイイんじゃね?と思って調べてみました。

結論からすると、通常のDSP要件では、やはりDSPエンジンを搭載するdsPICの方が有利なようです。
ただ、dsPICのDSPは16ビットの固定少数演算なので、浮動小数を使いたい場合はDSPエンジンが使えないことになり、途端にダメダメになってしまいます。

なので、浮動少数を使うケースでは、PIC32 の方が有利になるかも知れません。

回路図

自作ソフトウェアラジオの回路図

AMフロントエンドの LA1600 周りは基本データシート通りですが、IC内で増幅したIFが取り出せないので、外付けのIF増幅段を設けています。黒コイルの二次側からC5(10pF)を介してIFを入力しているので、IC内のRF段にAGCが効きます。取り出し経路のIF段(Q1)には効かないのですが、RF段へのAGCのおかげで電波が強くても大丈夫です。

C5の容量は小さいですが、このリアクタンスを利用してAGCの効き具合を調整しています。抵抗を使うと効きが少し悪くなるため使いません。※調整は調整箇所参照。

黒コイルの二次側から直接ADCに入力しています(S1AN0)。今回は確保できるADCのアクイジションタイムが短いので、相手の出力インピーダンスはなるべく低い必要があります。黒コイルの出力インピーダンスは約5Kなのでやや力不足を感じますが、実動作的には問題ないのでこれで良しとしています。また、ADCからは符号付きのフォーマットで読み出しますので、中点電位を1.15V(AVDD/2)にしています。

dsPICのMCLRピンはプルアップを内蔵していないため外付けする必要があります。R15(10K)がそれで、無いと不安定になります。

DACの出力は数百KHzのパルス変調なので、R11(2.2K)とC14(0.0047uF)でカットオフ15KHzの1次LPFを入れています。

最終段のスピーカーアンプには、こういう用途で定番の HT82V739 を使っているのですが、BTLなのでゲインが20倍もあります。この回路ではそんなにいらないので、R14(22K)を入れて約3倍に落としています。内部は反転増幅になっているので、これで帰還量が増えてホワイトノイズもグッと減ります。

パーツと入手先

ブレッドボードでの製作ですが、一応パーツリストをあげておきます。

全パーツリスト(タブ区切り)

主要パーツ

dsPIC33CH64MP202dsPIC33CH64MP202Microchip Directデータシート
初のデュアルコアdsPIC33CHシリーズ。最も少ない28ピンの品種です。しばらくは海外通販じゃないと入手しにくいと思われます。
DIP変換基板(SSOP-28)は、多くのパーツ店で入手できますね。

LA1600LA1600aitendoデータシート
使いやすいAMラジオIC。短波ラジオや実験用にも最適で、発振器としても利用できます。30年前の品種ですが、セカンドソースも出ていたので今だに入手は可能です。イーエレなどにもあります。

2V59M2V59M(AL-1P80-DJK)共立エレショップ
貴重な日本製(ミツミ)のスーパーラジオ用バーアンテナで、データシートはなく600uHです。もちろん、これじゃなくてもスーパーラジオ用なら何でも使えます。バリコンも、スーパー用が必要。

製作のポイント

スーパーラジオ用プラットフォーム本作で使っているブレボのセットは、別の製作で使ったラジオ実験セットです。IFTもブレボ上で使えるようにしたものです。

わりと簡単な回路なので再現性は高いと思いますが、一応注意点も書いておきます。

ソフトウェアラジオ自作例全体配置。

PICKIt3でデバッグ中デバッグ中。

PICKit3を繋いでいるとパソコンノイズが増えますが、やむを得ませんね。

ブレボでは、細ピンヘッダを使うこと

意外と知らない方も多いようですが、普通のピンヘッダのピンの太さはブレボにはサイズオーバーなので、無理に挿入するとキツくなったり傷めてしまう可能性もあります。

DIP変換基板では、細ピンヘッダを使いましょう。秋月電子で売っている細ピンヘッダがおすすめです。(多分、他では売っていない)

ブレッドボードの挿入口間の浮遊容量

当方の実測値では約4pF、1つ間を開けると2pFになります。

今回の回路で注意が必要な箇所は二つ。一つは、OSCに接続するVC(max.70pF)に追加される浮遊容量と、もう一つは LA1600 へのIF入力レベル調整(C5:10pF)です。

OSCの部分は、バリコンの調整トリマを最小付近にすることで吸収できます。

2マス間を空ける例C5は、このように2マス以上開けます。
回路図には10pFと記載していますが、実際には12pFになりますね。

ブレボの浮遊容量(4pF)でも鳴るレベルなので、逆に利用することもできます。

電源ラインはアナログとデジタルを分離する

普通の8ビットPICを大人しく使うのとは違って、dsPIC33CH64MP202 の2つのコアをMAXクロックで動作させると、100mA程度と消費電力が大きく、数百MHzオーダーのノイズがばらまかれます。場合によっては、それが回り回って、スピーカーから大きめのホワイトノイズのようなノイズ音が聴こえることがあります。

本作のレイアウトこんな感じに配置しています。

色々試してみた結果、意外にもアナログ部とデジタル部のグランドを一箇所接続すると(緑のライン)、スピーカーからかすかに聴こえていたノイズが大幅に減りましたので、そのまま接続しています。

電源ラインパスコンを入れてみる

例えば、バリコンを放送局が無いところに合わせてボリュームを最大にします。スピーカーからのノイズ音を聴きながら、ブレボの電源ライン上に、回路図には載っていないパスコンを入れてみるとかしてみます。

ブレボの電源ラインにパスコンただし、パスコンを入れたからといって、必ずしもノイズが減るとは限りません。場所によっては、追加したパスコンが通り道になって逆効果になるケースもあります。

また、オシロの観測ではノイズは減るのに、スピーカーからのノイズ音は増えるといった現象も出たりしますから困ったもんです。

調整・確認箇所

本作での確認や調整のポイントです。

トラッキング調整

ヘテロダイン方式なので必須。デジタル部をいじる前に調整しておくと安心ですね。LA1600 のアナログ出力を頼りに調整します。スーパーラジオの調整方法

AGCの効き具合の確認と調整

デジタル部も一通り動作するようになったら、AGCの効き具合を確認します。
もし、音が小さすぎたり電波の強い局で音が歪むようであれば、回路図中のC5(10pF)で LA1600 7ピンへのIF入力レベルを調整します。

  • 容量を小さくする → AGCの効きが弱くなる(アナログ出力は小さくなる)
  • 容量を大きくする → AGCの効きが強くなる(アナログ出力は大きくなる)

これで解決できないようなら次の調整が必要かも知れません。

IF増幅段のゲイン確認と調整

電波の強い局を受信した時、dsPICに入力するIF信号のレベルが2.3Vpp(AVDD)内に収まっていることを確認します。

dsPIC S1AN0(pin3)への入力信号を一定時間記録した波形dsPIC S1AN0(pin3)への入力信号を一定時間記録したところ。

強い電波をしばらく受信してもこんな感じになっているのが理想です。

レベルが小さすぎたり大きすぎるようなら、回路図中のR6(100Ω)で調整します。ただし、ここを触るのは、AGCの調整で解決できなかった場合に限ります。

マスターコアLEDの点滅

マスター側は、スレーブ側からデータを受信する仕組み上、スレーブ側より早く動かなければFIFOのオーバーフローが発生します。

当方の検証結果では、マスター側の方が早く動作しているようですが、結構ギリギリなので、dsPICの個体差などによりFIFOのオーバーフローが発生する可能性もあります。聴いた感じではあまり分からないので、オーバーフローした場合マスターコアLEDを点滅させるようにしてあります。

マスターコアLEDが点滅したら、マスター側を90MIPSではなく、100MIPSのオーバークロックで動作させると解消します。もちろん保証外ですが、100MIPS程度ならほぼ問題なく動作すると思われます。

ソフトウェア

dsPICでのDSPプログラミング概要と、当作のソフトウェアについて解説しています。

なお、デュアルコア特有の扱いについては、ここではデバッグ方法など必要最低限のことだけ書いてあります。もう少し知りたい場合は「デュアルコアdsPIC33CHシリーズの使い方まとめ」を参照してください。

DSPプログラミングについて

これからやる人からすると、dsPICでDSPプログラムを書くなんてとても敷居が高く感じられるかも知れませんが、実際はそうでもありません。特に、最も基本的とも言えるFIRフィルタなんか、わかってしまえば簡単です。

dsPICでは、CPU部分とDSP部分はハードウェア的には別れていますが、プログラムからはシームレスに扱うことができます。このことから、MicrochipではdsPICのことをDSC(Digital Signal Controller)と呼んでいます。

DSPエンジンの正体

DSPが得意で高速な処理が可能とされるdsPICですが、一体どれほど凄いハードウェアが載っているのでしょうか?

中心となるのは、17bit✕17bitの乗算器とその結果を格納する40bitのアキュムレータ、そして40bitの加算器と減算器、丸め処理(四捨五入)機能などです。
dsPIC33/PIC24 ファミリ リファレンス マニュアル、dsPIC33E拡張CPU

DSPエンジンのブロック図

「え、それだけ?」そう思いませんか?演算器としてはそれだけなんです。

そして、この乗算器で演算するためのDSP命令が、次の表にあるものになります。

乗算器を使うDSP命令

「え、これだけ?」そう思いませんか?これだけです。しかも、全部を使うことなんてほとんどありません。例えば、FIRやIIRフィルタではMAC命令だけでできます。

それで何が凄いのか?

これらのDSP命令は1サイクルで実行されます。が、それだけでは納得できませんよね。

DSP命令の良いところは、演算だけじゃなく演算対象となる2つのデータのプリフェッチとアドレスのインクリメント、そして演算結果のストアが同時に1サイクルで出来てしまうところにあります。アクセス対象のアドレスは全部で3つですが、それらに同時にアクセスできるんですね。そのために2系統のバス(XバスとYバス)を持っています。

さらに、モジュロアドレッシングをサポートしており、リングバッファのアクセスにオーバーヘッドが全くかかりません。

C言語的にMAC命令の実行内容を書くと、次のような感じになります。

初期化などは省いていますが、要はMAC命令は1サイクルでこれだけのプロセスを実行できるんです。
また、モジュロアドレッシングはハードウェアで自動的にやってくれますから、プログラム側で範囲チェックしたり剰余を求めたりする必要はありません。

DSPプログラムは、こういった単純な処理を数多く繰り返すだけのものですから、実行時間の短縮に期待できることが分かります。

XバスとYバス

X/Yデータバスは、CPUと共有する通常のメモリ空間へのアクセス経路であって、特別な何かが繋がっているわけではありません。ただ、アクセス可能な範囲に制約があります。

DATA MEMORY MAP FOR dsPIC33CH128MP508 DEVICES
dsPIC33CH64MP202 のマスターコアのメモリマップ。

スレーブコアでも形は同じですが、RAMの容量が半分になっています。
データシート

DSPエンジンに渡すXYバス経由のメモリ領域を、C言語の変数で宣言する場合は、次のようにグローバル変数を使い「__attribute__」キーワードを使って属性を与えます。

また、アドレスがNearエリア(0x2000)を超える場合は、同時に「far」属性も与えないと(デフォルトはNearが指定されているので)リンクエラーになります。

16ビット固定小数(Q.15)

DSPエンジンでは「Q.15フォーマット」と呼ばれる形式の固定小数点が使われます。
これは、-1.0~1.0までの値を65536分割して16ビット値に格納する方式で、多くのDSP機器、プレステなんかにも使われているそうです。

固定小数点 Q.15 フォーマット

最上位ビットは、符号フラグを兼ねる1の位なので-1.0は表せますが、厳密には+1.0は表せません。正確には[0x8000:-1.0]~[0x7FFF:0.999969482]の範囲になります。

xc16を始め、C言語ではこのQ.15形式を直接少数としては扱えませんが、16ビット変数(fractional型)に格納しておいたり、デバイスと受け渡しするだけになります。

また、この16ビットは解釈の問題なので、これを普通のshort値つまり、-32768~32767 の整数値として扱いたい場合は、変換せずにそのまま使えることになります。

DSPライブラリを使う方法

C言語からはDSP命令を直接使うことはできないので、アセンブラを使うことになります。でもいくら簡単とはいえ、多少なりとも知識や手間が必要ですよね。

幸いMicrochipの開発環境(XC16)には、C言語用のフリーのDSPライブラリ(49関数)が付属しているので、それを使う方法があります。
16ビット言語ツール ライブラリ

次のコードは、DSPライブラリに含まれるFIRフィルタの関連関数を使用する例です。先頭に”FIR”と付いているのがライブラリで定義されている構造体や関数です。

自分のソース上に「dsp.h」をインクルードし「libdsp-elf.a」をリンクすることで、DSPライブラリが使えるようになります。

ライブラリの場所は、デフォルトのインストール場所だと
「C:\Program Files (x86)\Microchip\xc16\v1.36※最後はXC16のバージョン
に置かれています。

ただ、ライブラリという性質上、各機能を実行するには相応のオーバーヘッドがあるので注意が必要。ある程度まとまったデータを渡して結果を得るのには良いかも知れませんが、1つずつリアルタイムに処理していくような用途では効率が悪いんです。

DSPライブラリ関数の速度 総合カタログから抜粋
DSPライブラリ関数の速度

さらに、電子工作では最適化のかからないフリー版でコンパイルすることが多いと思います。DSPライブラリの多くはアセンブラで記述されていますが、呼び出すC言語側で無駄なサイクルが多くなるため、ますます効率が悪くなる恐れがあります。

XC16のフリー版を使い、100MIPSの dsPIC33CH64MP202 で1サンプルの処理にかかるサイクル数を、16タップのFIRフィルタ(FIR()関数)で計測してみると、94サイクルかかります。これだと、フィルタ処理だけで約1Mサンプルでしか動けないことになります。(もちろん、ゆっくりで良いのならそれで構わないのですが…)

というわけで、本作ではソフトウェアラジオの処理にDSPライブラリは使わず、C言語のインラインアセンブラを使って自前でFIRフィルタを開発しました。そして、その動作確認をするためだけにDSPライブラリを利用しました。

DSPライブラリの問題点

それから、MicrochipのDSPライブラリには別の2つの問題があります。

最新の開発環境ではDSPブラリが使えない!?

現在の開発環境(MPLAB X V5.05 & XC16 V1.36)では、DSPライブラリ(ELF形式のlibdsp-elf.a)をリンクしても、なぜか「undefined reference to `_FIR’」といったエラーが出てビルドできません。色々試しましたが原因は不明。

幸いこれには解決策があります。DSPライブラリには全ソースコードが付属しているので、必要なソースを自分のプロジェクトに含めてしまうという方法です。多くは関数単位でアセンブラソース(.sと.inc)に書かれていますが、XC16のプロジェクトに含めるとそのままC言語ソースと一緒にビルドできますし、アセンブラソース上にブレークポイントを置いてデバッグすることもできます。こうなると好きに改造したり研究したりできるんで、むしろこの方法がオススメです。

※当記事で公開しているソースコードには、テストや動作確認のために、XC16 V1.36 に付属のFIRフィルタ関連のアセンブラソース(4ファイル)も含んでいます。

専用のフィルタ設計ツールが非公開になっている

もう一つは、Microchipのフィルタ設計ツール「Digital Filter Design Tool」が非公開になっているということ。このツールにはLite版があって本来無償で利用できるはずなのですが、公開ページが削除されており、有償版でさえMicrochip Directの商品リストから消えてしまっている状況です。

このツールは、フィルタのタップ係数をソースコードで出力してくれるので、それをDSPライブラリに参照させるというのが本来の開発方法なのですが、今ではなぜかそれができなくなっているんですね。

なので、別のフィルタ設計ツールでタップ係数を算出し、それをDSPライブラリで使える形に手動で編集するというやり方を取ります。FIRは簡単なんですが、IIRは一般にフィルタ設計ツールとの互換性が取りにくいため、ちょっと面倒になります。

DSPプログラムを自前で書く

次の表は、乗算を行う命令以外も含めた、全てのDSP関連命令の一覧です。
これらのDSP命令と一般の命令を使って、アセンブラやC言語のインラインアセンブラでコーディングします。

DSPインストラクション一覧
DSPインストラクション一覧
16 Bit MCU and DSC Programmer s Reference Manual

当作のソフトウェア解説

ブロック図

ソフトウェアブロック図

dsPIC33CHの最大の動作速度は、マスター側で90MIPS、スレーブ側で100MIPSです。能力の高いスレーブの方に、サンプリングとFIRフィルタ処理を割り当てました。

概略フロー

ソフトウェアラジオ概略フロー図

スレーブコアでの1サンプルあたりの処理サイクルは、
(4 + タップ数)✕ 2 + 3 であり、16タップでは43サイクルとなります。
それを受けるマスター側は30サイクルで、少しだけ待ち時間が発生します。

タイミングチャート

ADCへサンプリングトリガーをかけるところから、DACへ出力するところまでを時系列で表すと次のようになります。

ソフトウェアタイミングチャート

IF信号(455KHz)のサンプリング

ADCの取得フォーマットは、符号付きのfractional(Q15)に設定します。
割り込みを使うと、余計なサイクルが消費されるため使っていません。専用ADCを使用しているので、常時サンプリング、ADCへのトリガーで即座に変換を開始します。

タイマーにより周期的にトリガーをかけ、DMAを使って取得値(ADCBUF0)を「Xバス経由でアクセス可能なメモリ位置」に転送しています。このタイマーの周期を、DSP処理プログラムループの周期と全く同じとなるようにしている所がポイントです。

ループは一周するのに43サイクル。命令サイクルクロック(Fp)は100MHzですから、サンプリング周波数は 100MHz ÷ 43 = 2.326MHz になります。

データ構造とアドレッシング

ソフトウェアラジオデータ構造スレーブコアでは、直交ミクサとFIRフィルタを同時に、しかもI/Q信号2つ分を処理します。モジュロアドレッシングは、Xバス/Yバスそれぞれ1つずつしか指定できないので、2つのリングバッファの構造を次のように工夫することで同時処理を実現しました。

係数データは、PSV領域(プログラムのconst宣言)にあると余分なサイクルが必要になるため、RAM領域にコピーしてくるのが得策です。

また、DMAを使ったアキュムレータのライトバックアドレスを転送する仕組みとすることで命令サイクルを削減しています。

この一部特殊な実装は、汎用性やデバッグ性よりも、実行サイクル数を削減することを優先した結果です。

直交ミクサ

ADCでサンプリングした値(-1.0~1.0)に、局発信号(-1.0~1.0)を乗算するだけなので簡単です。sin波を掛けた結果をI信号、cos波を掛けた結果をQ信号としています。

局発の分解能をソース上で「#define OSC_NUM 8」と定義。これは、8回の処理で1周期となることを意味しており「サンプリング周波数÷8」が局発の周波数となります。
実際には、2.236MHz ÷ 8 = 291KHz になりますね。

FIRフィルタ

直交ミクサにより、I/Q信号は「455KHz ± 局発」つまり、164KHzと746KHzの2つの成分を含みます。そこから16タップのFIRフィルタを使って高い方の成分を除去します。

係数は、フィルタ設計ツール:DSPLinksを使い、Remez法で求めました。

FIRフィルタのタップ処理はこんな感じです。

REPEAT命令をやめて、タップの数だけMAC命令を並べるやり方にすると、さらに2サイクル(IとQの分)減らすことができます。

ベクトル長の計算

マスター側の主な役割は、FIRフィルタ後のI/Q信号をスレーブ側から受け取り、ベクトル長を求めて振幅を復調することです。そして、それをそのままDACへ流し込みます。

そこで問題となるのが、この式を解くこと。
IQベクトル長(2点間の距離)を求める式
特に、平方根を求めるのは一筋縄ではいかず重たいことで知られます。
なので、完全な値を求めるのは諦めるというか、そこまで正確である必要もないので、近似値を求めるアルゴリズムを利用します。

CORDICなどいくつかやりようはあるのですが、色々調べていると素晴らしい近似法を公開している記事を見つけました。平方根を使わずに距離を求める

元ネタはこの記事なんですが、さらに精度を改良したということで、簡単な乗算と加算だけで問題の数式を約1%の誤差で求めることができると書かれています。

これを、XC16のインラインアセンブラで実装してみたのが次のコード。

この計算の部分だけで、26サイクル程度に収めることができました。

乗算と加算を行うということでDSP命令が使えます。というか、このアルゴリズムでは中間結果の桁が10bit増えるため、それを格納できる40bitのアキュムレータが必要。

テストも兼ねて、x(w4)とy(w5)に-32768~32767の範囲の値をまんべんなく入力して誤差を調べてみました。小さい値(-64~64)はどうしても誤差の率が大きくなるので除外して、約100万通り計算させてみた結果、最大の誤差は1.16%でした。ヤッター!

スレーブ側から受け取った値は-1.0~1.0を表す16ビット値ですが、これを-32768~32767の整数と解釈すれば変換は不要なので、この近似計算にそのまま渡せます。

最終的には、元のプログラムにある最後の丸め計算「d = (d + 512) >> 10」は、次の理由で「ACCを-4シフトして205を加算する」という処理に置き換えています。

  • 丸め処理はコアがやってくれるため「+512」は不要
  • SAC命令で下位16bitをストアするために-16シフトする
  • 直交復調では信号成分が1/2になるため2倍する(-1シフト)
  • ADCには1/2スケールで入力しているため2倍する(-1シフト)
  • DACは12bitなので+4シフトする
  • dsPIC33CHシリーズのDACの有効範囲は「205~3890」

なお、この計算を行うために、スレーブコアではDSPエンジンの乗算モードを整数にするなどの設定を行っています。

その他注意点など

dsPIC33CHシリーズではADCの校正ができない!?

dsPIC33CH64MP202では、最新のリファレンスマニュアルに示されているサンプルコードを実行しても、ADCの校正レジスタが反応しません。何を書いても0のままだし、CAL0RDYビットもセットされず、未実装レジスタと同じ挙動を示します。恐らくデータシートの誤りで、校正は必要なくなったのかも知れません。

dsPIC33CHシリーズには汎用タイマーが無い!?

dsPIC33CHでは、他のPICにはあるTMR2やTMR3といったおなじみの汎用タイマーは廃止され、代わりにSCCP(Single output Capture/Compare/PWM/Timer)という多機能モジュールが搭載されています。汎用タイマーを使いたければ、このCCPモジュールをタイマーモードに設定して使うことになります。

実行サイクルの計測方法

プログラムの実行サイクルは、シミュレーターのStopWatchを使って計測できますが、間違っていることが結構あるので、本作のようにシビアなサイクル設計が必要な場合は、実デバイス上で正しいサイクル数を確認する必要があります。

汎用タイマーのクロックソースを命令サイクル(Fp)に設定し、そのカウンタをウォッチすることで実行サイクルを知ることができます。本作の初期化処理では、そのためにSCCP2モジュールをタイマーモードにセットアップするコードを入れてありますので、「//CCP2CON1Lbits.CCPON = 1;」をコメントインし、2つのブレークポイント間でCCP2TMRLレジスタ値の差分を取れば、実行サイクル数を確認することができます。

一部の機能はSimulatorで動かない

ADCやDMA、モジュロアドレッシングなどはシミュレーターでは再現されないので、実デバイスで確認する必要があります。

ソースとビルド

マスターコア用とスレーブコア用の、2つのプロジェクトを含んでいます。

ソースファイル(c/h/s/incファイル in ZIP)

解凍して出てきたフォルダをパソコン上の適当な場所にコピーして、MPLAB X で開きます。Masterプロジェクトをメインプロジェクトに設定してビルドしてください。

スレーブ側でDSPライブラリのヘッダ(dsp.h)をインクルードしていますが、xc16に含まれているためそのままビルドできます。

また、MasterのSlavesプロジェクトフォルダのプロパティーにある、スレーブのBuildチェックボックスは、外さないようにしてください。外すと、自動生成されるスレーブアドレスヘッダ(Slave.h)が生成されなくなるため、ビルドエラーになります。

書き込みは、普通のPICと同じようにすればOK。マスターとスレーブの両方が転送されます。ただ、デバッグする場合は特有の操作があります。※次項参照

使用したIDEのバージョンは下記の通りです。

MPLAB X IDE:v5.05
XC16:v1.36

MPLAB- X IDE | Microchip Technology Inc.

書き込みやデバッグには PICkit3 を使いました。

PICkit3PICkit3
Microchip正規品。PICへのプログラムの書き込やデバッグができます。最近では安い中国製の互換品も出回っていますが微妙です。

デュアルコアdsPICのデバッグ方法

マスターとスレーブを同時にデバッグすることも可能ですが、ICEを2つ用意するなどの段取りが必要。普通は別々にデバッグします。次の順番で操作してください。

マスターコア側のデバッグをする場合
Masterプロジェクトをメインプロジェクトに設定する。

Slavesプロジェクトフォルダのプロパティーで、スレーブコアプロジェクトのDebugチェックを外す

Masterプロジェクトのmain.c冒頭にある「#define SLAVE_DEBUG」をコメントアウトする。

デバッグを開始する。※どちらもデバッグしない場合は、ここでリリースビルドして普通にdsPICに書き込めばOK。

スレーブコア側のデバッグをする場合
Masterプロジェクトをメインプロジェクトに設定する。

Slavesプロジェクトフォルダのプロパティーで、スレーブコアプロジェクトのDebugチェックを付ける

Masterプロジェクトのmain.c冒頭にある「#define SLAVE_DEBUG」をコメントインする。

リリースビルドしてdsPICに書き込む。

Slaveプロジェクトをメインプロジェクトに設定する。

デバッグを開始する。

実験と検証結果

下の項目について変化させてみた結果を記載しようと思っていたのですが、実際に試してみたところ、違いがあまり出なかったため詳細は省きます。

  • 入力のサンプリング周波数を変えてみる
  • 局発周波数を変えてみる
  • FIRタップ数を変えてみる
  • 出力のサンプリングレートを変えてみる

変化させてみた量が小さすぎたのかもしれません。あるいは中波帯では、実視聴上では影響を受けているようには感じにくいのかも知れません。

感度について

本作の感度は、アナログ回路のフロントエンド部に依存するため、特に考察しません。

なお、本作でのADCの入力とDACの出力の比は、理論上ですが、
「ADCの入力範囲 ✕ 変調率(約70%)= DACの出力範囲」で表されます。

包絡線検波を試す

少し変えるだけで、ソフトウェア包絡線検波ができるのでちょっと試してみました。

まず、スレーブ側の係数テーブルの初期化にて、sin値とcos値を生成している部分がありますが、両方を「1」(0x7FFF)に変更します。

これにより、IQ信号は生成されなくなり、サンプリングされたそのままの値2つが、マスター側のベクトル長の計算に送られることになります。すると、次のように、

包絡線検波時のベクトル長の計算

単に、絶対値を1.4倍した値になります。絶対値になるということは、アナログ回路の全波整流による包絡線検波(検波で全波整流は普通やりませんが)と同じことをしていることになりますね。

こうなるとFIRフィルタは不要になるんですが、455KHzを通過させないといけないので、455±50KHz程度の帯域幅を持ったテキトーなバンドパスフィルタへ変更します。

音質的には、直交検波とさほど変わらずなかなかの良音です。ただ、同調際で小さく「ピー音」が入るようになったように思います。
疲れたうさぎそのため、微小な放送局ではピー音にかき消される感じで、全体的にノイジーに感じます。

サンプリングレートを変更したりすれば改善するかも知れませんが、それ以上の調査や実験は見送りました。

ダウンロード・資料

製作に使用した全ファイルです。無断で二次配布することはご遠慮ください。ご紹介いただく場合は当記事へのリンクを張ってください。連絡は不要です。

回路図(pngファイル)
ソースファイル(c/h/s/incファイル in ZIP)
全パーツリスト(タブ区切り)

ファームウェア開発環境:MPLAB-X IDE
デジタルフィルタ設計ツール:DSPLinks

dsPIC33CH64MP202 関連マニュアル

本作に関連する部分の資料をまとめました。

日本語は、マイクロチップ・テクノロジー・ジャパン株式会社日本語資料にありますが、翻訳されているのは一部です。
無いものや新しい資料は、本家Microchipの、dsPIC33CH64MP202からどうぞ。

dsPIC33CH64MP202

dsPIC33CH128MP508 Family Datasheet

CPU/DSPエンジン

dsPIC33/PIC24 ファミリ リファレンス マニュアル、dsPIC33E拡張CPU

モジュロアドレッシング

dsPIC33E/PIC24E ファミリ リファレンス マニュアル、セクション 03. データメモリ

MSI(FIFOなど)

dsPIC33/PIC24 FRM, Master Slave Interface (MSI) Module

ADC

dsPIC33/PIC24 ファミリ リファレンス マニュアル、12ビット高速マルチSAR A/Dコンバータ(ADC)

DMA

PIC24F ファミリ リファレンス マニュアル、セクション 54. ダイレクトメモリアクセス (DMA) コントローラ

SCCP

PIC24F ファミリ リファレンス マニュアル、セクション 64. キャプチャ /コンペア/PWM/ タイマ(MCCPおよびSCCP)モジュール

プログラマーズリファレンスマニュアル(インストラクションなど)

16 Bit MCU and DSC Programmer s Reference Manual

デュアルコア入門

AN2721 – Getting Started with Dual Core

XC16のマニュアル

MPLAB® XC16 Cコンパイラ ユーザガイド

ライブラリのマニュアル

16ビット言語ツール ライブラリ

ソフトウェアラジオの本

電子工作初心者さんにもオススメです。

ワンセグUSBドングルで作るオールバンド・ソフトウェア・ラジオ: 周波数コンバータやプリアンプを手作り! 1200MHzまでバッチリ受信! (電子工作Hi‐Techシリーズ) オールバンドソフトウェアラジオ
受信性能アップのためのプリセレクタや広帯域プリアンプ、周波数コンバーターやアンテナ自作方法などが分かりやすい。

小型・高感度受信! オールバンド室内アンテナの製作 (電子工作Hi-Techシリーズ)オールバンド室内アンテナ
プリアンプの製作などで上の書籍と一部内容が被っていますが、こちらは色々なアンテナの自作方法が解説されています。

らくらく!SDR無線機入門 (RFワールドNo.22): ソフトウェアによる無線信号処理の実際をハンズオン形式で学ぶらくらく!SDR無線機入門
こちらはより技術的な内容。例えば直交検波を、複素数を用いた数式ではなく図解で分かりやすく解説しているところが良いです。