nobcha23の日記

PICマイコンやArduinoを使う電子回路遊びを紹介します

PIC16F1829のMSSP2でまたつまづく

AD9830接続で挫折し、si5351aに切り替え、エアバンド用受信機局発を作ろうとしています。
秋月電子から部品が届きました。接続図に従い、PIC16F1829基板とつなぎます。

こうした際、配線確認もかね、i2cスキャンプログラムを流すことにしています。
i2cスキャンプログラムとは後で示すように、i2cアドレスを順繰りに出し、ack応答あるかを見るプログラムです。

oxC0で応答があり、無事動きました。

ところが、その後がいけません。i5351aの周波数設定プログラムを流すと、つながらない。
以前にPIC16F1829でMSSP2を使おうとしたらどうしても動かなくて、MSSP1に切り替えて使いましたが、再発です。原因追求中です。

i2cスキャンのプログラムです。

/* 
 * File:   newmain.c
 * Author: nobcha
 * Created on 2018/01/03, 18:01
 */

/*************************************************
 MSSP i2c SCAN TEST of PIC12F1829
              By nobcha all right reserved

  Ver 1.0 07/08/2012 for i2c peripheral TEST
  Ver 2.0 08/31/2012 for 1827
  Ver 3.0 10/05/2014 for 1829 11/25/2014 MSSP2 is OK
 * 01/06/2018 MPLAB X transfered OK

   PIC12F1829 + LCD  + charge pumping minus volt
   PIN Assign
 	RA0:LCD RS bit(RS)はRA0に接続
  	RA1:LCD EN bit (enable)はRA1に接続
 	RA2: not used T0CKI:F-in
 	RA3:RESET_sw    : MCLR
 	RB4:MEM_sw      : SW2
  	RB5:SDA2 MSSP2
	RB6:Heart beat  LED   
 	RB7:SCL2 MSSP2
	RC0:  not used Toggle Prescaler:CNT DISABLE
	RC2-5:SC1602は4ビットモードとし、RC2-5で接続
	RC6: Charge pump source:CCP4  
   	RC7: Down_sw   SW3

 	SC1602 pin connection via 4bit mode
 		#1	Vdd=3V
 		#2	Vss=GND
 		#3	LCD contrust center of 10k VOL minus V
 		#4	RS	RA0
 		#5	R/W	GND
 		#6	EN	RA1
  		#11-14	DATA	RC2-5

    OSC INT 16MHz
   Development Circumstance: MPLAB X IDE V2.20
************************************************* */

#define _XTAL_FREQ 16000000
#define PIC_CLOCK 1600000

#include <stdio.h>
#include <stdlib.h>
#include <htc.h>
#include "lcd.h"
#include "mssp2_i2c.h"

#define HEART_BEAT LATB6
#define UP_SW PORTBbits.RB4 // SW2

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection INT: device clock supplied to CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is RA3)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = ON    // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)


// proto
void itostring(char , unsigned int , char* );
void mssp_init(void);
unsigned char i2c_scan(unsigned char);

// display data
unsigned char Msg1[17] = "i2c SCAN test   ";
unsigned char Msg2[6] = "ADDR ";
unsigned char Msg3[5] = "ack ";
unsigned char Msg4[4] = "   ";
unsigned char Msg5[10] = "         ";

