Forum: Mikrocontroller und Digitale Elektronik Senden über SPI bei dsPIC33EV


von Svolvaer (Gast)


Lesenswert?

Hi,

ich versuche gerade, den SPI2 beim dsPIC33EV64GM002 zu verwenden, dabei 
soll nur gesendet werden, die Empfangsrichtung interessiert nicht. 
Leider klappt das ganze schon im Simulator nicht, die Statusabfrage in 
SPI1STAT (Bit SPIRBF) liefert mir immer ein "nicht fertig" zurück.

Im Moment habe ich das Folgende:

Mapping der Pins:
1
RPOR0bits.RP20R=8;    // use RP20 / pin 12 for SDO2
2
TRISAbits.TRISA4=0;   // set as output -> this can be removed (possibly)
3
4
RPOR0bits.RP35R=9;    // use RP35 / pin 7 for SCLK2
5
TRISBbits.TRISB3=0;   // set as output -> this can be removed (possibly)

Initialisierung von SPI2:
1
IFS2bits.SPI2IF = 0;
2
IEC2bits.SPI2IE = 0;
3
IPC8bits.SPI2IP = 0;
4
SPI2CON1 = 0x0337;  //0b0000 0011 0011 1110
5
SPI2CON2 = 0x0000;  //0b0000 0000 0000 0000
6
SPI2STAT = 0x8000; // 0b1000 0000 0000 0000
Die Teiler für den Clock passen sicher vorne und hinten noch nicht, für 
den Simulator sollte das aber erst mal egal sein?

Ein einzelnes Byte senden:
1
SPI1BUF=data;

Warten, dass der Sendevorgang abgeschlossen wird:
1
while (!SPI1STATbits.SPIRBF);

An genau der Stelle hängt mein Code, die while-Schleife kommt nie 
zurück.

Irgend eine Idee, was hier schief laufen könnte?

Danke!

von Michael S. (michi-s2)


Lesenswert?

Du musst nach dem while aus dem SPI1BUF lesen. Das will der PIC so. Hat 
mich auch viel Zeit gekostet.

von Svolvaer (Gast)


Lesenswert?

OK, allerdings komme ich aus dem while gar nicht erst raus, sprich ich 
hänge schon beim ersten Sendeversuch...

von Michael S. (michi-s2)


Lesenswert?

Ich vermute du kommst genau einmal raus. Ansonsten lese einfach mal 
davor.

von Michael S. (michi-s2)


Lesenswert?

Nur so als Tipp: Eine Notation wie diese:
1
  SPI2CON1bits.MSTEN = 1; //SPI-Master
2
  SPI2STATbits.SPIROV = 0;
3
  SPI2STATbits.SPIEN = 1; //SPI enable

ist deutlich leichter zu lesen ;-)

von Hermann U. (Firma: www.pcb-devboards.de) (gera82)


Lesenswert?

Hier mal mein dsPIC33EV, sollte funktionieren:
1
void Init_PPS (void)
2
{
3
4
      __builtin_write_OSCCONL(OSCCON & (~(1<<6))); // clear bit 6
5
6
7
          // output remappeble pins
8
          RPOR5bits.RP48R = RPO_SDO2;     
9
          RPOR9bits.RP118R = RPO_SCK2;     
10
11
      __builtin_write_OSCCONL(OSCCON | (1<<6));    // Set bit 6
12
13
14
}
1
void Init_SPI2(void)
2
{
3
// SPI1CON1 Register Settings
4
  SPI2CON1bits.DISSCK = 0; // Internal serial clock is enabled
5
  SPI2CON1bits.DISSDO = 0; // SDOx pin is controlled by the module
6
  SPI2CON1bits.MODE16 = 0; // Communication
7
  SPI2CON1bits.SMP = 1; // Input data is sampled at the middle of data output time
8
  SPI2CON1bits.CKE = 0; // Serial output data changes on transition from Idle clock state to active clock state
9
  SPI2CON1bits.SSEN = 0; // 0 = SSx pin is not used by the module; pin is controlled by port function
10
  SPI2CON1bits.CKP = 1; // Idle state for clock is a low-level;active state is a high-level
11
  SPI2CON1bits.MSTEN = 1; // Master mode enabled
12
13
  SPI2CON1bits.SPRE = 0b001; //Secondary prescaler value=5
14
  SPI2CON1bits.PPRE = 0b10; //3 //Primary prescaler=1
15
16
17
  SPI2CON2bits.FRMEN = 0; //0 = Framed SPIx support is disabled
18
  SPI2CON2bits.SPIBEN = 1; //Enhanced Buffer is enabled
19
20
  SPI2STATbits.SPIEN = 1; // Enable SPI module
21
  SPI2STATbits.SPIROV = 0; // Clear SPI2 receive overflow flag if set
22
23
    IFS2bits.SPI2IF = 0;              //Clear interrupt flag (no interrupt)
24
  //  IEC2bits.SPI2IE = 1;              //Enable SPI2 interrupts
25
}

