dsPIC33CK256MP503 覚書①

カテゴリー: PIC  タグ:

dsPIC30FやdsPIC33EPから、dsPIC33CKへの移行の覚書です

36pin UQFNパッケージ

大きな違いは?

独断と偏見で恣意的な比較表

  dsPIC30F dsPIC33EP dsPIC33CK
MAX速度 30MIPS 70MIPS 100MIPS
Core   MUL,Divider MUL,Divider、4×割り込み退避エリア
汎用タイマ 16bit×3 16bit×3

32bit×1(CCPの汎用タイマ×2)、PTG×1

ADC

12bit 200Ksps

12bit×2+1(shared), 3.25Msps

12bit×2+1(shared), 3.25Msps

DAC non 12bit×2 12bit×3
PWM 16bit×3

HSPWM 16bit×3,up to 1.04㎱

HSPWM 16bit×8,up to 250ps

EEPROM 1Kbyte/non non non
other Function UART,SPI,I2C UART,SPI,I2C,PGA UART,SPI,I2C,CAN FD,QEI,CLC,DMA
電流 小小

 

要は、高速高機能かつ低消費電流です。

dsPIC33CK は汎用タイマとしてTimer1一つしかありませんが、名称がかわるだけでCCPのタイマを従来のTimer2、Timer3としてつかえます。またトリガタイミング発生用としてPTG(プログラマブルタイミングジェネレータ)があります。

また一つだけ(?)、dsPIC30Fにあって、dsPIC33CK/EP にないもの

EEPROM

です。

フラッシュで代用できないこともないですが、書き込み手順が面倒なのと、ICDで書き込みエリアを制限しないと、書き込み/デバッグのたびに消去されてしまうし、MPLABXで書き込みエリア制限の設定がなかなかうまくいかない、という状態です。

都合の悪いことに、うちで作ったdsPIC30Fの基板はしっかりと内蔵EEPROMをつかっているのである。外付けEEPROMは必須です。

 

◆各初期設定覚書◆

各コードには冗長なものが含まれています。各自の責任においてご使用ください。また、リファレンスマニュアルから抜粋したコードは、最初にレジスタクリアごにビットをセットしていますが、パワーオンではクリアされても、ウォッチドッグタイムアウトなどでは必要かもしれませんので、各自でセットすることをお勧めします。

クロックの設定

高速クロックは、Coreに供給するマスターと補助を設定する。今回は内蔵FRCを使う初期設定。

 
// *********************
//	クロック関係初期設定
// *********************
void initCLK(void)
{
	// Fpll=8MHz*1*125/5/1=200MHz,Fosc=100MHz,Fp=50MHz 50MIPS
	CLKDIVbits.PLLPRE = 1; // N1=1
	PLLFBDbits.PLLFBDIV = 125; // M = 125
	PLLDIVbits.POST1DIV = 5; // N2=5
	PLLDIVbits.POST2DIV = 1; // N3=1
	// Initiate Clock Switch to Primary Oscillator with PLL (NOSC=0b011)
	__builtin_write_OSCCONH(0x01);
	__builtin_write_OSCCONL(OSCCON | 0x01);
	// Wait for Clock switch to occur
	while (OSCCONbits.OSWEN!= 0);
	while (OSCCONbits.LOCK!=1);
	
	// AFVCO = 400MHz AFPLLO = 50MHz using 8 MHz internal FRC
	// Configure the source clock for the APLL
	ACLKCON1bits.FRCSEL = 1; // Select internal FRC as the clock source
	// Configure the APLL prescaler, APLL feedback divider, and both APLL postscalers.
	ACLKCON1bits.APLLPRE = 1; // N1 = 1
	APLLFBD1bits.APLLFBDIV = 50; // M = 50:400MHz(min)
	APLLDIV1bits.APOST1DIV = 2; // N2 = 5:200MHz
	APLLDIV1bits.APOST2DIV = 4; // N3 = 4:50MHz
	// Enable APLL
	ACLKCON1bits.APLLEN = 1;
}

