Beste mede-CO-ers,

Ik probeer enkele functies in een PIC18f2553 te krijgen maar bij het onderdeel I2C heb ik toch wat vragen. Eerst had ik nogal problemen met het binnenhalen van I2C data, maar dat lijkt nu opgelost, de data wordt gelezen en het programma blijft lopen.

Mijn vraag: Volgens app. note AN991 (Eq1, Ex2) zou de waarde van de baud rate generator (SSPADD) berekend kunnen worden met: SSPADD= \frac {(\frac {Fosc} {bitrate})}{4}{-1}
Maar op een bijzondere manier kom ik op de dubbele snelheid uit!
Op het kristal staat 24MHz, met een baud rate van 100khz kom ik op een waarde van 59 (decimaal) = 0x3B.
Maar dan loopt de hele zaak op 200KHz. Door te rekenen met 50KHz kom ik wel op 100KHz uit, maar dat lijkt mij niet de bedoeling.
Heeft iemand hier een verklaring voor?

Verdere informatie:
Ik programmeer in mplab C18.
Gebruik de bootloader op een Usb Bit Wacker met bijgeleverde (aangepaste) .lkr
Ik gebruik een levelshifter om van 5volt naar 3.3v te gaan.
De i2c-lijnen zijn voorzien van 10k pullups, zowel voor als achter de levelshifter.
De informatie over het uitlezen van de gyro-module (WiiMotionPlus) heb ik van hier
Voor de opbouw van het programma met isr heb ik een applicatienote van microchip zelf gebruikt.

Hier volgt dan de code, hopelijk kan/wil iemand een aanwijzing geven.


/*********************************************************************
 * set timer0 interrupt 5Hz
 * read 1 adc portA0
 * read i2c gyroscope
 ********************************************************************/
#include <p18cxxx.h>
#include <delays.h>
#include <timers.h>
#include <stdio.h>
#include <i2c.h>

#define LED_1	LATCbits.LATC0
#define LED_2	LATCbits.LATC1
#define LED_3	LATBbits.LATB5

// Global variables
unsigned int  rx_array[20];		// data array

// Function Prototypes
void InterruptHandlerHigh(void);  //needed for 'goto'
void motion_read(unsigned int* array);

// Start of program code
#pragma code HIGH_INTERRUPT_VECTOR = 0x808
void high_ISR (void)
{
    _asm
	goto InterruptHandlerHigh //jump to interrupt routine
	_endasm
}
#pragma code //return to the default code section

#pragma interrupt InterruptHandlerHigh
void InterruptHandlerHigh (void)
{	 
unsigned char adh,adl;		//Local variables
unsigned int result;

if (INTCONbits.TMR0IF) 		//check for TMR0 overflow
	{ 
	INTCONbits.TMR0IF = 0; 	//clear interrupt flag
	WriteTimer0(60859);		//Every 0.2 secs, 5Hz
	
// Read ADC
	ADCON0bits.CHS0=0;		//Read port A0
	ADCON0bits.CHS1=0;
	ADCON0bits.CHS2=0;
	ADCON0bits.CHS3=0;		//CHANNEL 0 set, note, to read Port A1, ADCON0bits.CHS0=1, page 259 of the PIC18f4550 datasheet
	ADCON0bits.GO=1;
while (ADCON0bits.GO); 		//wait for finish

//Convert high and low bytes to a 16 bit value
	adl= ADRESL;
	adh= ADRESH;
	result=adh*256;
	result=result+adl;

//set state of output
	if (result>=20000){	
	LED_1=1;	//21627 = 1.65v
	}
	else{
	LED_1=0;
	}

	LED_3=!LED_3; //to check if it is still all running

    motion_read(rx_array);	// Read data

//set state of output
	if ((((rx_array[5] & 0xFC) << 6) + rx_array[2])>=9000){	//8192 is middle of 14 bit data
	LED_2=1;
	}
	else{
	LED_2=0;
	}
	}
}

void init (void)
{
    ADCON1 |= 0x0F;  // Default all pins to digital
	INTCON2=INTCON2&0B0111111;  //Set pullups on port B

// Start out all LEDs off
	LED_1 = 0;
	LED_2 = 0;
	LED_3 = 0;

// Make LED I/O pins be outputs
	TRISCbits.TRISC0 = 0;	//leds = output
	TRISCbits.TRISC1 = 0;
	TRISBbits.TRISB5 = 0;
    TRISBbits.TRISB0 = 1;	//i2c = input
    TRISBbits.TRISB1 = 1;

//init timer
	OSCCONbits.IRCF2=1;		//Ensure the oscillator is running at a specific speed
	OSCCONbits.IRCF1=1;
	OSCCONbits.IRCF0=1;
	OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256);
	INTCONbits.GIEH = 1; 	// enable interrupts
	INTCONbits.GIE = 1; 	// enable interrupts
	INTCONbits.TMR0IF = 0;  // clear timer 0 interrupt flag
	INTCONbits.TMR0IE = 1;  // enable the timer 0 interrupt

//init ADC
	TRISA=0b11;	//Set port A bits to input
	ADCON2bits.ADCS0=0;//Set FOSC/32
	ADCON2bits.ADCS1=1;
	ADCON2bits.ADCS2=0;
	ADCON1=0b00001101; //Set voltage reference and port A0 and A1 as analogue only, this is detailed in section 21.0, page 260 of the PIC18f4550 datasheet
	ADCON0bits.ADON=1; //Turn on ADC