8 Byte senden:
1
     SPI2BUF=1;
2
     SPI2BUF=2;
3
     SPI2BUF=3;
4
     SPI2BUF=4;
5
     SPI2BUF=5;
6
     SPI2BUF=6;
7
     SPI2BUF=7;
8
     SPI2BUF=8;
9
10
     // SRMPT: SPIx Shift Register (SPIxSR) Empty bit (valid in Enhanced Buffer mode)
11
     // 1 = The SPIx Shift register is empty and ready to send or receive the data
12
     // 0 = The SPIx Shift register is not empty
13
     while (!SPI2STATbits.SRMPT);

Gruß
Hermann

von Stampede (Gast)


Lesenswert?

Hast du die Clock Leitung bei dem Remapping als Ein- UND Ausgang 
gesetzt? Gern gemachter Fehler, sonst empfängt man nix!

von Svolvaer (Gast)


Lesenswert?

Stampede schrieb:
> Hast du die Clock Leitung bei dem Remapping als Ein- UND Ausgang
> gesetzt? Gern gemachter Fehler, sonst empfängt man nix!

Ich will ja nur Senden, Empangen interessiert nicht...

@Herman: danke für den Code, damit konnte ich bei mir zumindest schon 
mal feststellen, dass ich SPI2 initialisiert habe, dann aber auf SPI1BUF 
(=SPI1) rumgesendet habe - was nicht wirklich gut ist :-D

Aber selbst mit den Änderungen und deinem Code komme ich nie über's
1
while (!SPI2STATbits.SRMPT);

hinaus...

von Hermann U. (Firma: www.pcb-devboards.de) (gera82)


Lesenswert?

Svolvaer schrieb:
> Aber selbst mit den Änderungen und deinem Code komme ich nie über's
> while (!SPI2STATbits.SRMPT);

Mach das mal mit Debugger und richtiger Hardware, Simulation ist nicht 
gut, nur in der Hardware zählt ;-)
Poste mal dein Code, inkl aller Initialisierungen, Remapps, Clock etc...

Mein geposteter COde geht 100%, kannst du ja selber testet, an pins:
RPOR5bits.RP48R = RPO_SDO2;
RPOR9bits.RP118R = RPO_SCK2;
sollte was rauskommen, wenn du in SPI2BUF=1; was reinschreibst.

Gruß
Hermann

von Svolvaer (Gast)


Lesenswert?

@Hermann: Ich verwende exakt deinen Code, mit Ausnahme der Pins, an der 
SDO2 und SCLK2 liegen, da ich RP48 und RP118 nicht habe. Die 
Initialisierung sollte aber trozdem passen!?
1
RPOR0bits.RP20R=8;    // use RP20 / pin 12 for SDO2
2
TRISAbits.TRISA4=0;   // set as output -> this can be removed (possibly)
3
4
RPOR0bits.RP35R=9;    // use RP35 / pin 7 for SCLK2
5
TRISBbits.TRISB3=0;   // set as output -> this can be removed (possibly)

von Svolvaer (Gast)


Lesenswert?

Der vollständigkeit halber mal der komplette Code in der exakten 
Aufrufreihenfolge.

