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
voidinit_SPI1(boolenable_master_mode);//True: dsPIC als SPI Master; False: dsPIC als Slave
27
28
voidsendData_SPI1(intdata_out);
29
30
signedintreadData_SPI1();
31
32
voidSPI_check();
33
voidinit_LTC();
34
35
#endif
Die SPI.c:
1
#include"SPI.h"
2
#include"xc.h"
3
4
voidinit_SPI1(boolenable_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
voidsendData_SPI1(intdata_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
signedintreadData_SPI1(){
47
48
signedintdummy;
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
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.
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
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.
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.
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
voidsendData_SPI1(intdata_out)
2
{
3
intdummy;
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:
> 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.
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?
>> 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?
Du übersiehst, dass der Output Multiplexer vom Peripheriemodul gesteuert
wird. Es reicht also das SPI-Modul richtig zu konfigurieren, TRIS ist
hier unnötig.
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?
> 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
>> 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.
> 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.
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.
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.
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