SSブログ

[電子工作] ATxmega (E series)にFatFsを組み込む(USART-SPI) [電子工作]

FatFs R0.12bのATxmega Eシリーズへの組み込みです。

サンプルプロジェクトの、avr/srcから以下のコードを持ってきてベースとします

diskio.h -> 使用しない機能の設定
ff.c -> そのまま使う
ff.h -> そのまま使う
ffconf.h -> 下記の構成設定
integer.h -> そのまま使う
mmc_avr_usart.c -> XMEGA EシリーズのDMA化する

今回はとりあえず読めればいいので、以下の最小構成としました。

ffconf.h
_FS_READONLY = 1 (read only)
_FS_MINIMIZE = 1 (opendir, readdirを使いたいので)
_USE_STRFNUC = 0
_USE_FIND = 0
_USE_MKFS = 0
_USE_FASTSEEK = 0
_USE_EXPAND = 0
_USE_CHMOD = 0
_USR_LABEL = 0
_USE_FORWARD = 0
_USE_LFN = 0
_FS_RPATH = 0

_VOLUMES = 1
_STR_VOLUME_ID = 0
_MULTI_PARTITION = 0
_USR_TRIM = 0
_FS_NOFSINFO = 0

_FS_TINY = 1
_FS_EXFAT = 0
_FS_NORTC = 1
_FS_LOCK = 0
_FS_REENTRANT = 0

diskio.h
_USE_WRITE = 0
_USE_IOCTL = 0
_USE_ISDIO = 0

---------------------------------------------------------------

対応のメインはmmc_avr_usart.cです。
Chan氏のサンプルではAVR MEGA系(1284P)のUSART-SPIの実装になっています。

編集する箇所のサマリは下記になります。

power_on()
 USART-SPIとEDMAの有効化を設定(後述)

power_off()
 USART_SPIとEDMAの無効化を設定(後述)

xchg_spi()
 USART-SPIへのデータ送信&受信(1byte)(後述)
 受信のときはダミーデータ(0xff)を送る

rcvr_spi_multi()(後述)
 DMA化のキモ
 指定された回数だけ、ダミー値(0xFF)を送信してからデータを受信します。

xmit_spi_multi()
 今回はread onlyなので関数ごと削除
 なお、対応自体はrcvr_spi_multiとほぼ同じ。

disk_status(), disk_initialize(), disk_read()
 サンプルでは、CompacfFlashCardとSD-Card(MMC)のそれぞれをdiskio.cで
 呼び分けるようになっています。CFは不要なので、mmc_avr_usart.cにある
 関数"mmc_disk_xxx()"の名前を"disk_xxx()"に変更して直接呼ぶようにします。
 それぞれの関数の第一引数に"BYTE pdrv"を追加して、
 pdrv != 0だったらエラーリターンするよう一応ガードしておきます。

disk_timerproc()
 適当なタイマで100Hzの定期割込みを作って呼ぶようにする。
 WriteProtectとCardSenseを接続しない場合は状態チェックのコードを削除します。

---------------------------------------------------------------

ではいよいよ対応の詳細に行きます。

XMega EのUSART-SPI対応

XMega EにはUSARTC0, USARTD0の2つのUSARTがあります。
今回はUSARTD0側を使いました。
また、ピンアサインの都合で、PORTD[5:7]にリマップしています。
SSはPORTD4を割り当てます。

 PORTD4 : SPI-SS -> Output, High
 PORTD5 : SPI-SCK -> Output, Low
 PORTD6 : SPI-MISO -> In, 外部抵抗でプルアップ
 PORTD7 : SPI-MOSI -> Output, High

USART-SPIの有効化/無効化の設定は以下のようになります。

