MAH
Every machine is a smoke machine if you operate it wrong enough
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
MAH
Every machine is a smoke machine if you operate it wrong enough
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
#endifArabel
Re-integratiecoach uitgerangeerde en degoutante electronen
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
MAH
Every machine is a smoke machine if you operate it wrong enough
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 