2017年11月08日

AVR系Arduinoの外部割込みピンを増やしたかった

めもらしきもの

AVR系のArduinoではattachInterruptというステキ関数を使うことで外部割り込みを使うことができます。確かUNOではINT0,INT1の二つのピンで外部割込みを使うことでができますね。

これは二相ロータリーエンコーダ等の処理を行うのには非常に便利なわけです。

しかしattachInterruptは有能関数なのですがINTピン以外では有効にできないのはちょっと不便です。

まあ何が言いたいかっていうと強いエンコーダについてるZ相が読めないわけですね。

こういう時に外部割込みピンが無いと少々トリッキーな処理を書いたり
頭の悪い処理を描く必要性が出てしまいます。

INTピン増やしてぇ!!ってわけです。

実はAVRにはINTピン以外に外部割込み可能なPCINTピンがあります。
ぶっちゃけマイコンから飛び出てるIOポート全部ですね。

つまりIOピンのすべては外部割込みピンとして利用できるってわけです。
これはピン変化割り込み(PCINT)と言うのですが若干INTピンを使う方法と比べ制限が付きます。

それは
論理変化時化時にしか割り込めない
ピン個別ではなくポートごとに割り込んでしまう
という点です。

論理変化時にしか割り込めないと言うのは立ち上がり、立ち下りを判別できないってことですね。
これはハンドラ内でピンの状態を読めば解決できるのでそんなに問題にはならないです。
ピン個別ではなくポートごとに割り込んでしまうというのは欠点と言うより利点かもしれませんね
同ポート上の複数のピンで割り込めるかは知らない。マルチプレクサで束ねられてそうだから無理かもしれん

とまあこんな制限があります。この特性をうまく利用していくといいかもしれません。

実際にPCINT機能を使うには二つのレジスタをいじったりポートによってレジスタが違ったりし、更にそれを直接叩いてやるのは混乱を招きますし何やらArduinoっぽくありません

という訳で僕がArudino UNO用にArduino標準関数ライクなライブラリを書いておきました。

実は探すのが面倒だったから作ったというアホな理由

ちょろっと実験して動作確認した程度なのでちょっとした間違いは許して

では早速ヘッダ(PinChangeInterrupt.h)の方から
#pragma once
#ifndef PinChangeInterrupt_H
#define PinChangeInterrupt_H


#include <Arduino.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef EXTERNAL_NUM_INTERRUPTS
#define EXTERNAL_NUM_INTERRUPTS 3
#endif

#ifndef digitalPinToPCICR(p)
#define digitalPinToPCICR(p)    (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0))
#endif

#ifndef digitalPinToPCICRbit(p)
#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1))
#endif

#ifndef digitalPinToPCMSK(p)
#define digitalPinToPCMSK(p)    (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0))))
#endif

typedef void (*void_function_pointer)(void);
static void nop(void) {}
static volatile void_function_pointer interrupt_function[EXTERNAL_NUM_INTERRUPTS] = {nop, nop, nop};

enum { PC_INT_0, PC_INT_1, PC_INT_2 };

class PinChangeInterrupt {
  public:
    PinChangeInterrupt();
    ~PinChangeInterrupt();
    void attachInterrupt(uint8_t pin, void (*userFunc)(void));
    void detachInterrupt();

  private:
    uint8_t interrupt_pin;
    uint8_t interrupt_pin_bit_mask;
    uint8_t *interrupt_pin_port;
};
#endif


ソース(PinChangeInterrupt.cpp)の方
#include "PinChangeInterrupt.h"

#define _ISR(vect, interrupt) ISR(vect) {interrupt_function[interrupt]();}

PinChangeInterrupt::PinChangeInterrupt() {
  interrupt_pin = 0;
  sei();
}

PinChangeInterrupt::~PinChangeInterrupt() {
  PinChangeInterrupt::detachInterrupt();
}

void PinChangeInterrupt::attachInterrupt(uint8_t pin, void (*userFunc)(void)) {
  intterrput pin;
  uint8_t pcicr_bit_mask = digitalPinToPCICRbit(interrupt_pin);
  uint8_t pcmsk_bit_mask = digitalPinToPCMSKbit(interrupt_pin);

  //pinMode(interrupt_pin, INPUT);
  *(digitalPinToPCICR(interrupt_pin)) |= _BV(pcicr_bit_mask);
  *(digitalPinToPCMSK(interrupt_pin)) |= _BV(pcmsk_bit_mask);
  interrupt_function[pcicr_bit_mask] = userFunc;
}