power_on()関数にて
{
	PORTD.DIRSET   = PIN4_bm;
	PORTD.OUTSET   = PIN4_bm;

	PORTD.DIRSET = PIN5_bm | PIN7_bm;
	PORTD.OUTCLR = PIN5_bm;
	PORTD.OUTSET = PIN7_bm;

	PORTD.DIRCLR = PIN6_bm;

	PORTD.REMAP = PORT_USART0_bm;

	/* Setup USART D0 as MSPI mode */

	/* SPI Mode 0, MSB first */
	USARTD0.CTRLC = USART_CMODE_MSPI_gc;

	USARTD0.CTRLB = USART_TXEN_bm | USART_RXEN_bm;

	USARTD0.BAUDCTRLA = 63; /* 100kHz */


power_off()関数にて
	USARTD0.CTRLB     = 0;

	PORTD.OUTSET = PIN4_bm;


1バイト送信&受信は以下の流れになります。

「送信可能(DREIF = 1)か確認する」->「DATAに書き込む」
 ->「受信完了(RXCIF = 1)を待つ」->「DATAから読む」

static
BYTE xchg_spi (		/* Returns received data */
	BYTE dat		/* Data to be sent */
)
{
	while ( !(USARTD0.STATUS & USART_DREIF_bm));
	USARTD0.DATA = dat;
	while ( !(USARTD0.STATUS & USART_RXCIF_bm));
	return USARTD0.DATA;
}


ここで、とりあえずrcvr_spi_multi()関数を上記のxchg_spi()の処理を繰り返すように実装すれば、USART-SPIを用いたSD-Cardアクセスが動きます。

rcvr_spi_multi()関数のDMA化については長くなってきたので別記事に分けます。

[電子工作] ATxmega (E series)でSD Card WAVE Playerの実験(予告) - SPI Master with DMA - [電子工作]

実験成功したので記事化予告です。

すっかり影の薄いATxmegaの更に影の薄いEシリーズにChan氏のFatFsを組み込んでDMA化しました。Eシリーズは(E)DMAとDACを積んでいて、同等のAシリーズ(32A4)よりもちょいと安くてちょいと小さいのが魅力です(^_^;)
ペリフェラルについて微妙にAシリーズとは互換が無いものがあるので注意が必要です(^_^;)
(Timer4/5とかEDMAとか)

レシピ:
 マイコン : ATxmega32E5
  TQFP-32pinと小型でDACが載っているAVR XMEGAシリーズのマイコンです。
  RSコンポーネントやDigiKeyで450〜500円くらい。
  秋月にリクエストして取り扱ってもらいましょう!(切実)

 クロック : 12.8MHz
  特に理由は無し…
  たぶん8MHzでも間に合うんじゃないかな。

 SDカードからのRead
  Chan氏のFatFs(R0.12b)を最小構成,Read Onlyで組み込んでDMA化します。
  素のSPIはDMAでMaster動作できないので、USARTのMaster SPI modeを使います。
  EDMAを2 Standard Channel構成(CH0:Rx, CH2:Tx)で使用します。
  256バイト超のreadを256+残りに分ければPeripheral channelでもいいかも。

 DAC
  タイマでサンプリングレート毎に割込みを生成し、割込み処理でDACにデータを書き出します。
  アンプ(HT82V739)を通してスピーカーに出力しました。

結果:
 12.8MHzクロック (SPIクロック6.4MHz)で、読み出し約570kbyte/sec。
 44.1kHz/16bit/StereoのWAVファイルをリアルタイムで再生成功しました。
 写真はこの時のread の観測波形です。
  =>H期間がDMAのセットアップを含む1024バイトのread。
    パルスの周期は44.1kHz x 256サンプル = 約6ms。
sdread.jpg

[電子工作] ATXMEGA EシリーズのDFLL32Mの補正精度を確かめてみる [電子工作]

どのくらい使い物になるんでしょうねということでやってみました。

ちなみに前回試したDシリーズではなく、新たに入手したEシリーズです。
(Eシリーズも秋月で扱ってくれないかなあ)

クロックリファレンスにはちゃんとしたクロックジェネレータを使いたいところですが
持っていないのであくまで参考値です。

□リファレンス
 Mega328P + 12.288MHzの水晶(±30ppm)で f=50Hz Duty=50%の矩形波を出力。

□確認方法
 リファレンスの波形から5ms遅らせて10msのタイマーをスタート。
 10ms毎にリファレンスの出力を確認して、正しい出力が取れなくなったら
 5msずれたと判断してタイマーを停止する。

□結果
 RC32MHzのみ -> 数秒でアウト -> ±0.3%くらい?
 RC32MHz + 32.768kHz水晶(±20ppm)でDFLL -> 数十秒くらいでアウト -> ±200ppmくらい?

いちおう精度は上がっているようですがもうちょっと頑張って欲しいような気も。
ブレッドボードでさらに変換基板まで介しているせいか?

参考にXMEGA側にも12.288MHzの水晶 + 10pFのセラコンをつけたところ
あっという間にずれてしまいビックリしました。
負荷容量を22pFにしたら安定してずれなくなりましたが、データシートだと10pFだったような?


ロジックアナライザか多チャンネルのオシロスコープが欲しいなあ (^^;


余談:
XMEGA EシリーズはTQFP32でサイズが手頃だったり、3〜400円くらいで値段も手頃だったり、
8bit AVRでは珍しくDACがついていたりで遊べそうなんですが、
入手性が悪かったりところどころに罠があったりでなかなか楽には行かないですねー。

タイマ4のOverflow Flagが割込みで自動クリアされなくて二時間位ハマってしまいました。
データシートのOverflow Flagのところには自動クリアの記載はないので間違ってはないけど
tinyやmegaでは自動クリアされてたしxmegaでもコンペアマッチのフラグは自動クリアされるんで
いやいやそれはないだろうとか(汗
 

[電子工作] シフトレジスタをAVRのSPIマスタで制御して7セグメントLEDを駆動する [電子工作]

7seg_sr_photo.jpg

元ネタ -> chan氏の LEDディスプレイを接続する

元ネタではソフトウェアで制御していますが、SPIマスタで制御出来ないかと思い
試してみました。

・コモン側(桁選択)のIC(164)を、74ACシリーズにしてトランジスタレスに簡略化。
 ※74AC164は1ピンで20mAくらい出せる。
  今回は電流制限抵抗を1.8kΩとし、( (3.3V-2V)/1.8kΩ ) x 8 = 最大約6mAとしています。
  超高輝度LEDを使っているので、1セグメントあたり0.7mAでも充分な明るさを得られています。

・MOSIピンを[74HC595のデータ入力ピン(14)]と[74AC164のデータ入力ピン(1,2)]に接続して
 SPIマスタで制御

・MISOピンを[74HC595のラッチ(12)とイネーブル(13)]と[74AC164のクロック(8)]に接続
 SPIマスタ中はAVR側が入力になってしまうので、プルダウンしておく。

・74AC164側にクロックを送る際はSPIをdisableにする。この時SCKピンとMISOピンの出力が
 変化しないようにPORTB[4:5]の出力をSPIマスタの終了時の状態に合わせておく

SPIマスタを使うことで、データシフト -> ピン出力 -> クロック出力を最短2クロックで
できるので、ダイナミック駆動時のCPU負荷を軽減できるかな?

回路図とソースコードです。

7seg_sr.png


[電子工作]マイコンで時間計測 - 最適なクロックはいくつ? [電子工作]

そこそこ精度の高い時間計測をしたいとします。
とりあえず、ふつーに手に入る水晶発振子の精度は±30ppmくらいでしょうか?
300秒で最大±0.01秒くらいですね。

分周+タイマ/カウンタをCTCモードで動かして、0.01秒単位で割込みをかけるには、
どの水晶を使えばより効率的でしょうか?

というわけで計算してみます。

(1) 12.288MHz

12288000 = 2^15 x 3 x 5^3 です。

タイマーのプリスケーラを/1024 (=2^10)とすると、タイマへの入力は12kHzとなり、
タイマのTOP値を120にすると100Hzとなり、0.01秒が作れます。
※8bitで足りることが重要

このクロックは、3.3V電源のAVRの安全動作範囲だったり、
44.1kHzのWAVをSDカードからreadしながら再生するのに充分な速度を出せたり、
TOP値を40と1/3にすると300Hz 約3.3mSで割込みがかけられて
4桁の7セグLEDをドライブしつつ、カウント3回で0.01秒を計時、をタイマー一個でできたりで、
なかなか重宝しそうなかんじなんですが、秋月に売ってないんですよね…

MP3デコーダ(VS1011e)を使うときにもこのクロックを使いたいので、
ぜひ取り扱って欲しいところです。


秋月にある水晶で使えそうなものを探してみます

(2) 9.216MHz

表面実装型のみですが…
9216000 = 2^13 x 3^2 x 5^3

タイマーのプリスケーラを/1024 (=2^10)とすると、タイマへの入力は9kHzとなり、
タイマのTOP値を90にすると100Hzとなり、0.01秒が作れます。

TOP値=30なら300Hz, 36なら250Hz。


一般的?なクロックではどうでしょう?

(3) 8MHz

8000000 = 2^9 x 5^6

100Hzを残すために2^2 x 5^2を残すとすると、
残念ながら2^7 = 128までしか分周できません。
AVRのプリスケーラでは128分周はなく、64分周(=125kHz)になり、
100Hzを作るにはTOP値=1250となってしまい8bitに収まりません。

が、TOP値=250 = 500Hzを5回カウントするという手があることはあります。


(4) 12MHz

12000000 = 2^8 x 3 x 5^6

8MHzはそこそこ使えるのですが、44.1KHzのWAVをSDカードから読みながら再生しようとすると
ちょ〜〜っと性能がたりません。
そこで12MHzを使おうとすると、、、

64分周で187.5kHz。100Hzを作るにはTOP値=1875です。
8MHz同様に500Hzを作ろうにも、まだTOP値=375。厳しいですねえ。

TOP値=75として8bitに収めると、割込み間隔=2500Hz= 0.4ms。
割込み間隔は4800クロックあるので、コードで25カウントしながら処理でも
よほどのことがなければタイマの取りこぼしは無さそうですが、どーでしょうね?


※16ビットタイマ/カウンタを使えばいいじゃん、、、というのもあるにはあるのですが、
 Mega88系であれば16ビットタイマ1でCTCが使えるのですが、
 Tiny861のタイマ0は16ビット動作にするとCTCが使えません。
 OVF割込み(TOP=$FFFF)の度にTCNT値を書きなおすしか無いのですが、
 分周器でTCNTをインクリメントするまで(=64clock弱)のうちに
 書きなおす必要があり、面倒です。。。

※9.126MHzで44.1kHzのWAV再生が間に合うかは試せていません。

avrの動作電圧を5Vにできるのであれば、16.384MHz(=2^17 x 5^3)や、
19.6608MHz(=2^18 x 3 x 5^2)という選択肢もありそうです。
が、消費電力を考えると3.3V動作で12MHz台にしたいんですよねえ。

ATXMega始めました [電子工作]

IMG_7668.JPG

今更感がないわけではないのですが、ATXMegaを使っていく方向で考えてみようかなと。

理由1:GPIOが多いAVRが欲しい。

28ピンAVR(Mega328とか)では、外部クリスタルを使うと使えるGPIOは20本。
たいていは足りるといえば足りるのですが、SPIやらUSARTやらをぶら下げていくと
足りなくなる時があったり。

XMega32D4は、外部クリスタルを使っても32本のGPIOが使えるのでウハウハw


理由2:安い&チップ単体で買える。

XMega32D4が秋月で250円(2016年4月現在)。
TQFP版のMega328より安いw


理由3:高解像度PWMがある。

メインクロックの4倍(HiRes+で8倍)の解像度でPWMを生成できる。
XMega以外ではtiny861aの高速PWMがあるけど、こっちは20ピンなのでGPIOの数がツライ。

※できたらXMegaAシリーズのDACが使いたいけれど、Aシリーズは共立で1700円とかする。ひええ。


理由4:AVRISPmkIIが使える。

わりと重要。
ARM系のATSAMDも興味があるけれどAtmel-ICEを買わないと?なのがなあとか。
(あと0.5mmピッチのハンダ付けはつらそう?とか)


理由5:Macの開発環境がそのままつかえそう?

わりと重要w
avr-gccとavrdudeで行けそうかなあと。
まだ試していませんが。


理由6:アセンブラの命令セットがこれまでもAVRと同じ

これまで作ってきたアセンブラ資産をできれば使いまわしたい。


対して困りポイント:

困り1:DIP版は無い。

44pinのDIPとか使いたくないですがw
0.8mmピッチなので、自分のようなブッキーでもまだ手半田できるのはありがたい。
変換ボードでもブレッドボードには挿せないので実験するときにちょっと困りますね。

これについては、ブレッド用の変換基板を作ってみようかなと。


困り2:日本語の資料が極端に少ない。

マニュアルもアプリケーションノートまで見ないと使い方がわかりづれえ。
アプリケーションノートのサンプルと、レジスタ定義のヘッダを見ながら実験してみないと?



ひとまず、変換ボードにPDIのコネクタを生やしてみたので、
単体で各ペリフェラルの動作を見ていきたいと思います。

※VCC-GND間にパスコン入れたほうがいいんでしょうけど、まあ実験ということで。

Atmelのarmコアマイコン [電子工作]

ATSAMD21を使ってみたいのだけれど、開発環境とかライタをどう用意すれば良いのだろう?

ACとDACが載っていてGPIOが豊富というのが、ちょうど欲しい機能に合致するんだけどなあ。

[電子工作] ATTiny861Aのアナログコンパレータと、電力削減レジスタ [電子工作]

ATTiny861aの電力削減レジスタ(PRR)には、アナログコンパレータのビットがありません。
(アナログコンパレータの電源は、ADCSRAのACDビットに1を書いてオフにする)

電力削減レジスタのAD変換器のビットについて、データシートでは以下の説明になっています。

・Bit 0 – PRADC: Power Reduction ADC
Writing a logic one to this bit shuts down the ADC. The ADC must be disabled before shut down.
Also analog comparator needs this clock

アナログコンパレータだけ使いたい時でも、PRADCは0にしなくちゃいけない??


試しに、PRADC=1の状態で実際にアナログコンパレータを設定してみると、、、

動作します。


んーーー、どっちが正しいんでしょう?

※ADCの消費電流はけっこう大きいので、できればオフにしたいところ。

[電子工作] KiCadで設計した長穴のフットプリントをFusion PCB (Seeed studio)に注文してみる [電子工作]

こんな感じの部品用のスルーホールです。

スクリーンショット 2016-03-06 11.30.19.png

秋月で売っているこのパーツの取り付け用です。
(画像は裏から見た画になっています)

パッドの設定はこんな感じ

スクリーンショット 2016-03-06 11.30.39.png

gerbvやFusion PCBのGerber確認画面では正しく表示されません…

が、ドリルファイルを見ると以下のように正しく?指定されているようでは有ります。
G05
X122.609Y-138.173G85X121.609Y-138.173
G05
X126.865Y-149.43G85X125.865Y-149.43
G05
X129.242Y-142.13G85X129.242Y-143.13
G05
X131.72Y-140.297G85X131.72Y-141.297
G05
X138.271Y-145.373G85X138.271Y-146.373
G05
X139.119Y-138.173G85X138.119Y-138.173
G05
X143.375Y-149.43G85X142.375Y-149.43
G05
X145.752Y-142.13G85X145.752Y-143.13
G05
X148.23Y-140.297G85X148.23Y-141.297
G05



待つこと二週間ちょい。けっこう速く届きました。
きちんと長穴で仕上がっていました。

出来上がった基板

パーツもピッタリ!

パーツもピッタリ

ちょっとパッドが狭い気もするので、次に発注するときはパッドの設定を広げて見ようと思います。

[電子工作] ATMEL AVRを喋らせてみようプロジェクト - ATtiny861A + ぷちFatFsでSDカードから再生 [電子工作]

再生するWAVの音質について、何を喋っているかわかればいいレベルであれば8KHz, 8bitでも
まあいいかなあという感じですが、せっかくなので44.1KHzも再生してみたくなります。

がしかし、ATMega328では8MHzクロックで8ビット分解能のPWMを生成する場合、
32KHzでしかパルスを生成できないので44.1KHzのサンプリングには間に合っていません。

このページによると、ATtiny24/45/85は250kHzの高速PWMが生成できるとあります。
データシートを調べてみると、マイコン内部で8MHz x 8倍のクロックをPLLで生成して
タイマ・カウンタのクロックに入力できるとのこと(8MHz x 8 / 256 = 250KHz)。

でも8ピンマイコンではSDカードとの接続とPWM出力でピンを使いきってしまうしなあと
思っていたところ、秋月でATtiny861Aなる石を見つけました。
これはtiny85の20ピン版と考えればよいでしょうか?
GPIOが15本(RESETを除く)あるので、SDカード(ピンx4)とPWM(1)で5本使っても
まだ10本もピンが残ります!

tiny85とtiny861Aの他に高速PWMを使えるAVRが見当たらなかったので、
8ピンオーディオプレーヤーをtiny861Aに移植してみました。

2016-02-06 18-14-02 +0900.jpg

同じ系統の製品だし、ピンアサインだけ合わせればいけるだろうと軽く考えていましたが、
思わぬ罠にハマり丸一日悩むハメに。。。というわけで、情報を記事に起こしておきます。

tiny85 -> tiny861Aの移植チェックポイント

●FUSEビットは同じでOK

●SPIのSSの出力ピンは任意に選べる。
 ピンアサインはaudiofunc.Sの先頭のB_CSをあわせる。
 (PORTA側のピンにしたい場合は、ソースを検索してPORTB -> PORTAに変更)

●タイマのレジスタ構成が全く違うので、おなじ動作になるよう設定しなおす(main.c)
 具体的には、こんな設定で動作しました。
TIMER1 : 高速PWM出力。DA変換のPWMを64MHzで出力する設定
			TCCR1A = 0b00100001;	/* Enable OC1B as PWM */
			TCCR1B = 0b00000001;	/* Start TC1 */

※モノラルモードのみ。ステレオはTCCR1A=0b10100011のはずですが試していません※
ここで、TCCR1Aを設定した後でTCCR1Cに書くとPWMの出力設定が上書きされるので注意です。
(データシートの116ページ)
TCCR1AとTCCR1B以外はパワーオンのデフォルトのままでOKなので触らないほうが良いかも。
TOP値のOCR1Cが、パワーオン時に0xffになっているというのはちょっと便利ですね。

TIMER0側もCTCモードにするビットの設定が微妙に違う。
TIMER0 : サンプリング期間毎にコンペアマッチで割込みを生成
         TCCR0A = 0b00000001  (CTCモード)
         TCCR0B = 0b00000010  (1/8)


で、ここで、大きな罠がありました。

asmfunc.Sに定義しているコンペアマッチの割り込みベクタ名について、
ATtiny85はTIM0_COMPA_vectですが、
ATtiny861AはTIMER0_COMPA_vect
に変更が必要です。

avr-gccの定義値の違いでデータシートでは分からないし、コンパイルエラーにもならないので
気がつくのにえらい時間が掛かってしまいました。

<Tiny85のコンペアマッチ割込み処理の先頭>
;---------------------------------------------------------------------------;
; Audio sampling interrupt process
;
; ISR(TIM0_COMPA_vect);

.global TIM0_COMPA_vect
.func TIM0_COMPA_vect 
TIM0_COMPA_vect:


<Tiny861Aのコンペアマッチ割り込み処理の先頭>
;---------------------------------------------------------------------------;
; Audio sampling interrupt process
;
; ISR(TIMER0_COMPA_vect);

.global TIMER0_COMPA_vect
.func TIMER0_COMPA_vect
TIMER0_COMPA_vect:


[ところで]
8ピンオーディオプレーヤーもですが、3.3V電源で16MHz動作はスペック外の動作?
(データシートによると10MHzより高い周波数で動作できるのは4.5V以上となっている)
まあ実際動作しているのでマージン内ということでしょうか。

※実際には、3.3Vでは12MHzまでが安全領域ということらしい。

[アンプ]
250KHzの高速PWM動作の出力をアンプ(TA7368の標準回路。電源6V)に突っ込むと
増幅し過ぎのようで音が割れまくりました。
けれど、マイコン -> LPF -> カップリングコンデンサ -> スピーカーではちょっと出力が寂しいかな。
ゲインを抑えたアンプを構成するか、ボリューム抵抗を入れると良いかも。

[SPI]
いま気がついたのですが、オリジナルの8ピンオーディオプレーヤーでは
データの出力(DOの制御)をわざわざコードを書いて行っています。
Tiny85ではOC1AがUSIのDOとぶつかっているので、ステレオ出力するときに
DOを別のピンに避ける為でしょうか。
Tiny861AではUSIで使うポートをPORTA側に変更すれば、
OC1AとOC1BをPWMで使ったままでSPIのデータ出力をマイコンのペリフェラルでできそう。
これは後でトライしてみます。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。