Forum: Mikrocontroller und Digitale Elektronik Einrichtung SPI an dsPIC30F5011 für LTC6802-2


von Andre S. (gnano)


Lesenswert?

Guten Tag zusammen,

ich sitze seit einigen Tagen vor dem Problem meinen SPI für den 
dsPIC50F5011 aufzusetzen, um damit anschließend Spannungen aus dem LTC 
6802-2 auszulesen.

Ich habe jeweils die beiden SDO mit jeweils einem 10k Pull-Up versehen. 
Die Clock gibt ein brauchbares Signal, der SDO des PICs gibt am Scope 
allerdings nur murks. Es wird eine kurze Sequenz (sieht nach 2 Bits aus) 
ausgegeben und sonst eine kontinuierliche 0 oder Unsinn.

Ich verwende den XC16 Compiler in der neusten Version.

Mein Code sieht folgendermaßen aus:

SPI.h
1
#include "stdbool.h"
2
#include <stdint.h>
3
4
#ifndef SPI_H
5
#define SPI_H
6
7
8
//SPI1 Defines
9
#define SPI1_Interupt_Flag IFS0bits.SPI1IF
10
#define SPI1_Interupt_SPI1CON1_Register IEC0bits.SPI1IE
11
//#define SPI1_Internal_Serial_Clock SPI1CON1bits.DISSCK
12
#define SPI1_SDO1_Control_Mode SPI1CONbits.DISSDO //0 - Kontrolle durch Modul
13
#define SPI1_Control_Mode SPI1CONbits.MODE16 //8- oder 16-bit Kommunikation
14
#define SPI1_Data_Input_Sample_Phase SPI1CONbits.SMP
15
#define SPI1_Clock_Edge_Select SPI1CONbits.CKE
16
#define SPI1_Slave_Select_Enable SPI1CONbits.SSEN
17
#define SPI1_Clock_Polarity_Select SPI1CONbits.CKP
18
#define SPI1_Master_Mode_Enable SPI1CONbits.MSTEN
19
#define SPI1_Receive_Overflow_Flag SPI1STATbits.SPIROV
20
#define SPI1_Enable_Bit SPI1STATbits.SPIEN  
21
#define SPI1_Transmit_Buffer_Full_Status SPI1STATbits.SPITBF
22
#define SPI1_Receive_Buffer_Full_Status SPI1STATbits.SPIRBF 
23
#define SPI1_Framed_SPI_Support SPI1CONbits.FRMEN
24
#define SPI1_Buffer SPI1BUF 
25
26
void init_SPI1(bool enable_master_mode); //True: dsPIC als SPI Master; False: dsPIC als Slave
27
28
void sendData_SPI1(int data_out);
29
30
signed int readData_SPI1();
31
32
void SPI_check();
33
void init_LTC();
34
35
#endif

Die SPI.c:
1
#include "SPI.h"
2
#include "xc.h"
3
4
void init_SPI1(bool enable_master_mode){
5
   if(enable_master_mode == true) 
6
    {
7
       SPI1_Interupt_Flag = 0;
8
       SPI1_Interupt_SPI1CON1_Register = 0;
9
      
10
      //SPI1_Internal_Serial_Clock = 0;
11
      SPI1_SDO1_Control_Mode = 0;
12
      
13
      SPI1_Control_Mode = 0;
14
      SPI1_Data_Input_Sample_Phase = 0;
15
      SPI1_Clock_Edge_Select = 0;
16
      SPI1_Clock_Polarity_Select = 0;
17
      SPI1_Master_Mode_Enable = 1;
18
      SPI1_Enable_Bit = 1;
19
      SPI1_Buffer = 0x0000;
20
      
21
      SPI1_Interupt_Flag = 0;
22
      SPI1_Interupt_SPI1CON1_Register = 1;
23
      
24
    }   
25
}
26
27
28
void sendData_SPI1( int data_out)
29
{ 
30
31
   SPI1_Interupt_Flag=0; //falls vorher nicht richtig gelöscht
32
33
   if (SPI1_Control_Mode == 1) // word wide 
34
        SPI1_Buffer = data_out;
35
   else 
36
      SPI1_Buffer = data_out & 0xff; // byte wide
37
   
38
  // while(!SPI1_Interupt_Flag); //Warten bis vollständige Botschaft gesendet ->> Auskommentiert, da der PIC andauernd in dieser Schleife festhängt bzw. seine Ausführung stoppt
39
   
40
   SPI1_Interupt_Flag=0; //Zurücksetzen
41
42
   return;
43
}
44
45
46
signed int readData_SPI1(){
47
    
48
    signed int dummy;
49
    dummy = SPI1_Buffer; //reset Buffer
50
    
51
    while(!SPI1_Receive_Buffer_Full_Status);
52
53
    /* Status Full???*/
54
    if (SPI1_Receive_Buffer_Full_Status == 1)
55
    {
56
        SPI1_Receive_Overflow_Flag = 0;
57
        if (SPI1_Buffer)
58
            return ( SPI1_Buffer); //return word wide
59
        else
60
            return (SPI1_Buffer & 0xff); //return byte wide
61
    }
62
    return -1; //Buffer FULL wurde nicht gesetzt => Error
63
}
64
65
66
void Delay( uint16_t cycles )
67
{
68
    uint16_t temp;
69
    for( temp = 0; temp < cycles; temp++ );
70
}
71
72
void init_LTC()
73
{
74
    sendData_SPI1(0x0); 
75
    sendData_SPI1(0x01);
76
    sendData_SPI1(0x00);
77
    sendData_SPI1(0x00);
78
    sendData_SPI1(0x00);
79
    sendData_SPI1(0x00);
80
    sendData_SPI1(0x00);
81
    sendData_SPI1(0x00);
82
    sendData_SPI1(0x00);
83
    sendData_SPI1(0x00);
84
    
85
}
86
87
    init_SPI1(true);
