Forum: Mikrocontroller und Digitale Elektronik PIC Pin Konfiguration und SPI


von Wipffinder (Gast)


Angehängte Dateien:

Lesenswert?

Schönen Tag alle zusammen.
Dies ist mein erster Eintrag in diesem Forum und schon kommen Probleme. 
Leider half mir dieses mal die SuFu nicht.

Ich habe begonnen zu Hobbyzwecken (Synthesizer) 16bit PIC Controller zu 
programmieren. Ich habe bereits erfolgreich mit 8bit Typen gearbeitet. 
Nun ist ein für mich unerklärliches Problem aufgetreten.

Ich programmiere mit MPLab X und C und brenne mit PicKit3. Ziel ist es 
mit SPI ein DAC anzusprechen. SPI funktioniert fast. Und hier liegt das 
Problem. SS und Data Output funktionieren. Am Oszilloskop kann ich die 
richtige Bitfolge ablesen. Nur der SPI CLK tut rein gar nichts. Ich habe 
ein leichtes Übersprechen (durch lange Parallele Leiterbahnen) der Data 
Output Leitung. Deshalb denke ich, dass der Pin nicht als Output 
konfiguriert ist da Hochohmig.

Ich verwende den PIC pic24fj16mc101, das Pinout habe ich oben angehängt.
Unten folgt der Code mit dem ich die SPI Peripherie konfiguriere.

[c]
#define SPI_SS_TRIS      TRISBbits.TRISB4
#define SPI_SS_PORT      PORTBbits.RB4

void SPI1Init(void)
{
    //config SPI1
    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 = 1;  // set in 16-bit mode, clear in 8-bit mode
    SPI1CON1bits.SMP = 0;  // Input data sampled at mid of data output 
time
    SPI1CON1bits.CKP = 1;  // CKP and CKE is subject to change ...
    SPI1CON1bits.CKE = 1;  // ... based on your communication mode.
    SPI1CON1bits.MSTEN = 1;   // 1 =  Master mode; 0 =  Slave mode
    SPI1CON1bits.SPRE = 4;   // Secondary Prescaler = 4:1
    SPI1CON1bits.PPRE = 2;   // Primary Prescaler = 4:1

    SPI1CON2 = 0;  // non-framed mode
    SPI_SS_TRIS = 0;  // set SS as output

    SPI1STATbits.SPIEN = 1;   // enable SPI port, clear status
}
[\c]

Gesendet wird indem einfach ins entsprechende Register geschrieben wird. 
Den SS betätige ich momentan selber. Werde das dann noch ändern, ist 
aber nicht Teil des Problems.

[c]
unsigned short data = 0xAFAF;
SPI1BUF = data;
[\c]

Das Programm macht nun folgendes. SS und SPO funktionieren. SPI CLK 
macht nichts. Ich habe versucht ohne das ganze SPI Zeugs den PIN RB7 
(der PIN der mit dem SPI Clock belegt wird, falls SPI aktiv ist.) 
einfach mal über die entsprechenden TRIS und PORT Register auf High zu 
schalten. Für alle anderen Pins des B Registers gehts auch, nur nicht 
für diesen.

Was ich bis jetzt ausschliessen kann:
- Der SPI CLK kann nicht über remappable peripheral gemappet werden. 
(Laut Datasheet)

Mir fehlt nun der Ansatz das Problem zu lösen. Falls also jemand bereits 
ein ähnliches Problem lösen konnte könntet ihr mir sehr helfen.
Gruss Wipffinder

von Patrick B. (p51d)


Lesenswert?

Wie werden die Pins initialisiert?
Hast du auf irgend einem anderen Pin das CLK Signal?
Wie werden die Pins gemappt (sicher das es richtig ist?).
Richtig die configs gesetzt?



Hab mir mal den Beispielcode angesehen:
1
#include "p24fxxxx.h"
2
3
#ifdef __PIC24FJ128GA010__  //Defined by MPLAB when using 24FJ256GB110 device
4
  // JTAG/Code Protect/Write Protect/Clip-on Emulation mode