void PinChangeInterrupt::detachInterrupt() {
  uint8_t pcicr_bit_mask = digitalPinToPCICRbit(interrupt_pin);
  uint8_t pcmsk_bit_mask = digitalPinToPCMSKbit(interrupt_pin);

  *(digitalPinToPCMSK(interrupt_pin)) &= ~_BV(pcmsk_bit_mask);
  interrupt_function[pcicr_bit_mask] = nop;
}

_ISR(PCINT0_vect, PC_INT_0)
_ISR(PCINT1_vect, PC_INT_1)
_ISR(PCINT2_vect, PC_INT_2)

使い方はほぼattachInterruptと同じです。違うのは割り込みモードの指定ができないだけ

適当にLEDが0番ピンの立ち上がりで1番ピンがトグルするサンプルコードを作ってみました。
#include <PinChangeInterrupt.h>

#define PCINT16_PIN   0
#define LED_BLINK_PIN 1

PinChangeInterrupt pcint;

void blink(void) {
  volatile static bool blink_flg = true;
  if(digitalRead(PCINT16_PIN))digitalWrite(LED_BLINK_PIN, blink_flg = !blink_flg ); //立ち上がりモード
}

void setup() {
  pinMode(PCINT16_PIN, INPUT); //忘れずに
  pinMode(LED_BLINK_PIN, OUTPUT);
  pcint.attachInterrupt(PCINT16_PIN, blink); //void(void)な関数のポインタをぶち込もう
}

void loop() {

}
立下り立ち上がりの判断は割り込みハンドラ内でピン状態を読めばできますよ。
ただどっちでも割り込んじゃうけどね。

このライブラリはATmega328Pや168Pが実装されたUNOやnanoでしか使えない欠陥品です

マクロをいじればMEGAやらLeonardoにも対応できるのでいつかやってみようと思います。




drttx at 00:01|PermalinkComments(0)弱電 | マイコン

2017年10月21日

あたらしいDAC(組み込み編)

前回の続きです。

機能ごとにモジュール化された基板が動作させるのに必要な分を完成させたので次はケース作成です。

今回も共立さんで売ってるおなじみの訳ありケースを使いました。

[画像:41c83b77-s.jpg]
大きい方が一回り小さい奴より1000円も安いのはちょっとよくわからない

本当はサイドウッドで横にもう少し大きいいかにもなケースを使いたいけど予算が...
実験作だし仕方ないよね?

材質は柔らかめのアルミなのでスパスパ加工できていいですね。

フロントパネルです。
[画像:ab511c77-s.jpg]
前回は音量調節ノブはロータリーエンコーダでしたが電源投入前後の位置の記憶やらが面倒だったので可変抵抗になりました。結果フィルタやら組まないと揺らぎが凄かったです。

リアルタイムセンサみたいな使い方ではないので位相とかガン無視できつめにフィルタをかけたら一切揺らぎがなくなってとてもぐっど(*'ω'*)

けど可変抵抗の問題なのか閾値の問題なのかある特定の部分で止めると揺らぎが発生するのはなんでだろう…


ちぎにゃぁバックパネルですね

[画像:fd014435-s.jpg]

これは電源周りとかある程度加工されてるものを使いました。前回からの経験でフライスで加工するのは面倒ですからねぇ。

USB端子はノイトリック社のNAUSB-Wとかいう面白そうなモノを見つけたので試しに使ってみました。すっごい便利ですよこれ。どうやら同社のレセプタクルシリーズと穴径が互換なようでイロイロ切り替えができるみたい。実に汎用性が高そうだ

HDMIタイプもあるみたいなのでI2S信号を外部から差動で入力したいって時にも使えそうです。近々ラズパイオーディオもやってみる予定なので差動出力用の専用基板を作ってトランスミッタとして使うのもありかも…I2Sは外部からの影響を受けやすく、中距離以上の通信には全然向いてないので少しでも通信距離を稼ぐために差動で出力してやらないと通信できないんですよね。そのためのSPDIFなんて言わない約束です。どうせならSPDIFにも対応すればいい話なのですよ。


ケース加工も済んだことですしケースにモジュールをぶち込んでやりましょう。

image

前回ほどではないですが今回も少々ケースが小さかったようです。電源基板が途中で使用変更があったこともあり結構ギリギリで予定していたメーカーさんとかが良くやってる電源周りとDAC周りのシールドもできませんでした。頑張ればできそうですが、結局両者が近づくためあまり意味がなさそうです。

そうそう、ぶち込んだ後に気づいたんですが、このケース最高に接地がとりにくい&十分な接地面積が無加工だと確保できない…次からはこのケースは使わないと心に決めました。

ぶっちゃけ写真の段階で音は出ました。素の音では高音がヤヤきつい印象ですが分離はいいようです。しかし低音があまりよろしいとは思えませんなぁ。音に余裕がないようです。これは単純にオペアンプの性能的な問題が原因に挙げられますね。さっさと交換した方がよさそうです。