EEPROMは外付け24LCxxにしよう

I2CはPPS適用外で、ピンアサイン固定。I2Cの初期化はdsPIC33EPとほぼ同じ。


 

void initI2C(void) {
    I2C1CONLbits.I2CEN = 1; // Enable I2C Module
    I2C1CONLbits.A10M = 0; // 7-bit slave address/data
    I2C1CONLbits.DISSLW = 1; // Slew rate control disabled
    I2C1BRG = 197; // 400kHz 
//  I2C1CONLbits.SEN = 1; 
}

汎用タイマTimer1の初期化(100usサイクル周期割り込み用)

// ************************
//	Timer1初期設定
// ************************
#define	TM1_CNT		625	// Fp=50MHz ∴N=50MHz/10KHz/8
void initTM(void) {
	TMR1 = 0;		// クリヤ TM1レジスタ
	PR1 = TM1_CNT;		// カウンタ値を設定
	T1CONbits.TON   = 0;	// タイマ停止後から始動
	T1CONbits.TCKPS = 1;	// プリスケーラ値 1:8
	T1CONbits.TGATE = 0;
	T1CONbits.TCS   = 0;	// Fp選択
	T1CONbits.TECS = 0x2;	// Fosc(no use ∴TCS=0)
	T1CONbits.TON = 1;	// TM1始動
}

IOポートとPPSを設定しておく

LATxはその都度変わります。PWM・I2CやCANFDなどの固定ペリフェラル以外はPPSで設定する。

// *** InitIO ***
void initIO(void) {
	LATA = 0x0;		// DD Con STBY OFF
	LATB = 0x0;
	LATC = 0x0;
	ANSELA= 0b0000000000001111;		// RA4:digital other:analog
	ANSELB= 0x0;					// RB all digital
	TRISA = 0b0000000000001111;		// RA0-1:AN,other out
	TRISB = 0b0000000010011100;		// RB2-4,7:input,other out
	CNPUA = 0b0000000000010000;		// RA2(SW2):pullup
	CNPDB = 0b1111110000000000;		// RB10-15:pulldown
	CNPUB = 0b0000000000000000;		// PB1-4:pullup
	CNPUC = 0b0000000000000001;		// PC0(SW1):pullup

	RPINR18bits.U1RXR = 52;			// RPIN18(U1RXT) -> PR52
	RPOR10bits.RP53R = 1;			// RP53 -> U1TX
}

いよいよADCの設定

ADCはPWMトリガ1でトリガをかけ、ADC1で割り込みをかける設定。

コードはDS70005213Gより適用。dsPIC33EPで必要だったADCのキャリブレーションは不要となっている。

 

