Forum: Mikrocontroller und Digitale Elektronik PIC33F SPI funktioniert nicht


von Chris (Gast)


Lesenswert?

Hallo Leute,
ich hab mal wieder ein kleines Problem.
Und zwar tut sich bei mir bei der SPI-Kommunikation nichts.
Ich möchte generell erst mal mit einem Oszi am Pin testen, ob er was 
raus gibt...bisher leider nichts...und später möchte ich dann mit einem 
AD-Wandler kommunizieren. (MAX11254)

Initialisiert hab ich folgendermaßen:
1
// The following code sequence shows SPI register configuration for Master mode 
2
3
IFS0bits.SPI1IF = 0;                            // Clear the Interrupt flag
4
IEC0bits.SPI1IE = 0;                            // Disable the interrupt
5
// SPI1CON1 Register Settings
6
SPI1CON1bits.DISSCK = 0;                        // Internal serial clock is enabled
7
SPI1CON1bits.DISSDO = 0;                        // SDOx pin is controlled by the module
8
SPI1CON1bits.MODE16 = 1;                        // Communication is word-wide
9
SPI1CON1bits.MSTEN = 1;                         // Master mode enabled
10
SPI1CON1bits.SMP = 0;                           // Input data is sampled at the middle of data output time
11
SPI1CON1bits.CKE = 0;                           // Serial output data changes on transition from Idle clock state to active clock state
12
SPI1CON1bits.CKP = 0;                           // Idle state for clock is a low level; active state is a high level
13
14
SPI1CON1bits.PPRE = 0b01;                       //prescale 16:1 für 5MHz
15
SPI1CON1bits.SPRE = 0b111;                      //prescale 1:1
16
17
SPI1STATbits.SPIEN = 1;                         // Enable SPI module
18
IFS0bits.SPI1IF = 0;                            // Clear the Interrupt flag
19
IEC0bits.SPI1IE = 1;                            // Enable the interrupt
Prescaler mit 16, da ich maximal 8MHz laut Datenblatt für SPI verwenden 
kann. => 80MHz /16 = 5MHz


Meine Einstellungen zur Internen clock:
1
/* Configure PLL prescaler, PLL postscaler, PLL divisor */
2
PLLFBD=41;         /* M = PLLFBD + 2 */
3
CLKDIVbits.PLLPOST=0;   /* N1 = 2 */
4
CLKDIVbits.PLLPRE=0;    /* N2 = 2 */
5
6
__builtin_write_OSCCONH(0x01);      /* New Oscillator FRC w/ PLL */
7
__builtin_write_OSCCONL(0x01);      /* Enable Switch */
8
      
9
while(OSCCONbits.COSC != 0b001);    /* Wait for new Oscillator to become FRC w/ PLL */  
10
while(OSCCONbits.LOCK != 1);      /* Wait for Pll to Lock */


Ports wurden wie folgt Initialisiert:
CSB=RP28
DOUT=RP29
DIN=RP27
SCLK=RP16
1
ADPCFG = 0xFFFF;                                 //Alle Ports auf Digital
2
3
TRISA = 0x00;                                   //Ein- und Ausgänge festlegen
4
LATA = 0x0024;                                 //Alles auf 0 Setzen, bis auf PWM PINS
5
6
TRISB = 0x7C10;                                 //Ein- und Ausgänge festlegen
7
LATB = 0x0000;                                 //Alles auf 0 Setzen
8
9
TRISC = 0xA08;                                 //Ein- und Ausgänge festlegen
10
LATC = 0x0000;                                 //Alles auf 0 Setzen
11
12
__builtin_write_OSCCONL(OSCCON & ~(1<<6));     // to clear IOLOCK
13
RPINR20 = 0x1B;                                 //DIN Pin festlegen
14
RPOR14 = 0x1D00;                                //DOUT Pin festlegen
15
RPOR14 = 0x9;                                   //CSB Pin festlegen
16
RPOR8 = 0x8;                                    //SCLK Pin festlegen
17
__builtin_write_OSCCONL(OSCCON | (1<<6));      // to set IOLOCK

Das Senden dann folgendermaßen:
1
while(1)
2
{
3
//Senden
4
IFS0bits.SPI1IF = 0;                            // Clear the Interrupt flag
5
PORTBbits.RB9 = 0;                              //CSB auf 0 setzen          
6
dummy = SPI1BUF;                                //Dummy um Puffer zu leeren
7
SPI1BUF = 0xD100;                               //Daten in Puffer schreiben
8
while (!SPI1STATbits.SPITBF)                    //Warten bis Daten gesendet
9
PORTBbits.RB9 = 1;                              //CSB auf 1 setzen
10
}