void main(void)
{
    unsigned char i;

/* INITIALIZE REGISTER      */
	OSCCON = 0b01111000;		// Set 16MHz

	LATA =  0b00000000;		// Clear
	TRISA = 0b00111100;		// LATA INPUT RA4,5:SW,3:int,2:SW
	LATB =  0b00000000;		// LATB RESET
	TRISB = 0b10110000;		// LATB INPUT RB7:SCL2,5:SDA2,4:SW2
	LATC =  0b00000000;		// LATC RESET
	TRISC = 0b10000011;		// LATC INPUT RC7:SW3,0,1:SHT

	ANSELA = 0b00000000;		// All degital
	ANSELB = 0b00000000;
	ANSELC = 0b00000000;

	CM1CON0 = 0b00000111;		// No using compalator
	CM2CON0 = 0b00000111;		// No using compalator

 	OPTION_REG = 0b10100100;	// INTEDG 0,TOCS T0CKI 1,ToSE0,PSA TIMER0,1/32

 	INTCON=0;			// INT off
	T1CON = 0;			// Timer1 off

// To generate minus voltage for LCD with 3V supply
// CCP4 PWM initializing (83.8KHz on RB3 @16MHz)
	CCP4CON = 0b00001111;		// use PWM mode
	CCPR4L = 0x0c; 			// duty is 50%
	CCPTMRS = 0;			// Select TMR2
//  TMR2 initilizing
	T2CON = 0b00000100;		// POSTSCALE 1:1 ,TMR2 ON , PRESCALE 1:1
	PR2 = 0x17; 			// resolution is 6.5bit mode
	TMR2ON = 1;			// TMR2 start

	__delay_ms(200);
	__delay_ms(200);
	mssp_init();			// MSSP initialize
	lcd_init();			// LCD initialize continue
	HEART_BEAT = 1;			// LED off

	while(1)
	{
	__delay_ms(100);

		HEART_BEAT ^= 1;		// Heart beat LED upset
		lcd_goto(0x00);			// Move cursor 1st line
		lcd_puts(Msg1);			// Display test message

		i=2;
		while(i){
			lcd_goto(0x40);		// Move cursor to 2nd line
			lcd_puts(Msg2);		// i2c addr message
			itostring(2,i,Msg4);    // convert i to ASCII
			lcd_puts(Msg4);		// SCAN ADD

			if(i2c_scan(i)==0){     // If detect ack,displaying addr
				lcd_puts(Msg3);
				itostring(2,i,Msg4);
				lcd_puts(Msg4);
				while(UP_SW) ;  // Waiting SW1 PUSH CHECK
				__delay_ms(400);
			}
			else lcd_puts(Msg5);

			i=i+2;
			__delay_ms(100);
		HEART_BEAT ^= HEART_BEAT;	// Heart beat LED upset
		}

		__delay_ms(500);		// 0.5s waiting
	}
}
/***************************************
* Converting 2/4 hex to ASCII
****************************************/
void itostring(char digit, unsigned int data, char *buffer)
{
	char i;					// digit:2 or 4
	buffer += digit;			// last data
	for(i=digit; i>0; i--) {                //
		buffer--;			//
		*buffer = (data & 0xF) + '0';	// ASCII code
		if(*buffer>0x39) *buffer=*buffer+7;
		data = data >> 4;		// next hex
	}
}

/***************************************
* MSMSSP2 initialize
****************************************/

void mssp_init(void){
// Assign MSSP SDA2 & SCL2 except for RX & TX
//	APFCON0 = 0x80;			// Assign RX on RC5 instead of RB5
//      SSP2CON1 REGISTERS
	SSP2CON1bits.SSPEN      = 1;   	//Enables Serial Port Mode
        SSP2CON1bits.SSPM3      = 1;   	/////////
        SSP2CON1bits.SSPM2      = 0;   	//I2C Master Mode
        SSP2CON1bits.SSPM1      = 0;   	// clock= Fosc/(4*(SSP2ADD+1))
        SSP2CON1bits.SSPM0      = 0;   	////////

//     SSP2CON2 REGISTERS
       SSP2CON2   = 0x00;
//     SSP2CON3 REGISTERS
       SSP2CON3   = 0x00;


//      SSP2STAT REGISTERS
       SSP2STATbits.SMP = 1;   		// SLEW RATE non
       SSP2STATbits.CKE = 1;   		//SMBus Specific Inputs Enabled

//SSP2ADD    = 0x19;    	        //~75kHz
       SSP2ADD    = 0x13;     		//~100kHz
//SSP2ADD    = 0x07;     		//~400kHz
//SSP2ADD    = 0x50;
}


/***************************************
* i2c address scanning test
****************************************/
unsigned char i2c_scan(unsigned char data){
	unsigned char ack_data;
	i2c_start();			// start condition
	i2c_write(data);		// addr & wite mode
	ack_data=i2c_readack();		// if ack:0
	i2c_stop();
	return (ack_data);
}