Clock-Initialisierung:
1
static void set_clock()
2
{
3
   int j=100;                    //sets up temporary counter
4
   
5
   // setup internal clock for 80MHz/40MIPS
6
   // 7.37/2=3.685*43=158.455/2=79.2275
7
   CLKDIVbits.PLLPRE=0;        // PLLPRE (N2) 0=/2
8
   PLLFBD=41;                  // pll multiplier (M) = +2
9
   CLKDIVbits.PLLPOST=0;       // PLLPOST (N1) 0=/2
10
   
11
   __builtin_write_OSCCONH(0x01);     // now the PLL is configured. set the value for {COSC, NOSC} with this function to switch to FRC with PLL
12
   __builtin_write_OSCCONL(0x01);     // Tell the CPU to perform the clock switch.
13
   while(j>0)                         // This loop is here to guarantee that the clock PLL has stabilized before program operation continues
14
   {
15
      if(OSCCONbits.LOCK) j--;
16
   }
17
}

Pins mappen:
1
static void set_pins()
2
{
3
   // some other stuff
4
   RPINR0bits.INT1R=47;  // use RPI47 / pin 26 for CLK-in
5
   TRISBbits.TRISB15=1;  // INT1/RB15 as input -> this can be removed (possibly)
6
7
   RPINR1bits.INT2R=46;  // use RPI46 / pin 25 for SYNC-in
8
   TRISBbits.TRISB14=1;  // RB14 / pin 25 for SYNC-in -> this can be removed (possibly)
9
   
10
   TRISBbits.TRISB13=1;  // RB13 / pin 24 for data A in
11
   TRISBbits.TRISB12=1;  // RB12 / pin 23 for data B in
12
   
13
   //SPI thingies
14
   __builtin_write_OSCCONL(OSCCON & (~(1<<6))); // clear bit 6
15
   RPOR0bits.RP20R=_RPOUT_SDO2;    // use RP20 / pin 12 for SDO2
16
   TRISAbits.TRISA4=0;             // set as output -> this can be removed (possibly)
17
18
   RPOR0bits.RP35R=_RPOUT_SCK2OUT; // use RP35 / pin 7 for SCLK2
19
   TRISBbits.TRISB3=0;             // set as output -> this can be removed (possibly)
20
   __builtin_write_OSCCONL(OSCCON | (1<<6));    // Set bit 6
21
22
   TRISBbits.TRISB4=0;   // set as output -> this can be removed (possibly)
23
   PORTBbits.RB4=1;      // set DAC-SYNC to HIGH
24
}

Externe Interrupts konfigurieren (hat nix mit SPI zu tun):
1
   INTCON2bits.GIE=1;    //enable "global" interrupts
2
   INTCON2bits.INT1EP=0; //interrupt INT1 on rising edge
3
   IFS1bits.INT1IF=0;    //Reset INT1 interrupt flag
4
   IEC1bits.INT1IE=1;    //Enable INT1 Interrupt Service Routine
5
6
   INTCON2bits.INT2EP=1; //interrupt INT2 on falling edge
7
   IFS1bits.INT2IF=0;    //Reset INT2 interrupt flag
8
   IEC1bits.INT2IE=1;    //Enable INT2 Interrupt Service Routine

SPI initialisieren:
1
static void init_spi()
2
{  
3
   // SPI2CON1 Register Settings
4
   SPI2CON1bits.DISSCK = 0; // Internal serial clock is enabled
5
   SPI2CON1bits.DISSDO = 0; // SDOx pin is controlled by the module
6
   SPI2CON1bits.MODE16 = 0; // Communication
7
   SPI2CON1bits.SMP = 1; // Input data is sampled at the middle of data output time
8
   SPI2CON1bits.CKE = 0; // Serial output data changes on transition from Idle clock state to active clock state
9
   SPI2CON1bits.SSEN = 0; // 0 = SSx pin is not used by the module; pin is controlled by port function
10
   SPI2CON1bits.CKP = 1; // Idle state for clock is a low-level;active state is a high-level
11
   SPI2CON1bits.MSTEN = 1; // Master mode enabled
12
13
   SPI2CON1bits.SPRE = 0b001; //Secondary prescaler value=5
14
   SPI2CON1bits.PPRE = 0b10; //3 //Primary prescaler=1
15
16
   SPI2CON2bits.FRMEN = 0; //0 = Framed SPIx support is disabled
17
   SPI2CON2bits.SPIBEN = 1; //Enhanced Buffer is enabled
18
19
   SPI2STATbits.SPIEN = 1; // Enable SPI module
20
   SPI2STATbits.SPIROV = 0; // Clear SPI2 receive overflow flag if set
21
22
   IFS2bits.SPI2IF = 0;              //Clear interrupt flag (no interrupt)
23
  //  IEC2bits.SPI2IE = 1;              //Enable SPI2 interrupts
24
}

