2019年2月3日日曜日
JAPAN Camping Car Show 2019
2019年2月2日 土曜日
年に一度開催されるジャパン・キャンピングカーショーへ行きました。
最近は軽キャンピングカーがトレンドらしく、一見商用車のようなバンをベースとした軽バンが多く見られました。
多くをレポートしませんが、シンパシーを感じたものをいくつか紹介します。
2016年12月6日火曜日
USBの消費電力記録ツールを作りたい(構想段階)
1 目的
低消費電力なエナジーハーベスティングなどが流行しているので私も混ざりたい。まずは使用するマイコンやセンサの動作時の消費電力を測定したいが、短時間での動作をテスタでは読めない。消費電力の細かい変化をSDカードなどに記録し、表計算ソフトでグラフ化してみたい。
2 実現方法
電流検出IC => ADC(PIC) => microSD(MDDFSを使用してW/R)3 悩みどころ
構想をしつつ、回路図を途中まで書いてみました。
SDへの書き込みは過去の回路を流用出来ると楽なのでdsPIC33FJ64GP802を使いたいです。
電流検出ICはMAX4376FASAを購入しました。
-悩みどころ1 ADCリファレンス電圧の作り方
電流検出ICのMAX4376FASAはゲインが50倍で、電流1A、シャント抵抗が100mΩのときに5Vの出力となります。
5VをDACで取り込めば良いと考えますが、dsPICとmicroSDは3.3V駆動です。
dsPICのADCに使うリファレンス電圧 Vref+は3.6Vが最大とデータシートにあるので、5Vは取り込めないようです。
対策として、電流検出ICの出力を分圧してADCに取り込むことになりそうです。
初めからゲインが20倍の電流検出ICを買えば、1A時に2Vの出力なので問題なかったのに…。
続きは、また後日考えます。
2015年9月2日水曜日
dsPICでmicroSDからwavファイルの再生
dsPICでmicroSDからPCM音源のWAVファイルを再生してみた
SD :microSDHC Class10 (メーカー: GREEN HOUSE)
再生ファイル : Fs = 44.1kHz 、分解能16bit、ステレオ音源
クロック源 : 外付けの発信器未使用 完全に内部発振のみ
また、今回はとにかくWAVを再生することだけに専念したので、連続して音楽を再生するようなシステムや、フォルダ分けされた階層などは非対応です。
そういう意味では、MDDFSの使い方をしっかり理解しないと当然エラーで悩みます。
microSDの読み書きについて過去に記事をかいたので、詳しくはそちらを確認してください。
URLはこちら
それも、これはただのDAコンバーターではなく、AudioDACというオーディオ用のDACです。
そのため、使い方は基本的に固定されています。
手順をまとめます。
これにより、アップサンプリング時に発生するノイズを高音域に追いやる事ができるそうです。
これがAudioDACのブロック図になります。
中央にクロックとして[ACLK] が入力されています。
その先、[CLK DIV] で[ACLK]が分周されます。 この周波数を[DACCLK]とよび、音声のサンプリング周波数の256倍に設定する必要があります。
[ACLK]はどのように計算するかというと、それはクロックの設定についてブロック図を確認します。
(文字がマーカーで青く強調されてるのは、ミスですので気にしないでください。)
ブロック図右下のほうを見ると、[DAC] へ伸びる矢印があり、そこに [ACLK]と書いてあります。
今回は、内部発振を使いたいので、内部発振から生成可能なのは一番近くにある [Fosc] です。
SELACK で Foscを選択します。
SELACKというレジスタが有るわけではないのですが、設定方法はプログラム中にかいてりますので、ご確認ください。
また、Foscの設定方法もプログラム中に書いてありますが、作成中に発見した問題があります。
PLLは、M、 N1、 N2の値をレジスタで設定することで求まります。
Fosc = 7.3728MHz / N1 * M / N2
上のような式になるのですが、 N2が2より大きい場合にDAC割込みの周期に狂いが出る可能性があるということです。
私のプログラムに問題がある可能性が当然あるのですが、N2を2に設定することをお薦めします。
不思議なのは、システムクロック (Fcy = Fosc / 2)は正しく、ディレイ関数も問題なく動作するのに、DAC割込みのみが狂うという点です。
ちなみにこちらが、PLLでのクロック生成についてのブロック図です。
これとプログラムを照らしあわせて、計算方法をご確認ください。
今回私は夫々の割込みを丁寧に書きましたが、多くの方は片方の割込み処理内で両チャネル分の処理を書いているようです。
それでも動く上に、プログラムの処理も減るのでメモリの削減にはなると思います。
URLはこちら
読み解いて真似することもできると思いますが、特に注意するべき点はバッファを2つ用意する点です。
バッファがひとつしかないと、次のデータを読み込む間無音になってしまうため、一方のバッファが再生中もう一方のバッファは読み込みをする仕組みになっています。
AMPは HT82V739です。
非常に音が大きいので近所迷惑にならないよう…。
これは、電源ラインにフィルタを入れれば恐らく解決すると思いますが、現段階では未解決です。
解決したら報告します。
1 仕様
マイコン : dsPIC33FJ64GP802SD :microSDHC Class10 (メーカー: GREEN HOUSE)
再生ファイル : Fs = 44.1kHz 、分解能16bit、ステレオ音源
クロック源 : 外付けの発信器未使用 完全に内部発振のみ
また、今回はとにかくWAVを再生することだけに専念したので、連続して音楽を再生するようなシステムや、フォルダ分けされた階層などは非対応です。
2 実際に音楽を再生している様子
基板で動いた。電源のノイズは若干ある pic.twitter.com/8qLFZPDGdi
— とりまあ@マルチコプター製作中 (@Trimming_ly) 2015, 8月 27
3 MDDFSでのmicroSDの操作
MDDFSとはMicroChiop社が提供している、PIC向けのファイルシステムで、これを使うことでFATに関する知識が要らなくなる。そういう意味では、MDDFSの使い方をしっかり理解しないと当然エラーで悩みます。
microSDの読み書きについて過去に記事をかいたので、詳しくはそちらを確認してください。
4 AudioDACでのDAC出力
dsPIC33FJ64GP802は、分解能16bitのDAコンバーターを内臓しています。それも、これはただのDAコンバーターではなく、AudioDACというオーディオ用のDACです。
そのため、使い方は基本的に固定されています。
手順をまとめます。
4-1 オーバーサンプリングについて
このAudioDACでは、デジタル補間フィルタを備えており、256倍のオーバーサンプリングを行い補完データを作成します。これにより、アップサンプリング時に発生するノイズを高音域に追いやる事ができるそうです。
これがAudioDACのブロック図になります。
中央にクロックとして[ACLK] が入力されています。
その先、[CLK DIV] で[ACLK]が分周されます。 この周波数を[DACCLK]とよび、音声のサンプリング周波数の256倍に設定する必要があります。
4-2 DACクロックの計算方法
[ACLK]はどのように計算するかというと、それはクロックの設定についてブロック図を確認します。(文字がマーカーで青く強調されてるのは、ミスですので気にしないでください。)
ブロック図右下のほうを見ると、[DAC] へ伸びる矢印があり、そこに [ACLK]と書いてあります。
今回は、内部発振を使いたいので、内部発振から生成可能なのは一番近くにある [Fosc] です。
SELACK で Foscを選択します。
SELACKというレジスタが有るわけではないのですが、設定方法はプログラム中にかいてりますので、ご確認ください。
また、Foscの設定方法もプログラム中に書いてありますが、作成中に発見した問題があります。
PLLは、M、 N1、 N2の値をレジスタで設定することで求まります。
Fosc = 7.3728MHz / N1 * M / N2
上のような式になるのですが、 N2が2より大きい場合にDAC割込みの周期に狂いが出る可能性があるということです。
私のプログラムに問題がある可能性が当然あるのですが、N2を2に設定することをお薦めします。
不思議なのは、システムクロック (Fcy = Fosc / 2)は正しく、ディレイ関数も問題なく動作するのに、DAC割込みのみが狂うという点です。
ちなみにこちらが、PLLでのクロック生成についてのブロック図です。
これとプログラムを照らしあわせて、計算方法をご確認ください。
4-3 DAC割込み関数の記述について
DAC割込みは、ライトチャネルとレフトチャネルそれぞれの割込みがあります。今回私は夫々の割込みを丁寧に書きましたが、多くの方は片方の割込み処理内で両チャネル分の処理を書いているようです。
それでも動く上に、プログラムの処理も減るのでメモリの削減にはなると思います。
5.プログラム
こちらに今回使用したファイルをひと通り載せておきました。URLはこちら
読み解いて真似することもできると思いますが、特に注意するべき点はバッファを2つ用意する点です。
バッファがひとつしかないと、次のデータを読み込む間無音になってしまうため、一方のバッファが再生中もう一方のバッファは読み込みをする仕組みになっています。
6.回路図
AudioDACは、さすがAudio用、差動出力になっているのですが、今回は音をだすことだけをまず確認したかったので、ステレオ、ポジティブ出力のみで音を出してみました。AMPは HT82V739です。
非常に音が大きいので近所迷惑にならないよう…。
7.問題点
電源のノイズが乗っているようで、出力に「ぽうぽうぽうぽうぽう」という方形波のノイズが入ります。これは、電源ラインにフィルタを入れれば恐らく解決すると思いますが、現段階では未解決です。
解決したら報告します。
8.参考文献+ご協力くださった方
・フルート吹きのMIDI工房 様
・picfun 様
・Twitter 、FaceBookの皆様
WAVプレイヤーの進捗…
この記事は備忘録的、進捗報告です。
作品は未完成かつプログラムも作成過程ですので、ご了承ください。
- microSDカードの読み書き
- AudioDACの動作
この2つが無事成功しました。
前回、AudioDACのプログラムが動作しないという記事を書いて終わりましたが、こちらのプログラムではDACが動作するようになっているはずなのでこちらを参考に。
(DAC動作までご協力くださった師匠にこの場をお借りしてお礼申し上げます。有難うございます。)
(DAC動作までご協力くださった師匠にこの場をお借りしてお礼申し上げます。有難うございます。)
SD読み書きプログラムにAudioADCプログラムを移植
ここで問題が発生。RAM領域がいっぱいになってしまいました。
原因は正弦波を出力するテストモードが大容量であった事。
分解能は16bitで128ポイントの正弦波を予め計算して配列に格納していましたが… これは排除します。
結果、無事AudioDACは動作しました。
次のプログラムがそのプログラムです。
ひと通りの初期化(DACの有効化など)をするとwhileの無限ループに入り、その中でDAC割込みがただただ無限に発生します。
RA0ピンをみれば44.1kHzで割込みが入っていることが確認出来ます。
/*****************************************************************************
Microchip Memory Disk Drive File System
*****************************************************************************
* FileName: main_15_08_11_01.c
* Dependencies: FSIO.h
* Processor: dsPIC33E, PIC24E
* dsPIC33F64GP802
* Compiler: C30
* Company: Microchip Technology, Inc.
*
* Note: This file is included to give you a basic demonstration of how the
* functions in this library work. Prototypes for these functions,
* along with more information about them, can be found in FSIO.h
*****************************************************************************/
//DOM-IGNORE-BEGIN
/********************************************************************
Change History:
Rev Description
---- -----------------------
1.3.4 Initial Revision
********************************************************************/
//DOM-IGNORE-END
/*******************************************************************************
//NOTE : DISABLE MACRO "SUPPORT_LFN" IN "FSconfig.h" FILE TO WORK WITH THIS DEMO
EFFECTIVELY. DISABLING "SUPPORT_LFN" WILL SAVE LOT OF MEMORY FOR THIS
DEMO.
********************************************************************************/
/******************************************************************************
* プログラム内容
*
* MDDFSによるmicroSDの読み書きプログラムに44.1kHzのDAC割込みが入るプログラムを
* 付け足したプログラム。
* このプログラムを実行すると44.1kHzのDAC割込みが常に入り、割込み関数内でRA0ピンを
* 反転させている。
******************************************************************************/
/***********************************************************************
* プログラム全体にかかわる、初期設定
***********************************************************************/
/********************************
* ヘッダー と 定数
********************************/
#define FCY 39628800UL
#define PI 3.14159265359
#define SIN(x) sin(PI/180*x)
#include <xc.h>
#include <math.h>
#include <libpic30.h>
//#include "./p33FJ64GP802.h"
#include "./FSIO.h"
/********************************
* コンフィギュレーション
********************************/
#pragma config BWRP = WRPROTECT_OFF
#pragma config BSS = NO_BOOT_CODE
#pragma config RBS = NO_BOOT_RAM
#pragma config SSS = NO_SEC_CODE
#pragma config GWRP = OFF
#pragma config GSS = OFF
#pragma config FNOSC = FRCPLL
#pragma config IESO = OFF
#pragma config POSCMD = NONE
#pragma config OSCIOFNC = ON
#pragma config FCKSM = CSECMD
#pragma config FWDTEN = OFF
#pragma config FPWRT = PWR16
#pragma config ALTI2C = ON
#pragma config ICS = PGD1
#pragma config JTAGEN = OFF
/********************************
* グローバル変数
********************************/
const char sendBuffer[] = "Hello MDDFS";
char send2[] = "2";
char receiveBuffer[50];
/********************************
* ユーザー定義関数 プロトタイプ
********************************/
void init_clock(void); // クロックの初期設定
void init_pps(void); // ペリフェラルピンセレクトのピン設定
void init_gpio(void); // 入出力ピンの設定
void init_dac(void); // AudioDACの初期設定
/***********************************************************************
* 関 数 群
***********************************************************************/
/********************************
* メイン関数
********************************/
int main (void)
{
FSFILE * pointer;
// Activate the RTCC module
__builtin_write_RTCWEN();
Nop();
Nop();
RCFGCALbits.RTCPTR0 = 1;
RCFGCALbits.RTCPTR1 = 1;
// Set it to the correct time
// These values won't be accurate
RTCVAL = 0x0011;
RTCVAL = 0x0815;
RTCVAL = 0x0108;
RTCVAL = 0x2137;
RCFGCAL = 0x8000;
init_clock();
init_pps();
init_gpio();
init_dac();
while(1);
while (!MDD_MediaDetect());
// Initialize the library
while (!FSInit());
/*
// Open file 1 in read mode
pointer = FSfopen ("FILE1.TXT", "r");
if (pointer == NULL){
//ERROR();
while(1);
}
// Read one "r_byte"-byte object
r_byte = 5; // 1バイト読み取り
if(FSfread (receiveBuffer, r_byte, 1, pointer) != 1){
//ERROR();
while(1);
}
// Check if this is the end of the file- it shouldn't be
if (FSfeof (pointer)){
//ERROR();
while(1);
}
// Close the file
if (FSfclose (pointer)){
//ERROR();
while(1);
}
__delay_ms(1000);
if(receiveBuffer[0] == 'a') LATAbits.LATA0 = 1;
__delay_ms(1000);
if(receiveBuffer[1] == 'b') LATAbits.LATA1 = 1;
__delay_ms(1000);
if(receiveBuffer[2] == 'c') LATAbits.LATA2 = 1;
__delay_ms(1000);
if(receiveBuffer[3] == 'd') LATAbits.LATA3 = 1;
__delay_ms(1000);
if(receiveBuffer[4] == 'e') LATAbits.LATA4 = 1;
*/
// Create a file
pointer = FSfopen ("FILE2.TXT", "w");
if (pointer == NULL){
while(1);
}
// Write 21 1-byte objects from sendBuffer into the file
if (FSfwrite (sendBuffer, 1, sizeof(sendBuffer), pointer) != sizeof(sendBuffer)){
while(1);
}
// FSftell returns the file's current position
if (FSftell (pointer) != sizeof(sendBuffer)){
while(1);
}
// FSfseek sets the position one byte before the end
// It can also set the position of a file forward from the
// beginning or forward from the current position
if (FSfseek(pointer, 1, SEEK_END)){
while(1);
}
// Close the file
if (FSfclose (pointer)){
while(1);
}
while(1);
}
/********************************
* ペリフェラルピンセレクトの設定
* 主にSPIピンの設定
********************************/
void init_pps()
{
/*
* ----Initialize Peripheral Pin Select of SPI----
* <入力の割り当て>
* [入力名] [機能名] [レジスタ] [コンフィグレーションビット]
* SPI1データ入力 SDI1 RPINR20 SD1R
* SPI1クロック入力 SCK1 RPINR20 SCK1R
*
* <出力の割り当て>
* [出力名] [機能名] [RPnR]
* RPnをSPI1データ出力に接続 SDO1 00111
* RPnをSPI1クロック出力に接続 SCK1OUT 01000
*
* CS(Chip Select) は RB5
*/
TRISBbits.TRISB5 = 0; // CSは出力端子
/**************************************************
* Un lock Registers *
**************************************************/
__builtin_write_OSCCONL(OSCCON & 0xDF);
/**************************************************
* Configure Input functions *
**************************************************/
// Assign "SDI1" To Pin "RP2" (RB2)
RPINR20bits.SDI1R = 2;
// Assign "SCK1" To Pin "RP3" dsPICがマスターだから使わないかも。
//RPINR20bits.SCK1R = 3;a
/**************************************************
* Configure Output functions *
**************************************************/
// Assign "SDO1" To Pin "RP3"
RPOR1bits.RP3R = 0b00111;
// Assign "SCK1OUT" To Pin "RP4"
RPOR2bits.RP4R = 0b01000;
/**************************************************
* Lock Registers *
**************************************************/
__builtin_write_OSCCONL(OSCCON | 0x40);
}
/********************************
* 汎用入出力の設定
********************************/
void init_gpio()
{
AD1PCFGL = 0xFFFF;
TRISA = 0x00;
TRISBbits.TRISB2 = 1; // RB2(SDI1) is in pin
TRISBbits.TRISB3 = 0; // RB3(SDO1) is out pin
TRISBbits.TRISB4 = 0; // RB4(CKOUT)is out pin
LATA = 0x0000; // PORTAを全て0で初期化
LATB = 0x0000;
}
/********************************
* 動作クロックの設定
********************************/
void init_clock()
{
// Initialize and configure Primary PLL, and enable Secondary Oscillator
// Fvco = 7.3728MHz / N1 * M = 158.515MHz
// Fosc = Fvco / N2 = 158.515MHz / 2 = 79.258MHz
// Fcy = Fosc / 2 = 39.629MHz
PLLFBDbits.PLLDIV = 41; // M = 43
CLKDIVbits.PLLPOST = 0; // N2 = 2
CLKDIVbits.PLLPRE = 0; // N1 = 2
CLKDIVbits.ROI = 0; // Interrupts have no effect on the DOZEN bit
CLKDIVbits.DOZE = 0; // Fcy / 1
CLKDIVbits.DOZEN = 0; // disable DOZE
CLKDIVbits.FRCDIV = 0; // FRC/1(default)
ACLKCONbits.AOSCMD = 0b00; // 補助オシレータ(Aosc)を無効にする(規定値だけど)
// 必然的に補助クロックはPLL出力を参照
ACLKCONbits.APSTSCLR = 0b111;
}
/********************************
* Audio DACの設定
********************************/
void init_dac()
{
DAC1STATbits.ROEN = 1; // Right Channel DAC Output Enabled
DAC1STATbits.LOEN = 1; // Left Channel DAC Output Enabled
DAC1STATbits.RITYPE = 0; // Right Channel Interrupt if FIFO is empty
DAC1STATbits.LITYPE = 0; // Left Channel Interrupt if FIFO is empty
// DAC1STATbits.LMVOEN = 0; // Midpoint DAC output is anabled
// DAC1STATbits.RMVOEN = 0; // Midpoint DAC output is anabled
DAC1CONbits.AMPON = 0; // Amplifier Disabled During Sleep and Idle Modes
// Fs = 44.1kHz
// Fs(kHz) * 256 = 11.2896MHz
// Fvco(MHz) / 11.2896MHz = 14.041 ≒ 14
DAC1CONbits.DACFDIV = 13; // Divide Clock by 14
DAC1CONbits.FORM = 0; // Data Format is Unsigned
DAC1DFLT = 0x8000; // Default Value set to Midpoint when FORM
IFS4bits.DAC1RIF = 0; // Clear Right Channel Interrupt Flag
IFS4bits.DAC1LIF = 0; // Clear Left Channel Interrupt Flag
IEC4bits.DAC1RIE = 1; // Right Channel Interrupt Enabled
IEC4bits.DAC1LIE = 1; // Left Channel Interrupt Enabled
DAC1CONbits.DACEN = 1; // DAC1 Module Enabled
}
/********************************
* Audio DAC 割込み関数
********************************/
//-- ライトチャネル
void __attribute__((interrupt, no_auto_psv))_DAC1RInterrupt(void)
{
LATAbits.LATA0 = ~LATAbits.LATA0;
IFS4bits.DAC1RIF = 0; // Clear Right Channel Interrupt Flag
DAC1RDAT = 0x8000; // User Code to Write to FIFO Goes Here
}
//-- レフトチャネル
void __attribute__((interrupt, no_auto_psv))_DAC1LInterrupt(void)
{
IFS4bits.DAC1LIF = 0; // Clear Right Channel Interrupt Flag
DAC1LDAT = 0x8000; // User Code to Write to FIFO Goes Here
}
wavファイルからデータチャンクを探す
wavファイルのファイル構造について、書籍やネットで色々見ました。しかししっかり頭には入っていません。
ひとまずわかった事
分解能: 16bit or 8bit
チャンネル: ステレオ or モノラル
サンプリングレート: 44.1kHz or 48kHz
これらの可能性があり、ファイルのヘッダに書かれているようです。
これらを考慮するとDACのクロック設定を弄る必要が出てしまい、手間がかかるので
分解能: 16bit
チャンネル: ステレオ
サンプリングレート: 44.1kHz
という条件のファイルを用意することにしました。
① ファイルから4キロバイトのデータをバッファに読み込む
② memmem関数を作り、dataというデータを探す
③ dataが見つかった場所+4バイト(データサイズを表す領域)の先にポインタをセット
④ 順次データを読み出し
このような手順を取ります。
参考サイト
・memmem関数の作成について(URL)教えてgoo!より、jacta様の解答がそのまま使えそうだったので使わせて頂きました。
2015年8月2日日曜日
dsPIC33FJ64GP802 16bit DAC 動作確認
備忘録として作業過程をメモしつつまとめていきます。
この記事は現段階で未解決です
今回私は次の条件でDACを使います。
・外付発振器をつかわ
ず、全て内蔵FRCとPLLで使う
・wavを適当に再生できれば良いので差動出力はポジティブ出力のみを使用
右チャネル・左チャネルとそれぞれ16bitのFIFOがあり、そこにデータをセットすることで自動でアナログ出力が出る。
出力されるとFIFOが空になり、また割込みが入る。
この割込み周期をDACCLKとする。
DACCLKは外付けの補助クロックをつけ、DAC専用とすれば非常に簡単に出来そうだけど、回路をなるべく簡素にしたので内蔵FRCPLLを使う。
とりあえずクロックの設定ができてんのか、超高速Lチカをしてみる。
次のプログラムは、まだ必要ないDACあたりの設定もかなり書かれているけど、DACの初期化を行うinit_dac()はコメントアウトしてあるのでDACは動作してない。
DAC割込み処理とかも無視してください。
RA0をオシロで確認すると1kHz周期で出力が反転しているのでFcyの計算はあっていると考えられます。
ここで、次のブロック図を確認してみる。
一番下、右端にACLKという出力がある。これをいくらか分周したものがADCLKとなる。
この出力を登っていくと、Auxiliary Oscillator にたどり着くがちょっと登りすぎて、その二つくらい下のマルチプレクサちゃんに Fvco という選択肢が与えられてる。
これは、まさしく先ほどLチカをした時に使ったシステムクロックFcyを作る過程の信号である。
1kHzのLチカが出来たってことはこれもあっているはず。
・SELACLK
これはデフォルトで’0’です。よってPLL出力であるFvcoがマルチプレクサの出力となります。
・APSTSCLR
分周器です。こいつは 0b111 を指定することで 分周比が1となります(÷1)。
よって、ACLK DACはFvcoのまま、ということになります。
Fvcoは次の画像のように求まります。
Fvco = FIN / N1 × M
先ほどのプログラムの値だと
Fvco = 7.3728MHz / 2 × 53 = 195.3792MHz
となる。
AudioDACのブロック図を見てみる。
中央、左の方を見るとACLKの入力がある。
その次に分周器 CLK DIVがある。
この分周後の周波数、DACCLKは
DACCLK = Fs × 256 とある。
DACCLK = 44.1kHz×256 = 11.2896MHz
DACCLK = ACLK / CLK DIV
11.2896MHz = 195.3792MHz / CLK DIV
CLK DIV = 195.3792MHz / 11.2896MHz = 17.31 ≒ 17分周
DACFDIV = 16に設定すれば DACFDIV + 1の分周比となる。
これで、DACCLKの設定は完了のはず。
また、
Fosc = Fvco / N2
また Fosc < 80MHz という条件があるので
PLLPOST = 1 (N2 : 4分周) とし、
Fosc = 195.3792MHz / 4 = 48.8098MHz
Fcy = Fosc / 2
となる。
8行↑くらいの説明からは、もはやDACCLKには無関係の話であるはず。(ブロック図を見る限り)
では、DAC割込みの周期を見てみる。
プログラムは先程のプログラムで init_dac() のコメントアウトを外しただけ。
早速、RA0のポート変化の周期をみたら、22.388kHzでした。
目的の44.1kHzのやく半分です。
なぜ、分周比が上がってるのでしょうか。
17分周をその半分にすれば44.1kHzは作れますが、スッキリしない。
現状ではわからないことがわかった。
この記事は現段階で未解決です
今回私は次の条件でDACを使います。
・外付発振器をつかわ
ず、全て内蔵FRCとPLLで使う
・wavを適当に再生できれば良いので差動出力はポジティブ出力のみを使用
右チャネル・左チャネルとそれぞれ16bitのFIFOがあり、そこにデータをセットすることで自動でアナログ出力が出る。
出力されるとFIFOが空になり、また割込みが入る。
この割込み周期をDACCLKとする。
DACCLKは外付けの補助クロックをつけ、DAC専用とすれば非常に簡単に出来そうだけど、回路をなるべく簡素にしたので内蔵FRCPLLを使う。
とりあえずクロックの設定ができてんのか、超高速Lチカをしてみる。
次のプログラムは、まだ必要ないDACあたりの設定もかなり書かれているけど、DACの初期化を行うinit_dac()はコメントアウトしてあるのでDACは動作してない。
DAC割込み処理とかも無視してください。
/*
/*
* File: main_15.08.02.01.c
* Author: kota
*
* Created on 2015/07/17, 17:15
*/
/***********************************************************************
* プログラム全体にかかわる、初期設定
***********************************************************************/
/********************************
* ヘッダーのインクルード
********************************/
#define FCY 24413125UL
#include <libpic30.h>
#include <xc.h>
/********************************
* コンフィギュレーション
********************************/
#pragma config BWRP = WRPROTECT_OFF
#pragma config BSS = NO_BOOT_CODE
#pragma config RBS = NO_BOOT_RAM
#pragma config SSS = NO_SEC_CODE
#pragma config GWRP = OFF
#pragma config GSS = OFF
#pragma config FNOSC = FRCPLL
#pragma config IESO = OFF
#pragma config POSCMD = NONE
#pragma config OSCIOFNC = ON
#pragma config FCKSM = CSECMD
#pragma config FWDTEN = OFF
#pragma config FPWRT = PWR16
#pragma config ALTI2C = ON
#pragma config ICS = PGD1
#pragma config JTAGEN = OFF
/********************************
* ユーザー定義関数 プロトタイプ
********************************/
void init_gpio(void);
void init_clock(void);
void init_dac(void);
/***********************************************************************
* 関 数 群
***********************************************************************/
/********************************
* メイン関数
********************************/
int main(void) {
init_clock();
init_gpio();
//init_dac();
while(1){
LATAbits.LATA0 = 1;
__delay_ms(1);
LATAbits.LATA0 = 0;
__delay_ms(1);
}
return 0;
}
/********************************
* 動作クロックの設定
********************************/
void init_clock()
{
CLKDIVbits.ROI = 0; // Interrupts have no effect on the DOZEN bit
CLKDIVbits.DOZE = 0; // Fcy / 1
CLKDIVbits.DOZEN = 0; // disable DOZE
CLKDIVbits.FRCDIV = 0; // FRC/1(default)
// Initialize and configure Primary PLL, and enable Secondary Oscillator
PLLFBDbits.PLLDIV = 51; // M = 53
CLKDIVbits.PLLPOST = 1; // N2 = 4
CLKDIVbits.PLLPRE = 0; // N1 = 2
// Fvco = 7.3728MHz / N1 * M = 195.3792MHz
// Fosc = Fvco / N2 = 48.845MHz
// Fcy = Fosc / 2 = 24.422MHz
ACLKCONbits.SELACLK = 0; // PLL出力(Fvco参照)
//ACLKCONbits.ASRCSEL = 1; // DAC用クロックは主クロックを使用
ACLKCONbits.APSTSCLR = 0b111;
}
/********************************
* GPIOの設定
********************************/
void init_gpio()
{
AD1PCFGL = 0xFFFF; // アナログ入出力をオフに
TRISA = 0x0000; // RA0-
LATA = 0x0000; // 出力を0に初期化
}
/********************************
* Audio DACの設定
********************************/
void init_dac()
{
DAC1STATbits.ROEN = 1; // Right Channel DAC Output Enabled
DAC1STATbits.LOEN = 1; // Left Channel DAC Output Enabled
DAC1STATbits.RITYPE = 0; // Right Channel Interrupt if FIFO is empty
DAC1STATbits.LITYPE = 0; // Left Channel Interrupt if FIFO is empty
// DAC1STATbits.LMVOEN = 0; // Midpoint DAC output is anabled
// DAC1STATbits.RMVOEN = 0; // Midpoint DAC output is anabled
DAC1CONbits.AMPON = 0; // Amplifier Disabled During Sleep and Idle Modes
// Fs = 44.1kHz
// Fs(kHz) * 256 = 11.2896MHz
// Fvco(MHz) / 11.2896MHz = 17.31 ≒ 17
DAC1CONbits.DACFDIV = 16; // Divide Clock by 17
DAC1CONbits.FORM = 0; // Data Format is Unsigned
DAC1DFLT = 0x8000; // Default Value set to Midpoint when FORM
IFS4bits.DAC1RIF = 0; // Clear Right Channel Interrupt Flag
IFS4bits.DAC1LIF = 0; // Clear Left Channel Interrupt Flag
IEC4bits.DAC1RIE = 1; // Right Channel Interrupt Enabled
IEC4bits.DAC1LIE = 1; // Left Channel Interrupt Enabled
DAC1CONbits.DACEN = 1; // DAC1 Module Enabled
}
/********************************
* Audio DAC 割込み関数
********************************/
//-- ライトチャネル
void __attribute__((interrupt, no_auto_psv))_DAC1RInterrupt(void)
{
IFS4bits.DAC1RIF = 0; // Clear Right Channel Interrupt Flag
LATAbits.LATA0 = ~LATAbits.LATA0;
DAC1RDAT = 0x0000; // User Code to Write to FIFO Goes Here
}
//-- レフトチャネル
void __attribute__((interrupt, no_auto_psv))_DAC1LInterrupt(void)
{
IFS4bits.DAC1LIF = 0; // Clear Right Channel Interrupt Flag
DAC1LDAT = 0x8000; // User Code to Write to FIFO Goes Here
}
RA0をオシロで確認すると1kHz周期で出力が反転しているのでFcyの計算はあっていると考えられます。
ここで、次のブロック図を確認してみる。
一番下、右端にACLKという出力がある。これをいくらか分周したものがADCLKとなる。
この出力を登っていくと、Auxiliary Oscillator にたどり着くがちょっと登りすぎて、その二つくらい下のマルチプレクサちゃんに Fvco という選択肢が与えられてる。
これは、まさしく先ほどLチカをした時に使ったシステムクロックFcyを作る過程の信号である。
1kHzのLチカが出来たってことはこれもあっているはず。
・SELACLK
これはデフォルトで’0’です。よってPLL出力であるFvcoがマルチプレクサの出力となります。
・APSTSCLR
分周器です。こいつは 0b111 を指定することで 分周比が1となります(÷1)。
よって、ACLK DACはFvcoのまま、ということになります。
Fvcoは次の画像のように求まります。
Fvco = FIN / N1 × M
先ほどのプログラムの値だと
Fvco = 7.3728MHz / 2 × 53 = 195.3792MHz
となる。
AudioDACのブロック図を見てみる。
中央、左の方を見るとACLKの入力がある。
その次に分周器 CLK DIVがある。
この分周後の周波数、DACCLKは
DACCLK = Fs × 256 とある。
DACCLK = 44.1kHz×256 = 11.2896MHz
DACCLK = ACLK / CLK DIV
11.2896MHz = 195.3792MHz / CLK DIV
CLK DIV = 195.3792MHz / 11.2896MHz = 17.31 ≒ 17分周
DACFDIV = 16に設定すれば DACFDIV + 1の分周比となる。
これで、DACCLKの設定は完了のはず。
また、
Fosc = Fvco / N2
また Fosc < 80MHz という条件があるので
PLLPOST = 1 (N2 : 4分周) とし、
Fosc = 195.3792MHz / 4 = 48.8098MHz
Fcy = Fosc / 2
となる。
8行↑くらいの説明からは、もはやDACCLKには無関係の話であるはず。(ブロック図を見る限り)
では、DAC割込みの周期を見てみる。
プログラムは先程のプログラムで init_dac() のコメントアウトを外しただけ。
/*
* File: main_15.08.02.01.c
* Author: Chatteringok
*
* Created on 2015/07/17, 17:15
*/
/***********************************************************************
* プログラム全体にかかわる、初期設定
***********************************************************************/
/********************************
* ヘッダーのインクルード
********************************/
#define FCY 24413125UL
#include <libpic30.h>
#include <xc.h>
/********************************
* コンフィギュレーション
********************************/
#pragma config BWRP = WRPROTECT_OFF
#pragma config BSS = NO_BOOT_CODE
#pragma config RBS = NO_BOOT_RAM
#pragma config SSS = NO_SEC_CODE
#pragma config GWRP = OFF
#pragma config GSS = OFF
#pragma config FNOSC = FRCPLL
#pragma config IESO = OFF
#pragma config POSCMD = NONE
#pragma config OSCIOFNC = ON
#pragma config FCKSM = CSECMD
#pragma config FWDTEN = OFF
#pragma config FPWRT = PWR16
#pragma config ALTI2C = ON
#pragma config ICS = PGD1
#pragma config JTAGEN = OFF
/********************************
* ユーザー定義関数 プロトタイプ
********************************/
void init_gpio(void);
void init_clock(void);
void init_dac(void);
/***********************************************************************
* 関 数 群
***********************************************************************/
/********************************
* メイン関数
********************************/
int main(void) {
init_clock();
init_gpio();
init_dac();
while(1){
}
return 0;
}
/********************************
* 動作クロックの設定
********************************/
void init_clock()
{
CLKDIVbits.ROI = 0; // Interrupts have no effect on the DOZEN bit
CLKDIVbits.DOZE = 0; // Fcy / 1
CLKDIVbits.DOZEN = 0; // disable DOZE
CLKDIVbits.FRCDIV = 0; // FRC/1(default)
// Initialize and configure Primary PLL, and enable Secondary Oscillator
PLLFBDbits.PLLDIV = 51; // M = 53
CLKDIVbits.PLLPOST = 1; // N2 = 4
CLKDIVbits.PLLPRE = 0; // N1 = 2
// Fvco = 7.3728MHz / N1 * M = 195.3792MHz
// Fosc = Fvco / N2 = 48.845MHz
// Fcy = Fosc / 2 = 24.422MHz
ACLKCONbits.SELACLK = 0; // PLL出力(Fvco参照)
ACLKCONbits.APSTSCLR = 0b111;
}
/********************************
* GPIOの設定
********************************/
void init_gpio()
{
AD1PCFGL = 0xFFFF; // アナログ入出力をオフに
TRISA = 0x0000; // RA0-
LATA = 0x0000; // 出力を0に初期化
}
/********************************
* Audio DACの設定
********************************/
void init_dac()
{
DAC1STATbits.ROEN = 1; // Right Channel DAC Output Enabled
DAC1STATbits.LOEN = 1; // Left Channel DAC Output Enabled
DAC1STATbits.RITYPE = 0; // Right Channel Interrupt if FIFO is empty
DAC1STATbits.LITYPE = 0; // Left Channel Interrupt if FIFO is empty
// DAC1STATbits.LMVOEN = 0; // Midpoint DAC output is anabled
// DAC1STATbits.RMVOEN = 0; // Midpoint DAC output is anabled
DAC1CONbits.AMPON = 0; // Amplifier Disabled During Sleep and Idle Modes
// Fs = 44.1kHz
// Fs(kHz) * 256 = 11.2896MHz
// Fvco(MHz) / 11.2896MHz = 17.31 ≒ 17
DAC1CONbits.DACFDIV = 16; // Divide Clock by 17
DAC1CONbits.FORM = 0; // Data Format is Unsigned
DAC1DFLT = 0x8000; // Default Value set to Midpoint when FORM
IFS4bits.DAC1RIF = 0; // Clear Right Channel Interrupt Flag
IFS4bits.DAC1LIF = 0; // Clear Left Channel Interrupt Flag
IEC4bits.DAC1RIE = 1; // Right Channel Interrupt Enabled
IEC4bits.DAC1LIE = 1; // Left Channel Interrupt Enabled
DAC1CONbits.DACEN = 1; // DAC1 Module Enabled
}
/********************************
* Audio DAC 割込み関数
********************************/
//-- ライトチャネル
void __attribute__((interrupt, no_auto_psv))_DAC1RInterrupt(void)
{
IFS4bits.DAC1RIF = 0; // Clear Right Channel Interrupt Flag
LATAbits.LATA0 = ~LATAbits.LATA0;
DAC1RDAT = 0x0000; // User Code to Write to FIFO Goes Here
}
//-- レフトチャネル
void __attribute__((interrupt, no_auto_psv))_DAC1LInterrupt(void)
{
IFS4bits.DAC1LIF = 0; // Clear Right Channel Interrupt Flag
DAC1LDAT = 0x8000; // User Code to Write to FIFO Goes Here
}
早速、RA0のポート変化の周期をみたら、22.388kHzでした。
目的の44.1kHzのやく半分です。
なぜ、分周比が上がってるのでしょうか。
17分周をその半分にすれば44.1kHzは作れますが、スッキリしない。
現状ではわからないことがわかった。
2015年7月17日金曜日
dsPIC33FJ64GP802でmicroSDの読み書きをしてみた
MDDFS (Microchip's Memory Disk Drive File System) を用いてmicroSDの操作をしました。
既に、MDDFSを用いた操作についていくつかのサイトでまとめられていますが、その時、その時のバージョンや環境での説明なので、手元にあるライブラリと異なる点が多々ありました。
その点混乱しないよう、違いがある可能性もあるよという言葉を添えながらまとめたいと思います。
では、極力箇条書きで説明していきます。
2015年3月23日月曜日
私の所属している研究会
ご無沙汰しております。
私は拓殖大学の造形美術研究会で会長を務めているのですが、そんなこともあって最近の作業報告は全部研究会のブログにて行っています。
あれからいろいろありました。
1.電光掲示板2号が大学内の文化局連合杯(プレゼン大会)で最優秀賞
2.工事担任者総合種合格
あれ、まあ大きく達成したことをあげると意外と対してないのですが一つのものを作る中で覚えることってかなり多いと思うのでブログもいろいろ書いていますよ。
ということで、ここが更新できない言い訳とブログの紹介でした。
リンクは↓↓です
http://takudai-zoukei.blogspot.jp/
私は拓殖大学の造形美術研究会で会長を務めているのですが、そんなこともあって最近の作業報告は全部研究会のブログにて行っています。
あれからいろいろありました。
1.電光掲示板2号が大学内の文化局連合杯(プレゼン大会)で最優秀賞
2.工事担任者総合種合格
あれ、まあ大きく達成したことをあげると意外と対してないのですが一つのものを作る中で覚えることってかなり多いと思うのでブログもいろいろ書いていますよ。
ということで、ここが更新できない言い訳とブログの紹介でした。
リンクは↓↓です
http://takudai-zoukei.blogspot.jp/
登録:
投稿 (Atom)