88
    while(1)
89
    {
90
        if(button1_status==0) // Button woanders definiert !
91
        {
92
            sendData_SPI1(0x00);
93
            sendData_SPI1(0x11);
94
            unsigned int received = 0;
95
            received=readData_SPI1();
96
        }
97
    }


Ich hoffe jemand kann mich erleuchten ;)

Vielen Dank für jeden Hinweis.

Viele Grüße

von Torben K. (tokuhila)


Lesenswert?

1
>   // while(!SPI1_Interupt_Flag); //Warten bis vollständige Botschaft 
2
> gesendet ->> Auskommentiert, da der PIC andauernd in dieser Schleife 
3
> festhängt bzw. seine Ausführung stoppt
4
>    SPI1_Interupt_Flag=0; //Zurücksetzen

Wenn du in einen Eimer, der voll ist, was reinschüttest, läuft was über.

: Bearbeitet durch User
von Andre S. (gnano)


Lesenswert?

Wieso?

Soweit ich weiß wird das Flag gesetzt, wenn die Daten aus dem TX-Buffer 
in den Buffer gesendet wurde. Das heißt ich warte doch nur bis es auf 
dem Buffer liegt, dann kommt für das Flag eine 1 und die while wird 
beendet?

Davon abgesehen läuft es nicht egal ob die while auskommentiert ist oder 
nicht.

: Bearbeitet durch User
von Torben K. (tokuhila)


Lesenswert?

Was soll der PIC30 deiner Meinung nach machen, wenn du in den Puffer 
schreibst, der vorherige Puffer aber noch nicht ins Schieberegister 
übernommen wurde? Irgendwo anders zwischenspeichern? Die 
Programmausführung solange verzögern?

Du musst warten bis der Puffer leer ist, sprich ins SR übernommen wurde. 
Siehe dsPIC30F Family Reference Kapitel 51 SPI

Wenn du gleichzeitig Daten empfängst mußt du natürlich vorher SPIBUF 
auslesen sonst sind die empfangenen Daten futsch

: Bearbeitet durch User
von Michael K. (Gast)


Lesenswert?

Sowas hatte ich mal mit einem dsPIC30F4013.
Nach vielen Tagen Fehlersuche kam ein Kollege auf die Lösung:
Der SPI lag an einem Pin der alternativ auch vom ADC genutzt werden 
könnte.
In einem der ADC Register mußte der betreffende PIN explizt auf digital 
in gestellt werden. Das der ADC unbenutzt und abgeschaltet war hat dabei 
keine Rolle gespielt.
Die SPI Hardware bekommt sonst nur teilweise die Kontrolle über die pins 
was zu völlig obskuren Ergebnissen führt.

Es gingen trotzdem nicht alle SPI Modes aber das gehört bei den MC 
Käfern ja zum guten Ton.

von Volsvorg (Gast)


Lesenswert?

Ich glaube du musst bei den dsPIC30 den den Spibuffer immer erst 
auslesen bevor du ihn beschreiben kannst. Ist lange her das ich mit 
dsPICS30 gearbeitet habe. Ich meine das waren die beiden Stolpersteine 
der SPI. erstens der schon erwähnte Analog Port und das man den SPI 
Buffer immer erst auslesen muss. Sollte aber alles in den Reference 
Manuels stehen.