Ein Byte senden (recv ist optional, macht aber keinen Unterschied):
1
static void spi2_send(const int data)
2
{
3
   volatile int recv;
4
5
   recv=SPI2BUF; // PIC expects a receive out of the buffer...
6
   SPI2BUF=data;
7
   while (!SPI2STATbits.SRMPT);
8
}

von Hermann U. (Firma: www.pcb-devboards.de) (gera82)


Lesenswert?

Ja was ist jetzt? was geht nicht, bleib hier hängen?:
while (!SPI2STATbits.SRMPT);

Kannst du in der Hardware debuggen?

RPOR0bits.RP20R=8;    // use RP20 / pin 12 for SDO2
RPOR0bits.RP35R=9;    // use RP35 / pin 7 for SCLK2

meins ist auch gleich:

RPO_SDO2     =  0b001000,
RPO_SCK2     =  0b001001,

PS:
ANSELA=0;
ANSELB=0;

;-)

: Bearbeitet durch User
von Svolvaer (Gast)


Lesenswert?

Hermann U. schrieb:
> Ja was ist jetzt? was geht nicht, bleib hier hängen?:
> while (!SPI2STATbits.SRMPT);

Ja, er kommt aus der while-Schleife nicht raus.

Was mich in deinem Code ein wenig überrascht, ist das da:
1
SPI2BUF=1;
2
SPI2BUF=2;
3
SPI2BUF=3;
4
SPI2BUF=4;
5
SPI2BUF=5;
6
SPI2BUF=6;
7
SPI2BUF=7;
8
SPI2BUF=8;

Ich hätte nirgends gesehen, dass der dsPIC einen Sende-FIFO hat, wie 
lange geht das denn mit dem einfach Reinschreiben gut?

von PICler (Gast)


Lesenswert?

Svolvaer schrieb:
> Ja, er kommt aus der while-Schleife nicht raus.

Hermann U. schrieb:
> Kannst du in der Hardware debuggen?

Du sollst doch in der Hardware testen, Simulation geht hier nicht.

Svolvaer schrieb:
> Was mich in deinem Code ein wenig überrascht, ist das da:

Das Teil hat ein 8x 8Bit TX und RX FIFO, kannst 8 Byte ohne Überprüfung 
senden, wenn du mehr brauchst gibst SPIBEC Register:
while (SPI2STATbits.SPIBEC > 0-7)

> SPI2CON2bits.SPIBEN = 1; //Enhanced Buffer is enabled
und wird hier eingeschaltet, wenn du das nicht brauchst kannst du es 
abschalten.

im Normal Buffer Mode, wird dann so gesendet:
1
    while(SPI2STATbits.SPITBF);
2
    SPI2BUF = Data;

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Hermann U. schrieb:
> meins ist auch gleich:

 meins ist länger.

von Hermann U. (Firma: www.pcb-devboards.de) (gera82)


Lesenswert?

Marc V. schrieb:
> meins ist länger.

träum weiter.



Svolvaer schrieb:
> Ich hätte nirgends gesehen, dass der dsPIC einen Sende-FIFO hat, wie

auf der Seite 222:
http://ww1.microchip.com/downloads/en/DeviceDoc/70005144e.pdf

teste doch mal in der Hardware, dein Programm sollte laufen.

Falls du später doch die Daten über SPI (SDI) empfangen willst, solltest 
du die PINs auf Digital umschalten, beliebter Fehler:

Zb.
ANSELA=0;
ANSELB=0;


The  ANSELx  register  has  a  default  value  of  0xFFFF.
Therefore,  all  pins  that  share  analog  functions  are
analog (not digital) by default.

von Svolvaer (Gast)


Lesenswert?

OK, mit
1
while (SPI2STATbits.SPIBEC > 0-meineDatenFürDenFifo)

funktioniert es jetzt - vielen Dank!

von Svolvaer (Gast)


Lesenswert?

Sorry, natürlich
1
while (SPI2STATbits.SPIBEC > 7-meineDatenFürDenFifo)

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.