// *** InitADC ***
void initADC(void) {
	ANSELA = 0x0003;				// AN0,1 analog
	ADCON1L = 0x0000;				// AD off

	ADCON1Hbits.FORM = 0;		// integer format
	ADCON1Hbits.SHRRES = 0x3;	// SHARED ADC:Integer,12bit

	ADCON2Hbits.SHRSAMC = 15;	// SHARED ADC Sample Time:17*TADCORE

	ADCON3Lbits.REFSEL = 0;		// AVdd as voltage reference

	ADCON3Hbits.CLKSEL = 0;		// Fosc(100MHz)を使う(ADCORExと組み合わせてMax70MHz))
	ADCON3Hbits.CLKDIV = 0;		// no clock divider

	ADCON4Hbits.C0CHS = 0;		// CORE0:AN0
	ADCON4Hbits.C1CHS = 0;		// CORE1:AN1

	ADCORE0Lbits.SAMC = 0;		// Core0 delay:TADCORE*2
	ADCORE1Lbits.SAMC = 0;		// Core1 delay:TADCORE*2
	ADCORE0Hbits.ADCS = 0;		// clock divider (1:2)
	ADCORE1Hbits.ADCS = 0;		// clock divider (1:2)
	ADCORE0Hbits.RES  = 3;		// Core 0 ADC Core in 12-bit resolution mode
	ADCORE1Hbits.RES  = 3;		// Core 1 ADC Core in 12-bit resolution mode
	ADMOD0Lbits.SIGN0 = 0;		// AN0/RA0
	ADMOD0Lbits.DIFF0 = 0;		// AN0/RA0
	ADMOD0Lbits.SIGN1 = 0;		// AN1/RA1
	ADMOD0Lbits.DIFF1 = 0;		// AN1/RA1
	ADMOD0Lbits.SIGN2 = 0;		// AN2/RB7
	ADMOD0Lbits.DIFF2 = 0;		// AN2/RB7
	ADIELbits.IE0 = 1;		// enable interrupt for AN0
	ADIELbits.IE1 = 1;		// enable interrupt for AN1
	_ADCAN0IF = 0;			// clear interrupt flag for AN0
	_ADCAN0IE = 1;			// enable interrupt for AN0
	_ADCAN1IF = 0;			// clear interrupt flag for AN1
	_ADCAN1IE = 0;			// enable interrupt for AN1

	ADTRIG0Lbits.TRGSRC0 = 0x4;	// AN0:PWM1 trigger
	ADTRIG0Lbits.TRGSRC1 = 0x4;	// AN1:PWM1 trigger

	ADCON1Lbits.ADON = 1;		// Turn on the ADC module now.

	ADCON5L = 0;					// 各COREをパワーオンする
	ADCON5Lbits.C0PWR	 = 1 ;	// Turn on analog power for dedicated core 0
	while(ADCON5Lbits.C0RDY == 0);

	ADCON3Hbits.C0EN	  = 1 ;	// Dedicated ADC Core 0 Enable
	ADCON5Lbits.C1PWR	 = 1 ;	// Turn on analog power for dedicated core 1
	while(ADCON5Lbits.C1RDY == 0);

	ADCON3Hbits.C1EN	  = 1 ;	// Dedicated ADC Core 1 Enable
	ADCON5Lbits.SHRPWR	= 1 ;	// shared core ON
	while(ADCON5Lbits.SHRRDY == 0);

	ADCON3Hbits.SHREN	 = 1 ;	// Shared ADC Core Enable
	while(ADCON5Lbits.SHRRDY == 0);	// shared core ready?
}

ラスボス、HSPWMの設定

もっともシンプルな差動PWMですが、動作するのに一番時間がかかりました。