von Andre S. (gnano)


Lesenswert?

Verstehe ich damit die Änderungen folgendermaßen richtig:

Die sendData-Routine muss lediglich um ein Auslesen ergänzt werden und 
dann läuft auch die while Schleife?
1
void sendData_SPI1( int data_out)
2
{ 
3
   int dummy;
4
   dummy = SPI1_Buffer; // hier die Veränderung
5
6
   SPI1_Interupt_Flag=0; //falls vorher nicht richtig gelöscht
7
8
   if (SPI1_Control_Mode == 1) // word wide 
9
        SPI1_Buffer = data_out;
10
   else 
11
      SPI1_Buffer = data_out & 0xff; // byte wide
12
   
13
     while(!SPI1_Interupt_Flag);
14
   
15
   SPI1_Interupt_Flag=0; //Zurücksetzen
16
17
   return;
18
}

Über den SDO Pin b finde ich leider weder im Family Reference, noch im 
Manual etwas. Muss nur der SDO als digitaler Output gesetzt werden oder 
auch der SDI als digitaler Input? Wie funktioniert das?
Reicht da für z.B. SPI2 bereits aus:
1
TRISBbits.TRISB8= 0 // 0 - Output?

von Torben Kuhn (Gast)


Lesenswert?

> Die sendData-Routine muss lediglich um ein Auslesen ergänzt werden und
> dann läuft auch die while Schleife?

Sauber ist es, wenn man auch auf Write Collision prüft.

> Über den SDO Pin b finde ich leider weder im Family Reference, noch im
> Manual etwas.

Ich vermute du meist SDO2? Brille putzen, nochmals lesen. Steht alles im 
Datenblatt. Bzgl. TRIS: Figure 8-2 im Datenblatt.

> TRISBbits.TRISB8= 0 // 0 - Output?

Wenn du RB8 als Ausgang nutzen willst. Mit SPI hat der nix am Hut.

von Andre S. (gnano)


Lesenswert?

Torben Kuhn schrieb:
>> Die sendData-Routine muss lediglich um ein Auslesen ergänzt
> werden und
>> dann läuft auch die while Schleife?
>
> Sauber ist es, wenn man auch auf Write Collision prüft.

Aber funktionieren würde es auch erstmal so?



>> Über den SDO Pin b finde ich leider weder im Family Reference, noch im
>> Manual etwas.
>
> Ich vermute du meist SDO2? Brille putzen, nochmals lesen. Steht alles im
> Datenblatt. Bzgl. TRIS: Figure 8-2 im Datenblatt.
>
>> TRISBbits.TRISB8= 0 // 0 - Output?
>
> Wenn du RB8 als Ausgang nutzen willst. Mit SPI hat der nix am Hut.

Ich meinte RG 8 und habe mich vertippt.

Im Reference steht:

>The use of the ADPCFG and TRIS registers control the
>operation of the A/D port pins. The port pins that are
>desired as analog inputs must have their corresponding
>TRIS bit set (input). If the TRIS bit is cleared
>(output), the digital output level (VOH or VOL) will be
>converted.

Heißt die entsprechende Festlegung muss so aussehen?
1
TRISGbits.TRISG8= 0 // Tris cleared=0


Vielen Dank für alle bisherigen Hilfen :)

von Torben Kuhn (Gast)


Lesenswert?

> Heißt die entsprechende Festlegung muss so aussehen?

Irrelevant. Schau dir Figure 8-2 an.

von Andre S. (gnano)


Angehängte Dateien:

Lesenswert?

>> Heißt die entsprechende Festlegung muss so aussehen?
>
>Irrelevant. Schau dir Figure 8-2 an.

Ich stehe aktuell etwas auf dem Schlauch, was die Erkenntnis aus der 
Figure (habe ich mal angehängt) betrifft.

Sieht für mich so aus als müsste ich insgesamt zwei 0en setzen.

Eine für Output Enable (TRIS Register für den entsprechenden PIN) um 
Write TRIS zu verwenden und dann einmal eine 0 für Output Data (LAT 
Register für den entsprechenden PIN) um den gesamten Port als Output zu 
verwenden.

Was übersehe ich denn?

von Torben Kuhn (Gast)


Lesenswert?

Du übersiehst, dass der Output Multiplexer vom Peripheriemodul gesteuert 
wird. Es reicht also das SPI-Modul richtig zu konfigurieren, TRIS ist 
hier unnötig.