//init I2C Initialize the module by sending I2C commands to make the gyromodule 'active'
  	SSPCON1 = 0b00101000;
  	SSPCON2 = 0x00;
  	SSPSTAT = 0b10000000;	//Disable SMBus and Slew rate control		
	OpenI2C(MASTER, SLEW_OFF);	
	I2C_SDA = 1;
  	I2C_SCL = 1;
	SSPADD = 0x3B; 	// Set I2C frequency
  	PIR1bits.SSPIF = 0;
  	PIR2bits.BCLIF = 0; 

// init gyro device
    IdleI2C();
    StartI2C();
    IdleI2C();
	WriteI2C(0xA6);
    IdleI2C();
    WriteI2C(0xFE);
    IdleI2C();
    WriteI2C(0x04);
    IdleI2C();   
    StopI2C();
}

// Motion Read: Read the six bytes of data from the gyro. The read must be preceded
// by sending a zero.
void motion_read(unsigned int *array) 
{
	IdleI2C();		
    StartI2C();
	IdleI2C();
    WriteI2C(0xA4);
    IdleI2C();
    WriteI2C(0x00);
    IdleI2C();   
    StopI2C();

	IdleI2C();
    StartI2C();
    IdleI2C();
    WriteI2C(0xA5);
    IdleI2C();
	array[0] = ReadI2C();
	AckI2C();
	array[1] = ReadI2C();
	AckI2C();
	array[2] = ReadI2C();
	AckI2C();
	array[3] = ReadI2C();
	AckI2C();
	array[4] = ReadI2C();
	AckI2C();
	array[5] = ReadI2C();
    NotAckI2C();
    IdleI2C();   
    StopI2C(); 
}

void main(void)
{
init();
	while(1);
}

Edit: startpost aangepast

Dit is het hele programma.
De config is de ongewijzigd van de bootloader, en zou dus goed moeten zijn. Dit kan ik niet veranderen zonder de software van de bootloader aan te passen (waardoor de bootload niet meer zal werken).
Ik heb het toch even opgezocht.


#if defined(__4MHz_UBW_BOOTLOADER)
	#pragma config PLLDIV   = 1       // (4 MHz input)
	#pragma config CPUDIV   = OSC1_PLL2
	#pragma config USBDIV   = 2       // Clock source from 96MHz PLL/2
	#pragma config FOSC     = XTPLL_XT
#elif defined(__20MHz_UBW_BOOTLOADER)
	#pragma config PLLDIV   = 5       // (20 MHz input)
	#pragma config CPUDIV   = OSC1_PLL2
	#pragma config USBDIV   = 2       // Clock source from 96MHz PLL/2
	#pragma config FOSC     = HSPLL_HS
#elif defined(__24MHz_UBW_BOOTLOADER)
	#pragma config PLLDIV   = 6       // (24 MHz input)
	#pragma config CPUDIV   = OSC1_PLL2
	#pragma config USBDIV   = 2       // Clock source from 96MHz PLL/2
	#pragma config FOSC     = HSPLL_HS
#else
	#error "You MUST define one __XXMHz_UBW_BOOTLOADER"
#endif

#pragma config FCMEN    = OFF
#pragma config IESO     = OFF
#pragma config PWRT     = OFF
#pragma config BOR      = ON
#pragma config BORV     = 3
#pragma config VREGEN   = ON
#pragma config WDT      = OFF
#pragma config WDTPS    = 32768
#pragma config MCLRE    = ON
#pragma config LPT1OSC  = OFF
#pragma config PBADEN   = OFF
#pragma config CCP2MX   = ON
#pragma config STVREN   = ON
#pragma config LVP      = OFF
#pragma config DEBUG    = OFF       // Dedicated In-Circuit Debug/Programming
#pragma config XINST    = OFF       // Extended Instruction Set
#pragma config CP0      = OFF
#pragma config CP1      = OFF
#pragma config CP2      = OFF
#pragma config CP3      = OFF
#pragma config CPB      = OFF
#pragma config CPD      = OFF
#pragma config WRT0     = OFF
#pragma config WRT1     = OFF
#pragma config WRT2     = OFF
#pragma config WRT3     = OFF
#pragma config WRTB     = ON		// Boot Block Write Protection ON
#pragma config WRTC     = ON		// Configuration register write protect ON
#pragma config WRTD     = OFF
#pragma config EBTR0    = OFF
#pragma config EBTR1    = OFF
#pragma config EBTR2    = OFF
#pragma config EBTR3    = OFF
#pragma config EBTRB    = OFF

#endif

Volgens mij klopt het gewoon, je moet alleen niet uitgaan van 24MHz clock maar van 48Mhz

24Mhz kristal > div 6= 4Mhz >PLL >96Mhz div 2 =48Mhz (USB2.0)

Voor USB zijn er 2 snelheden (USB1.1 en USB2.0 resp. 6Mhz en 48 Mhz)
Wil je de bootloader blijven gebruiken moet je dus uitgaan van deze frequenties(met bijbehorende config).

voor USB1.1 geldt:
20Mhz kristal div 5= 4MHz > 96Mhz div 4(cpudiv) =24Mhz div 4=6Mhz
24MHz kristal div 6= 4MHz > 96MHz div 4(cpudiv) =24Mhz div 4=6Mhz

Okee, bedankt! Blijkbaar is dit de verklaring.
Ik heb de pll nog nooit gebruikt. Waarschijnlijk heb ik er daarom ook niet aan gedacht. Ik kan weer verder :)