5
  // Watchdog Timer/ICD pins select
6
  _CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx2) 
7
  // Disable CLK switch and CLK monitor, OSCO or Fosc/2, HS oscillator,
8
  // Primary oscillator
9
  _CONFIG2(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMOD_HS & FNOSC_PRIPLL)
10
#endif
11
12
// RB2 as SS for SPI slave MCU
13
#define SPI_SS_TRIS      TRISBbits.TRISB2
14
#define SPI_SS_PORT      PORTBbits.RB2
15
16
unsigned short spiBufT[]={0x00ac,0x05a0,0xa500,0};  // for demo only
17
unsigned short spiBufR[]={0,0,0,0};  // SPI buffer for Receiving
18
19
void SPI1Init(void)
20
{
21
    //config SPI1
22
    SPI1STATbits.SPIEN     = 0;  // disable SPI port
23
    SPI1STATbits.SPISIDL   = 0;   // Continue module operation in Idle mode
24
    
25
    SPI1BUF         = 0;     // clear SPI buffer
26
    
27
    IFS0bits.SPI1IF     = 0;  // clear interrupt flag
28
    IEC0bits.SPI1IE     = 0;  // disable interrupt
29
    
30
    SPI1CON1bits.DISSCK    = 0;  // Internal SPIx clock is enabled
31
    SPI1CON1bits.DISSDO    = 0;  // SDOx pin is controlled by the module
32
    SPI1CON1bits.MODE16   = 1;  // set in 16-bit mode, clear in 8-bit mode
33
    SPI1CON1bits.SMP    = 0;  // Input data sampled at middle of data output time
34
    SPI1CON1bits.CKP     = 1;  // CKP and CKE is subject to change ...
35
    SPI1CON1bits.CKE     = 0;  // ... based on your communication mode.
36
  SPI1CON1bits.MSTEN     = 1;   // 1 =  Master mode; 0 =  Slave mode
37
  SPI1CON1bits.SPRE     = 4;   // Secondary Prescaler = 4:1
38
  SPI1CON1bits.PPRE     = 2;   // Primary Prescaler = 4:1
39
  
40
    SPI1CON2         = 0;  // non-framed mode
41
    
42
  SPI_SS_PORT        = 1;  // 
43
  SPI_SS_TRIS        = 0;  // set SS as output
44
  
45
    SPI1STATbits.SPIEN     = 1;   // enable SPI port, clear status
46
}
47
48
unsigned short writeSPI1( unsigned short data )
49
{
50
    SPI1BUF = data;          // write to buffer for TX
51
    while(!SPI1STATbits.SPIRBF);  // wait for transfer to complete
52
    return SPI1BUF;            // read the received value
53
}//writeSPI1
54
55
int main (void)
56
{
57
  unsigned short i;
58
  
59
  // Disable Watch Dog Timer
60
  RCONbits.SWDTEN = 0;
61
  // for LED
62
  ODCAbits.ODA6 = 0;
63
  TRISAbits.TRISA6 = 0;
64
65
  SPI1Init();
66
  
67
    while (1) {
68
      for (i=0; i<0xffff; i++);  // a simple delay
69
    
70
    SPI_SS_PORT  = 0;
71
    spiBufR[0]  = writeSPI1(spiBufT[0]);
72
    spiBufR[1]  = writeSPI1(spiBufT[1]);
73
    spiBufR[2]  = writeSPI1(spiBufT[2]);
74
    spiBufR[3]  = writeSPI1(0);
75
    SPI_SS_PORT = 1;
76
77
      __builtin_btg((unsigned int *)&LATA, 6);
78
  } 
79
80
  return 0;
81
}

: Bearbeitet durch User
von Wipffinder (Gast)


Lesenswert?

>Wie werden die Pins initialisiert?
Nachdem SPIenable auf 1 gesetzt wird, funktioniert der SDO (SPI DATA 
OUT) und der SS bereits richtig. Ich brauche also nicht vorher die Pins 
über TRISx = 0x0000 als Output zu initialisieren. Nur der CLK geht halt 
nicht. Auch wenn ich diesen Pin vorher über das TRIS Register als Output 
setzte, geht der CLK nicht.