そして更なる問題が発生しました。アンプのボリュームを最大にして無音状態で耳をすますと高周波数領域で良からぬ信号が出てるんですね。具体的には「ピー」って音です。かなり古いアンプだったのでアンプがおかしいのかなぁって最初は思ってましたが。最近買ったポータブルスピーカーの方でも似た現象が起きたので間違いなくDACの方から出てるみたいです。

これが簡易的なFFT結果
DMk50SMVAAAz5c2

生活音とかアンプ本来のノイズとかが混じっててゴミみたいな測定?結果ですが何やら7kHz付近に不自然にピークが出てますね…多分悪いのはコイツです。計算ノイズ説もありましたがDACの駆動中にしか現れなかったためそれはなさそうですし結構大きめです。

どこから来てる発振音なのか血眼になって探しましたよ。アナログ回路はどうも白でした。電源周りはそもそも中途半端に広域なので対象外です。デジタル回路が一番の怪しみをはらんでいたんですが信号源は想定外のところだったんですよね...そうI2Cバスラインだったんですよ…
I2Cでデータのやり取りを止めたら綺麗さっぱり無くなりました( ^ω^)
どうすっかなぁって感じです。今回のDACの各モジュール間の通信は全部I2Cで行ているんですよね。ぶっちゃけ止めれないわけです。最悪DAC側はアッテネート機能を取っ払って電子ボリュームを外付けすれば最低限で済みますが、COMBO384とかミュート回路とか結構重要な部分はどうしても止められないんですよね。ああアッテネート機能は完全に取っ払います。思ったものと違いました。
アナログボリュームみたいに連続的に値を変えると「ぼぼ」とノイズが入りました。クリックノイズみたいな感じですがそれとはちょっと違うよう気がします。

とりあえず今は音は鳴るっちゃ鳴るけどPCM1795の特性を完全に生かせてないみたいですね。完成までの道のりは結構長そうです。

次回はまともな測定器を使って原因究明をしたいと思います。

drttx at 00:40|PermalinkComments(0)オーディオ | PCM1795

2017年10月17日

あたらしいDAC(作製編)

まぁ毎年のようにこの時期はロボコンがあるわけですね。結果は残念なことに一回戦敗退で悲しみが深いです...相手との相性が最悪だったとしか言えません...

一回戦から優勝しちゃった優勝候補とかなんなんだよ…(ワイが抽選会で引いてしまったわけだが)

死ぬほどモータドライバ作ったんですがね…うちの部の回路開発関係は漏洩とかそこらの問題で大きく取り上げれないのが残念です。モチベーション下がっちゃうねんねん

ここ数年、圧倒的回路人員不足で実動員が2人なわけで、理想はワイが設計担当もう一人が製作担当って状態です(2人の時点で何かおかしいが…)。しかしかし、結局チームごとに分かれちゃうんで実質一チーム分の回路の設計製作を一人でやる必要があって大変というかおかしすぎるわけです。今年はロボットの台数が3台でモータを死ぬほど使う形になりワイが死んだ

ぶっちゃけた話うちの部は回路事情が周りよりクソほど遅れてるわけで(ワイより前の世代がごみ過ぎた)二年前ぐらいからちょっとづつ改革をしはじめ、最近やっと周りに追いつきかけてきたわけです。要するにまとまった技術体系が確率できてないんですね。

人手不足なせいで同時進行でプロジェクトを進められないのだよ...回路ブロックの人員補給が来年度最大の課題になりそうだ...

愚痴やらそこらはこの辺で終わらせましょう。

まあ要するにロボコンが全国いけなかったんで他のことに時間を注げるわけです。今作製中のオーディオなDACにたくさん時間を割けますね!

早速DACのお話に入っていきます。(*・ω・)(*-ω-)(*・ω・)(*-ω-)

前回の設計通りにPCBをElecrowに発注して基板が届いたわけだ

青基板のカッコよさ

DSC_0554

因みにDAC基板にはLPFと差動合成アンプがくっついてちょっと便利さがアップしてる。
Elecorwはデザインルールとサイズさえ合致してれば基板どうしをくっつけて面付けもどきができるのでイロイロ基板に余計なものが追加されてます。追加された中でも機能的にでかいのがこれ


vol

電子ボリュームですね。今回使うDACICは量子化ビット数が32bitなので16bit音源の場合は内部デジタルアッテネータの関係上音質劣化はほぼ発生しません



肝心の32bit音源やよくある24bit音源では劣化が発生します。これではもったいないわけです。
そこで、入ってきた音声データをいじって音量を調整するDAC内部のデジタルアッテネータではなく操作はデジタルインターフェースだけどアナログ的に音量を調整できる電子ボリュームの必要性を感じました。電子ボリュームには賛否両論が分かれますが、ワイはいいものだと思います。