Jetzt hab ich zm einen das Problem, dass ich mit meinem Oszi nichts am 
DOUT messen kann und ich außerdem, nachdem ich mein Programm im 
Debug-Modus ausführe, folgende Meldung erhalte:
"Target halted due to Software Breakpoint in user code"
Ich vermute mal, dass sich das Programm in der while-Schleife 
festhängt....

hat jemand Ideen?

von X4U (Gast)


Lesenswert?

Chris schrieb:
> Jetzt hab ich zm einen das Problem, dass ich mit meinem Oszi nichts am
> DOUT messen kann

Hole dir doch erstmal eine Beispielapplikation.
Z.B. Google PIC33F spi example

> und ich außerdem, nachdem ich mein Programm im
> Debug-Modus ausführe, folgende Meldung erhalte:
> "Target halted due to Software Breakpoint in user code"

Vermutlich passiert das was da steht. Das Programm ist auf einen 
Software Breakpoint gelaufen. Woher der kommt wirst du schon rausfinden.


> Ich vermute mal, dass sich das Programm in der while-Schleife
> festhängt....

Vermutlich nicht, alle Debugger die ich kenne geben dann keine Meldung 
von sich. Sie führen die while Schleife aus.

von Peter C. (peter_c49)


Lesenswert?

Hallo Chris,

>IEC0bits.SPI1IE = 1;                            // Enable the interrupt
wo ist dein InterruptHandler ?

Falls du keinen hast, Interrupt NICHT anmachen. (= 0;)
Ich weiss nicht wo der int-vector default hinzeigt, könnte also auch 
einen trap auslösen wenn du keinen handler hast.

Und, ohne das DB zu deiner MCU angesehen zu haben,
vorsichtshalber IMMER die ports die du als SPI benutzen möchtest auf 
Input bzw Output setzen, schadet nie, auch wenn einige MCU's das ev 
automatisch machen wenn das SPI modul activiert ist.

mfG
Peter

von Chris (Gast)


Lesenswert?

Hallo Ihr zwei,

erstmal vielen Dank für die Antworten.

Das mit dem Software Breakpoint hab ich mit dem Interrupt auf 0 weg 
bekommen...
Die Ports sind als Input bzw. Output gesetzt.. aber es passiert immer 
noch nichts :-(

von Chris (Gast)


Lesenswert?

Kurzer Nachtrag...
also meine Clock kann ich mit 2,5MHz messen. Auch mein CSB wird 
gesetzt... Aber am Dout kommt nichts raus

von Chris (Gast)


Lesenswert?

Keiner eine Idee?

>"Kurzer Nachtrag...
>also meine Clock kann ich mit 2,5MHz messen. Auch mein CSB wird
>gesetzt... Aber am Dout kommt nichts raus"

Muss ich korrigieren... hab ich nur, so bald ich Frame auf 1 stelle...

Bei dem Stand, wie das Programm oben beschrieben ist, habe ich nur 4 
Ausschläge der Clock....

Examples hab ich mir schon diverse angesehen, aber ich komm nicht drauf, 
was noch falsch wäre.... Wäre klasse, wenn mir jemand helfen könnte, 
sonst verzweifel ich hier noch!

von Peter C. (peter_c49)


Lesenswert?

Hallo Chris,

RPOR14 = 0x1D00;                                //DOUT Pin festlegen
RPOR14 = 0x9;                                   //CSB Pin festlegen

die beiden schaust du noch mal an, denke das tut nicht so.
zusammenodern.
wobei ich zweifel hab ob es generel richtig gemapt ist.
kenne deinen chip aber nicht u mag nicht das DB hohlen zur zeit.

wenn du #include<spi.h>  machst, kannst du auch die bequemlichen PPS 
mapping funktionen benutzen:
zb:
    PPSUnLock;
    iPPSInput(IN_FN_PPS_SDI1, IN_PIN_PPS_RP14);
    iPPSOutput(OUT_PIN_PPS_RP13, OUT_FN_PPS_SDO1);
    iPPSOutput(OUT_PIN_PPS_RP12, OUT_FN_PPS_SCK1);
    PPSLock;

sind ev gut um weniger fehler zu machen, ich mag diese syntax aber auch 
nicht.

so, und dann sehe ich noch den hier
 SPI1CON1bits.MODE16 = 1;
bist du sicher ?

hier mal eine spi init die ich grad auf meinem browser notebook gefunden 
hab,
da hatte ich einen nRF24 dran, weiss grad nicht welcher PIC24/33 es war.
funktioniert aber immer noch, war für eine 2.4Ghz handfernbedienung mit 
der ich hier vom Sofa die beleuchtung(RGB LEDs) bunt mache.

void spi_init(void) {
    //printf("\nspi_init...");
    // set dir and port types first
    ANSB = 0; // all digital
    TRISBbits.TRISB15 = 0; // *SS1 AN9 RB15
    TRISBbits.TRISB13 = 0; // output SDO1/RB13 AN11
    TRISBbits.TRISB14 = 1; // input  SDI1/RB14 AN10
    TRISBbits.TRISB12 = 0; // input  SCK1/RB12 AN12

    // now spi
    SPI1STATbits.SPIEN   = 0; // disable SPI port
    SPI1STATbits.SPISIDL = 0; // Continue module operation in Idle mode

    SPI1BUF = 0; // clear SPI buffer

    IFS0bits.SPI1IF = 0; // clear interrupt flag
    IEC0bits.SPI1IE = 0; // disable interrupt
    SPI1CON1bits.DISSCK = 0; // Internal SPIx clock is enabled
    SPI1CON1bits.DISSDO = 0; // SDOx pin is controlled by the module
    SPI1CON1bits.MODE16 = 0; // set in 16-bit mode, clear in 8-bit mode
    SPI1CON1bits.SMP    = 0; // Input data sampled at middle of data 
output time
    SPI1CON1bits.CKP    = 0; // 0 = Idle state for clock is a low level; 
active state is a high level
    SPI1CON1bits.CKE    = 1;
             // 1 = Serial output data changes on transition from active 
clock state to Idle clock state
             // 0 = Serial output data changes on transition from Idle 
clock state to active clock state
    SPI1CON1bits.MSTEN  = 1; // 1 =  Master mode; 0 =  Slave mode
    SPI1CON1bits.SPRE   = 0b101; // Secondary Prescaler = 4:1
    SPI1CON1bits.PPRE   = 0b010; // Primary Prescaler = 4:1

    SPI1CON2            = 0; // non-framed mode

    // RB15 as SS for SPI slave select
    #define SPI_SS_TRIS      TRISBbits.TRISB15
    #define SPI_SS_PORT      PORTBbits.RB15
    SPI_SS_PORT         = 1; //
    SPI_SS_TRIS         = 0; // set SS as output

    SPI1STATbits.SPIEN  = 1; // enable SPI port, clear status

    // Interrupt Controller Settings
    IFS0bits.SPI1IF = 0; // Clear the Interrupt flag
    IEC0bits.SPI1IE = 0; // Disable the interrupt
}

// send and receive 8bit on SPI1, blocks.
uint8_t spi_fast_shift( uint8_t data) {

    SPI1BUF = data; // send it

    while(!SPI1STATbits.SPIRBF);  // wait for transfer to complete

    return SPI1BUF;
}

achte bitte auf die spi_fast_shift(), die sendet und empfängt!
deine methode in der while(1){} ist mir sehr suspect.

mfG
Peter ;-)