// *** InitPWM ***
void initPWM(void) {
	// 単純 相補PWM
	// PWM control register configuration
	PCLKCONbits.MCLKSEL	= 2;	// MCLKSEL FPLLO:200MHz
	MPER = 10000;				// Master Period register
	// Initial Duty Setup
	PG1DC			= 1000;		// 25% duty
	PG2DC			= 1000;		// 50% duty
	PG3DC			= 1000;		// 75% duty

	PG1CONLbits.CLKSEL	= 1;
	PG1CONLbits.MODSEL	= 0;	//Independent edge triggered mode
	PG1CONH = 0x0000;			// Complementary mode, PWM1H and PWM1L output pins, output pins are active high
	PG1CONHbits.MPERSEL	= 1;	// MPERselect(master periodを使う)
	PG1IOCONH = 0x000C;			// PWM uses PG1DC, PG1PER, PG1PHASE registers, not broadcast UPDATE status bit state or EOC signal
								// Update the data registers at start of next PWM cycle (SOC), Single Trigger mode, (SOC) = local EOC, Write to DATA REGISTERS
//	PG1PER			= 10000;	// PWM frequency is 100kHz
	PG1PHASE		= 0;		// Phase offset in rising edge of PWM
	PG1DTH			= 40;		// Dead time on PWMH:500ns
	PG1DTL			= 40;		// Dead time on PWML

	PG2CONLbits.CLKSEL	= 1;
	PG2CONLbits.MODSEL	= 0;	// Independent edge triggered mode
	PG2CONH = 0x0000;			// Complementary mode, PWM1H and PWM1L output pins, output pins are active high
	PG2CONHbits.MPERSEL	= 1;	// MPERselect(master periodを使う)
	PG2IOCONH = 0x000C;			// PWM uses PG1DC, PG1PER, PG1PHASE registers, not broadcast UPDATE status bit state or EOC signal
								// Update the data registers at start of next PWM cycle (SOC), Single Trigger mode, (SOC) = local EOC, Write to DATA REGISTERS
//	PG2PER			= 10000;	// PWM frequency is 100kHz
	PG2PHASE		= 0;		// Phase offset in rising edge of PWM
	PG2DTH			= 40;		// Dead time on PWMH
	PG2DTL			= 40;		// Dead time on PWML

	PG3CONLbits.CLKSEL	= 1;
	PG3CONLbits.MODSEL	= 0;	// Independent edge triggered mode
	PG3CONH = 0x0000;			// Complementary mode, PWM1H and PWM1L output pins, output pins are active high
	PG3CONHbits.MPERSEL	= 1;	// MPERselect(master periodを使う)
	PG3IOCONH = 0x000C;			// PWM uses PG1DC, PG1PER, PG1PHASE registers, not broadcast UPDATE status bit state or EOC signal
								// Update the data registers at start of next PWM cycle (SOC), Single Trigger mode, (SOC) = local EOC, Write to DATA REGISTERS
//	PG3PER			= 10000;	// PWM frequency is 100kHz
	PG3PHASE		= 0;		// Phase offset in rising edge of PWM
	PG3DTH			= 40;		// Dead time on PWMH
	PG3DTL			= 40;		// Dead time on PWML

//	CMBTRIGLbits.CTA1EN = 1;

	PG1TRIGA = 5000;	// Initialize PWM GENERATOR 1 TRIGGER A REGISTER
	PG1TRIGB =    0;	// Initialize PWM GENERATOR 1 TRIGGER B REGISTER
	PG1TRIGC =    0;	// Initialize PWM GENERATOR 1 TRIGGER C REGISTER

	PWMEVTAbits.EVTASEL=0b1000;		//ADCTrigger1 signal
	PWMEVTAbits.EVTAPGS=0b000;		//PWM generator #1
	
	PG1EVTL	 =0x0000;
	PG1EVTLbits.ADTR1PS = 0;		// postscale 1:1
	PG1EVTLbits.ADTR1EN3 = 0;		// PG1TRIGAでコンペア
	PG1EVTLbits.ADTR1EN2 = 0;		// PG1TRIGAでコンペア
	PG1EVTLbits.ADTR1EN1 = 1;		// PG1TRIGAでコンペア
	PG1EVTLbits.PGTRGSEL = 0;		// Trigger1:PGxTRIGA event
	PG1EVTH	 =0x0000;
	PG1EVTHbits.IEVTSEL = 0x1;		// PWM割り込み使用しないのでN.A.
	PG1EVTHbits.ADTR2EN1 =1;		// Trigger2未使用だが仮設定

	PG1EVTLbits.UPDTRG = 1;			// update Trigger Select:PG1DC
	PG2EVTLbits.UPDTRG = 1;			// update Trigger Select:PG2DC
	PG3EVTLbits.UPDTRG = 1;			// update Trigger Select:PG3DC
	
	PG1CONLbits.ON	= 1;			// PWM1 module is enabled(PWM全部セットしてからONする)
	PG2CONLbits.ON	= 1;			// PWM2 module is enabled
	PG3CONLbits.ON	= 1;			// PWM3 module is enabled

 }

差動PWMでADCトリガをかけるので、PG1TRIGAをPWMピリオドの真ん中の5000=周期10000/2とする(要微調)。

また、PG1CON.ON=1を途中で行うと、その後のセットが無効になるので注意!