>Hast du auf irgend einem anderen Pin das CLK Signal?
Das CLK Signal befindet sich auf keinem anderen Pin, habe alle 
durchprobiert und nichts gefunden.

>Wie werden die Pins gemappt (sicher das es richtig ist?).
Auf die Pins die gemappet werden können, kann nur der SPI SS gemappt 
werden, andere SPI Peripherie ist an den vorgegebenen Pin gebunden.

>Richtig die configs gesetzt?
Der Code den du gepostest hast ist genau der den ich verwendet habe.

Kann es sein das nach dem Reset bereits eine Peripherie standartgemäss 
aktiv ist?
Im Pinout stehen für den Pin der SPI CLK folgende Möglichkeiten:
FLTA1/SCK1/INT0/RP7/CN23/RB7
Ich kann SCK1 und RB7 nicht als Output nutzen. Ich vermute im Moment, 
dass es am FLTA1 liegt, aber ich begreif einfach das Datasheet nicht.

Laut Datasheet
The PWM Fault pins are enabled and asserted during any reset event. 
Refer to Section 15.2 “PWM Faults” for more information on the PWM 
faults.

Nur leider finde ich dort nicht mehr Informationen (die ich verstehe).

von Frank K. (fchk)


Lesenswert?

Wipffinder schrieb:

> Ich kann SCK1 und RB7 nicht als Output nutzen. Ich vermute im Moment,
> dass es am FLTA1 liegt, aber ich begreif einfach das Datasheet nicht.

Setze mal die PxFLTACON Register auf 0. Damit sollte der Pin freigegeben 
werden. Das Schreiben erfordert eine Unlock-Sequenz, die auf Seite 142 
des Datenblatts steht.

fchk

von Wipffinder (Gast)


Lesenswert?

@Frank K.
Genau das war das Problem, danke vielmals.
Nun noch zwei Fragen:
- Warum gibt es diese Unlocksequenz bzw. warum ist das Register 
gesperrt?
- Mir funktioniert die Unlocksequenz nur mit Inlineassembler
[c]
asm("mov #0xabcd,w10");
asm("mov #0x4321,w11");
asm("mov #0x0000,w0");
asm("mov w10, PWM1KEY");
asm("mov w11, PWM1KEY");
asm("mov w0,P1FLTACON");
[\c]
mit c gehts nicht
[c]
PWM1KEY = 0xABCD;
PWM1KEY = 0x4321;
P1FLTACON = 0x0000;
[\c]
Ist der Umweg über die Register w10, w11 und w0 Teil der Unlocksequenz?

Dankbare Grüsse
Wipffinder

von Klaus (Gast)


Lesenswert?

Ob das wirklich mit dem Problem des TO zu tun hat, weiß ich nicht, aber 
in C geht's so
1
__builtin_write_PWMSFR(&P1FLTACON, 0x0000, &PWM1KEY);

MfG Klaus

von Frank K. (fchk)


Lesenswert?

Wipffinder schrieb:
> @Frank K.
> Genau das war das Problem, danke vielmals.
> Nun noch zwei Fragen:
> - Warum gibt es diese Unlocksequenz bzw. warum ist das Register
> gesperrt?

Dieser Pin ist Teil einer Hardware-Sicherheitsfunktion und soll nicht 
versehentlich abgeschaltet werden können, wenn das Programm Amok läuft.

> [\c]

nimm den / und nicht den \

> mit c gehts nicht
> PWM1KEY = 0xABCD;
> PWM1KEY = 0x4321;
> P1FLTACON = 0x0000;
Die drei Schreibzugriffe müssen innerhalb einer bestimmten Anzahl an 
Takten passieren, sonst wird nicht entsperrt. Das macht der C-Code 
nicht. Das gibts auch an anderen Stellen bei PIC24/dsPIC

von Wipffinder (Gast)


Lesenswert?

Jetzt wird mir einiges klar. Und sorry wegen \/
Danke

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.