von Chris (Gast)


Lesenswert?

Hi Peter,

vielen Dank für deine Hilfe (auch beim UART ;-) )... werds morgen gleich 
ausprobieren!!!

von Chris (Gast)


Lesenswert?

Hi Peter,

also mit deinem Code (angepasst auf meinen Bedarf) klappts...:-)
Danke nochmal!

von Chris (Gast)


Lesenswert?

So,... nachdem ich nun vo PIC alles ordnungsgemäß raus bekomme, hab ich 
ein weiteres Problem -.-

Und zwar möchte ich einen MAX11254 24Bit AD-Wandler über mein SPI 
auslesen. Wenn der Wandler nicht angeschlossen ist, kann ich mit dem 
OSZI am DOUT schön meine einzelnen Bits messen.
So bald ich meinen AD-Wandler anschließe, habe ich an dessen DIN eine 
Spannung von 3,3V anliegen. Verbinde ich nun DOUT vom µC mit DIN des 
AD-Wandlers, und versuche dann meine Bits zu senden, bekomme ich keine 
einzelnen Bits am Oszi zu sehen, sondern eine kontinuierliche Spannung 
von ca. 0,7V. => Wenn das der Fall ist, nimmt auch die Stromaufnahme der 
Schaltung zu! (um ca. 25mA)

Brauch ich an meinem SPI-BUS noch irgendwie Pullup-Widerstände? Wobei 
die mir ja hier eigentlich nicht helfen, da sie ja meinen Spannungspegel 
im undefinierten Zustand auf 3,3V ziehen sollten... was ich ja hier 
eigentlich hab.

Ich hab auch ein Testboard für den AD-Wandler... auch hier liegen die 
3,3V an, so bald die Spannungsversorgung vorhanden ist. Ich denke also, 
dass ich keinen Verdrahtungsfehler gemacht habe.

Theoretisch müsste ja der PIC jetzt an seinem DOUT entweder den Pegel 
auf GND ziehen, oder auf 3,3V... je nachdem wie mein Bit-Muster aussieht 
oder?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.