前回のDACではLM1972で電子ボリュームを構築しましたが結構使い勝手もよくリギングエラーも発生しないので気持ちよく音量調整ができました。少なくとも1000円程度のボリュームよりは良いと思いました。

ただこのICは使用可能電圧がそんなに高くなく結構古いICです。

この電子ボリューム基板では±15Vで使用できダイナミックレンジも大きくTHD+Nも優れているPGA2320を使っています。オーディオに強いBBブランドですがその性能はいかに?

とりあえず電子ボリュームの話はここで終わらしてどんどん作っていきます。

最初にできたのはミュート回路です。最初にできたのは別に動かなくても精神的ダメージがおおきくないからですよん。

DJlgAGpVwAAqH9D

うおっ かっこいいね

まとまった感じに仕上がりました。リレーは音響用じゃないけど別に問題ないでしょう

動作チェックした結果、OFF時にすみやかにミュートがかかりました。これによってポップノイズが入らなくて耳にやさしいです。参考にしたパルス検出もしっかり働いてるみたいです。例外処理として自動復帰機能も付けたけど意味があるかは不明ですね。

この基板はタイマ機能もありスタンドアロンに使うこともできますしI2CやSPI等の通信インターフェースのスレーブにもなり得るため結構使用用途が広がるかと思います。

何よりプログラムが一発で動いて草し生えなかった。(よく見たら完成前の基板だった)

次はDAC基板

DKfz1A8UEAE7kwk


OSコンやらタンタルコンをふんだんに使ってやりました。(写真は制作途中という矛盾)本当はパスコンにEUCPシリーズのフィルムコンデンサを使いたかったけど納期が11月だったのでPCM1972Aのときにでも使ってみます。

レギュレータには新日本無線の超低ノイズ低ドロップでリーズナブルな値段で有名なレギュレータを使ってたり(EABLE端子が正論理なのにGNDに直結されていたという意味不明使用)

DSDの入力信号切り替えも上手く言ってるみたいなんだけどオーバーシュートが結構あるみたい...ダンピング抵抗の値をもう少し大きくしたほうがいいみたいですね。と思ったけどI2Sバスが3.3Vに対しDACICくんは5Vトレラントなのであまり気にしなくて良さそうです。

基板の先にはI/Vコンバータと差動合成アンプが乗ってます。資金不足のためI/VコンバータはOPA2134、差動合成アンプにはNJM5534をぶち込んだんですが両者とも力不足のようです。OPA2134に関しては発振してるのかかなり熱を持ってますね。

そこまで高速なオペアンプじゃないわけで自分もこのオペアンプが発振するのは初めてです。もしかしたら役不足なことで爆熱してるだけかもしれませんがね。とりあえず今度オシロで確認することにします。

ここのアナログ部分は音質にかなり影響を与える部分から超強いオペアンプを買ってこようかなぁと思ってみたり

I/Vコンバータはデュアルタイプのみ対応なので選択に幅がやや狭くなります...今のところ

OPA1612あたりがいいんでないかなぁって算段ですね。こいつはOPA2212のオーディオ向けの後継機らしくノイズが1.1nV/√Hzで歪率0.000015%とちょっと頭おかしいスペックとなっています。OPA2134より色々な面でスペックが高いので良い方向に進んでくれたら嬉しいなぁ
因みにお値段850円ほど

差動合成アンプはシングルタイプに対応しているため結構選択の幅が広いです。
しかし、シングルタイプの最高峰とも言われるOPA627は高杉なんで評価がかなり高いTHS4631を使ってみます。これもいうまでも無くアホスペックです。中には上手く使えばOPA627を超える可能性を秘めてると言う声も。

上手く使えるかは非常に微妙...
超高速オペアンプでそれなりの電流を消費するためただでさえ熱を持つのに爆熱になるというね。更に発振領域が高いためそこらのオシロじゃわからないっていう代物。条件付きでユニティゲインでも使えるみたいです。
因みにお値段およそ800円

追加部品は3000円ほどで済みそうでうれC
日本で買うと倍ぐらいしそうだよね。特に某立エレショップでは3倍くらいの値段で売られていて意味不明でしょ

使う基板を揃えるとこんな感じ

DK0DLzHVAAA4hKd

青ってやっぱりいいよねぇ…
insta映えしそうな色だよ…

まあ改装計画も立てられたことですじゃっかにゃ長かったですが今回はここで終わりにします。

最後に最近買ったブルジョワレンズで撮った写真

DMWRMIuUMAEtt06

組み込んだ後のDAC基板くん
絶賛テスト駆動中だ!

次回に続く






drttx at 01:08|PermalinkComments(0)オーディオ | PCM1795