von Andre S. (gnano)


Lesenswert?

Torben Kuhn schrieb:
> Du übersiehst, dass der Output Multiplexer vom Peripheriemodul
> gesteuert
> wird. Es reicht also das SPI-Modul richtig zu konfigurieren, TRIS ist
> hier unnötig.

Vielen Dank für diese Erkenntnis!


Würde meine oben stehende send-Routine dann so funktionieren (auch wenn 
es noch) keine ganz ordentliche Lösung ist?


Kann ich den SSx Pin des dsPIC auch manuell high oder low setzten ohne 
die Verwendung des SSEN Bits?

von Torben K. (tokuhila)


Lesenswert?

> Würde meine oben stehende send-Routine dann so funktionieren (auch wenn
> es noch) keine ganz ordentliche Lösung ist?

Sollte eigentlich soweit funktionieren. Kenne den Rest vom Code nicht.

> Kann ich den SSx Pin des dsPIC auch manuell high oder low setzten ohne
> die Verwendung des SSEN Bits?

Nur wenn SSEN = 0, näheres im Family Reference Manual Abteilung SPI 
Abschnitt Pin Control

von Andre S. (gnano)


Lesenswert?

>> Kann ich den SSx Pin des dsPIC auch manuell high oder low setzten ohne
>> die Verwendung des SSEN Bits?
>
> Nur wenn SSEN = 0, näheres im Family Reference Manual Abteilung SPI
> Abschnitt Pin Control

Dort steht aber nicht explizit, wie ich den PIN dann high oder low 
setzte.
Es fehlt die Information, wie genau ich dies tue, jedenfalls sehe ich es 
- mal wieder - nicht :D

Im Manual finde ich nur soetwas für den SSX-Pin:

>Used to enable transmit/receive in Slave mode,
>if SSEN (SPI1CON<7>) has been set to ‘1’

Da ich den PIC aber als Master verwende fällt diese Option für mich 
flach.

Der Slave hingegen fordert:
>1. Pull CSBI low
>2. Send Address byte
>3. Send RDCV command
>4. Read CVR00 byte
>5. Pull CSBI high

Da der CSBI an dem Port SSX beim PIC hängt muss ich diesen entsprechend 
manuell low setzen. Der SSEN = 1 Modus würde eine Steuerung vom "Master" 
aus erlauben, da der PIC aber der Master ist fällt die Möglichkeit das 
ganze automatisch (intern) zu lösen weg.

von Andre S. (gnano)


Lesenswert?

> Im Manual finde ich nur soetwas für den SSX-Pin:
>
>>Used to enable transmit/receive in Slave mode,
>>if SSEN (SPI1CON<7>) has been set to ‘1’
>
> Da ich den PIC aber als Master verwende fällt diese Option für mich
> flach.

Bzw. ich habe es so verstanden, dass SSEN auch im Master-Mouds verwendet 
werden kann. Allerdings bin ich mir nicht sicher, ob der PIN dann an der 
richtigen Stelle automatisch high/low gesetzt wird. Denn ich habe es so 
verstanden das dann der Slave das Signal vorgibt.

von Torben K. (tokuhila)


Lesenswert?

Sorry, Kapitel befindet sich im Band 11 IO-Ports.

Section 11.3.1.2 Pin Control Summary

SSx heißt Slave-Select, d.h. der Master "addressiert" damit den Slave 
und dieser sollte/muß dann reagieren.

Im Master-Mode wird SSx nur im Framed-Modus automatisch bedient. Im 
Feld-Wald-Wiesen Master Mode mußt du das selbst machen. TRIS & LAT wie 
üblich.

: Bearbeitet durch User
von Dieter W. (dds5)


Lesenswert?

Torben K. schrieb:
> Im Feld-Wald-Wiesen Master Mode mußt du das selbst machen. TRIS & LAT
> wie üblich.

Wobei man in dem Fall jeden Portpin benutzen kann - sonst könnte man ja 
nie mehr als einen slave ansprechen.

von JamieL (Gast)


Lesenswert?

Ich habe zu dem Thema auch eine Frage:

Im Family Reference 
(http://ww1.microchip.com/downloads/en/DeviceDoc/70067E.pdf) steht, dass 
SCK1 und SCK2 als Input und als Output verwendet werden können.

Muss die CLK dann via TRIS, LAT so als Input/Output gesetzt werden oder 
geschieht das automatisch durch das CKP und CKE Register bei der 
Initialisierung?

Vielen Dank

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.