MSSP制御関数です。プロトタイプ宣言のmssp2_i2c.hは必要です。

#define _LEGACY_HEADERS

#include  <htc.h>
#include  "mssp2_i2c.h"
#define TRUE 0x0;
#define FALSE 0x1;

/**************************************************
 *  MSSP使用マスターモード専用I2C関数 by nobcha
 *  教育・ホビー用. 営利目的・商用への利用は禁止
 *  詳しいタイミングはNXPの資料やPICドキュメント
 *  参照のこと
 *   09/25/2011
 *   10/05/2014 rewrite for MSSP2
 **************************************************
 */

/*
 *	msspはSDAとSCL信号をスタート状態にします
 *	衝突有るとMSSPはリセットされる
 */
  void i2c_start(void){
      SSP2CON2bits.SEN = 1;           // SSP1CON2:0 initiate I2C START condition
      while (SSP2CON2bits.SEN == 1);  // wait until START bit finishes
  }

/*
 *	msspはSDAとSCL信号をRESTART状態にします
 *	衝突有るとBCL1IFが立つ
 */
  void i2c_restart( void) {
   	SSP2CON2bits.RSEN = 1;         // SSP1CON2:1 Repeated Start
   	while (SSP2CON2bits.RSEN==1);
  }

/*	関数の説明
 *	DATAをSSP1BUFに書きスレーブに転送かける
 *	転送中はR_nWが1になっている
 */
  void i2c_write( unsigned char DataByte ){
   	SSP2BUF = DataByte;
   	while (SSP2STATbits.R_nW == 1);
  }

/*	関数の説明
 *	受信可にしてDATAを待つ。
 *	RSEN0になったら、SSP2BUFのデータを読み持って返る
 */
  unsigned char i2c_read( void) {
   	SSP2CON2bits.RCEN = 1;           // SSP1CON2:3 Receive enable
   	while (SSP2CON2bits.RCEN == 1);
   	return SSP2BUF;
 }

/*	関数の説明
 *	msspはSDAとSCL信号をstop状態にします
 *	PENが0になったら、かえる。衝突あるとBCL1IFが立つ
 */
  void i2c_stop( void) {
   	SSP2CON2bits.PEN = 1;           // SSP1CON2:2 initiate I2C STOP condition
   	while (SSP2CON2bits.PEN);
  }

/*	関数の説明
 *	ACK(ACKDT:0)かNACK(ACKDR:1)を送る
 *	ACKENしたらかえる。
 */
  void i2c_sendack(unsigned char status) {
   	SSP2CON2bits.ACKDT = status;       // SSP1CON2:5 set to ACK:0,NACK:1
   	SSP2CON2bits.ACKEN = 1;            // SSP1CON2:4  initiate I2C ACK condition
   	while (SSP2CON2bits.ACKEN);        // wait until ACK sequence is over
  }

/*	関数の説明
 *	ACK(ACKDT:0)かNACK(ACKDR:1)をチェックする
 *	ACK(ACKSTAT:0)かNACK(ACKSTAT:1)でかえる。
 */
  unsigned char i2c_readack(void) {
   	if (SSP2CON2bits.ACKSTAT == 0) {
      	return 0;         			// ACK detected
   	} else {
            return 1;         			// ACK not detected
   	}
  }

/*	関数の説明
 *	指定アドレスにWRITEモードでアドレスを書く
 *	ACK有ればTRUEで、無ければFALSEでかえる
 */
  unsigned char i2c_writeto(unsigned char address){
	i2c_start();
	i2c_write(address | 0x0);
	if(i2c_readack()) return TRUE;
	return FALSE;
  }

/*	関数の説明
 *	指定アドレスにREADモードでアドレスを書く
 *	ACK有ればTRUEで、無ければFALSEでかえる
 */
  unsigned char i2c_readfrom(unsigned char address){
	i2c_start();
	i2c_write(address | 0x1);
	if(i2c_readack()) return TRUE;
	return FALSE;
  }

ホームページではまとめて記載。