Forum: Mikrocontroller und Digitale Elektronik PIC24 SPI-BUS für DAC MCP4822 // kein Clock signal


von Patrick B. (Gast)


Lesenswert?

Hallo,

Verwendeter Mikrocontroller: PIC24HJ128GP502
Digital Analog Converter   : MCP4822
Programmierumgebung        : MPLAB

ich versuche momentan einen SPI-BUS an einem PIC24HJ128GP502 
Mikrocontroller zu Programmieren.

Der Mikrocontroller soll als Master mit einem MCP4822 DAC kommunizieren. 
Dazu sind folgende Leitungen notwendig: SCK,SDO,SS(CS).

Mein Problem ist nun das ich kein Clock-Signal am SCK PIN messen kann. 
Damit funktioniert meine ganze SPI-Übertragung nicht. Ich habe schon ca. 
40 Stunden im Internet herumgesucht und diverse dinge getestet, jedoch 
ohne Erfolg.

Hier nun mein Code:
1
void spi_2_init(void)
2
{
3
   /*  Definieren der PINs für MCP4822  */
4
5
       #define CONTROLLER_MOSI_SPI2_TRIS  _TRISB12
6
  #define CONTROLLER_MOSI_SPI2_PIN   _LATB12
7
  #define CONTROLLER_SCK_SPI2_TRIS   _TRISB13
8
  #define CONTROLLER_SCK_SPI2_PIN    _LATB13
9
10
        #define CONTROLLER_SS_SPI2_TRIS   _TRISB0
11
        #define CONTROLLER_SS_SPI2_PIN    _LATB0
12
13
  #define REGISTER_MAP_SPI2_DO  _RP12R
14
  #define REGISTER_MAP_SPI2_SCK _RP13R
15
    
16
  OSCCONbits.IOLOCK = 0;
17
  REGISTER_MAP_SPI2_DO = 0b01010; /* Set as SPI DO */
18
  REGISTER_MAP_SPI2_SCK = 0b01011; /* Set as SCK */
19
  OSCCONbits.IOLOCK = 1;
20
21
  CONTROLLER_MOSI_SPI2_TRIS = 0;
22
  CONTROLLER_SCK_SPI2_TRIS = 0;
23
  CONTROLLER_SS_SPI2_TRIS = 0;
24
25
   
26
/* SPI setup based on sample code from datasheet */
27
28
29
        
30
  IFS2bits.SPI2IF = 0; /* Clear the Interrupt Flag */
31
  IEC2bits.SPI2IE = 0; /* Disable the Interrupt */
32
33
  /* SPI2CON1 Register Settings */
34
  SPI2CON1bits.DISSCK = 0; /* Internal Serial Clock is Enabled */
35
  SPI2CON1bits.DISSDO = 0; /* SDOx pin is controlled by the module */
36
  SPI2CON1bits.MODE16 = 0; /* Communication is word-wide (16 bits) */
37
  SPI2CON1bits.SMP = 0;    /* Input data is sampled at the middle of data */
38
  SPI2CON1bits.CKE = 0;    /* Serial output data changes on transition */
39
40
41
  SPI2CON1bits.CKP = 0;    /* Idle state for clock is a low level */
42
43
  SPI2CON1bits.PPRE = 0b11;  /* Primary prescale = 1:1 */
44
  SPI2CON1bits.SPRE = 0b001; /* Secondary prescale = 4:1 */
45
46
47
  SPI2CON1bits.MSTEN = 1;  /* Master mode Enabled */
48
  SPI2STATbits.SPIEN = 1;  /* Enable SPI module */

Ich bin noch nicht recht frisch was das PIC-Programmieren angeht, 
deshlab bitte ein wenig nachsicht ;)

Gruß Patrick

von Dieter W. (dds5)


Lesenswert?

Um das IOLOCK Bit zu manipulieren bedarf es einer besonderen Technik, 
nur allein ein Bitbefehl reicht da nicht.

Der alte C-Compiler stellt dazu __builtin Funktionen zur Verfügung.
Ob die im neuen XC auch vorhanden sind weiss ich nicht.

__builtin_write_OSCCONL(OSCCON & ~(1<<IOLOCK)); //release IOLOCK
__builtin_write_OSCCONL(OSCCON | (1<<IOLOCK));  //engage IOLOCK


Es ist außerdem ratsam, sämtliche Analogeingänge zu deaktivieren da sie 
Vorrang vor den Digitalfunktionen der Pins haben.

AD1PCFGL = 0xFFFF;      //no analog inputs used

von Patrick B. (Gast)


Lesenswert?

Hallo,

habe mal die Vorschläge wie folgt umgesetzt:
1
/*  Definieren der PINs für MCP4822  */
2
       #define CONTROLLER_MOSI_SPI2_TRIS  _TRISB12
3
  #define CONTROLLER_MOSI_SPI2_PIN   _LATB12
4
  #define CONTROLLER_SCK_SPI2_TRIS   _TRISB13
5
  #define CONTROLLER_SCK_SPI2_PIN    _LATB13
6
7
        #define CONTROLLER_SS_SPI2_TRIS   _TRISB0
8
        #define CONTROLLER_SS_SPI2_PIN    _LATB0
9
10
  #define REGISTER_MAP_SPI2_DO  _RP12R
11
  #define REGISTER_MAP_SPI2_SCK _RP13R
12
13
    AD1PCFGL = 0xFFFF;      //no analog inputs used
14
15
        __builtin_write_OSCCONL(OSCCON | (1<<OSCCONbits.IOLOCK));
16
  REGISTER_MAP_SPI2_DO = 0b01010; /* Set as SPI DO */
17
  REGISTER_MAP_SPI2_SCK = 0b01011; /* Set as SCK */
18
  __builtin_write_OSCCONL(OSCCON & ~(1<<OSCCONbits.IOLOCK));

Jedoch war wieder kein Clock messbar.

Bei einer SPI - Übertragung ist doch der Clock auch messbar wenn keine 
Daten übertragen werden, oder ?

Gruß Patrick

von Klaus (Gast)


Lesenswert?

Patrick B. schrieb:
> Bei einer SPI - Übertragung ist doch der Clock auch messbar wenn keine
> Daten übertragen werden, oder ?

Nein

MfG Klaus

von Patrick B. (Gast)


Lesenswert?

Hallo,

um mal eine Datenübertragung zu simulieren habe ich folgendes nach dem 
oben stehendem Code eingefügt:
1
uint8_t counter_2;
2
3
  while(1) {
4
5
                CONTROLLER_SS_SPI2_PIN = 1;
6
7
                while (SPI2STATbits.SPITBF);                    */
8
    SPI2BUF = (counter_2 & 0x00FF);
9
    while(!SPI2STATbits.SPIRBF); /* Wait until TX finished */
10
             
11
    uint8_t read_2;
12
13
    read_2 = SPI2BUF; 
14
    __delay_ms(1); /* Wait 1 ms */
15
16
    counter_2++;
17
18
                 CONTROLLER_SS_SPI2_PIN = 0;
19
        }

Jetzt bekomme ich für ein paar Sekunden das CS-Signal aber kein Clock...

Hat jemand einen Tipp ?

Wäre sehr dankbar.

Gruß Patrick

von WehOhWeh (Gast)


Lesenswert?

Meine Fehler sind immer folgende:

- ANSELx gesetzt. Einige IO-Banks haben das per Default.
- Falschen PIN konfiguriert (ein Fehler beim Remapping)
- Clockdivider falsch / out of spec.
- Er hängt bei SPITBF/SPIRBF.


Es gab da irgendein dummes Problem, dass er da immer hängt, wenn man den 
Receivebuffer nicht liest oder so ähnlich. Aber das tust du eigentlich.

Hast du da mal einen Debugger reingehängt?

Falls Interesse besteht, könnte ich dir meine SPI zukommen lassen (für 
PIC24FJ126GC006, aber das ist vermutlich sehr ähnlich). Allerdings erst 
Abends.

von Andi S. (andi1111)


Lesenswert?

Muss das CS-Signal nicht 0 sein, wenn man kommunizieren will?
also
1
CONTROLLER_SS_SPI2_PIN = 0; !!!!
2
    while (SPI2STATbits.SPITBF);                    */
3
    SPI2BUF = (counter_2 & 0x00FF);
4
    while(!SPI2STATbits.SPIRBF); /* Wait until TX finished */
5
             
6
    uint8_t read_2;
7
8
    read_2 = SPI2BUF; 
9
    __delay_ms(1); /* Wait 1 ms */
10
11
    counter_2++;
12
CONTROLLER_SS_SPI2_PIN = 1;   !!!!!!!!!

Ich hatte mal Ärger mit dem SPIROV-Bit. Lösch das einfach vor jeder 
SPI-Aktion.

>bekomme ich für ein paar Sekunden das CS-Signal aber kein Clock.

Ein paar Sekunden ist ziemlich lang.
Hängt sich die Routine vieleicht irgendwo auf?

von Patrick B. (Gast)


Lesenswert?

Hallo,

@wehohweh: Wäre echt freundlich von dir mir den Code zukommen zu lassen.
Meine Emailadresse: Patze1991@gmx.net



ich werde die Punkte die du geschrieben hast
1
Meine Fehler sind immer folgende:
2
3
- ANSELx gesetzt. Einige IO-Banks haben das per Default.
4
- Falschen PIN konfiguriert (ein Fehler beim Remapping)
5
- Clockdivider falsch / out of spec.
6
- Er hängt bei SPITBF/SPIRBF.
7
8
9
Es gab da irgendein dummes Problem, dass er da immer hängt, wenn man den 
10
Receivebuffer nicht liest oder so ähnlich. Aber das tust du eigentlich.
11
12
Hast du da mal einen Debugger reingehängt?

durchgehen und versuchen diese zu überprüfen / implementieren.

Gruß Patrick

von WehOhWeh (Gast)


Lesenswert?

Patrick B. schrieb:
> @wehohweh: Wäre echt freundlich von dir mir den Code zukommen zu lassen.
> Meine Emailadresse: Patze1991@gmx.net

Das war ein Feher. Niemals eine Emailadresse in ein Forum posten. Wenn 
du Pech hast, dann hat sie ein Bot schon erbeutet und du bekommst 
zukünftig tolle Angebote für Potenzfördernde Medikamente oder 
Hilfeersuchen von Nigerianischen Astronauten :-(

Wenn du die Emailadresse schnell herauswirfst, wirst du vielleicht noch 
Glück haben.

Ich poste das hier rein, fertig.

Es gäbe für die Zwischenzeit aber noch andere Quellen:
http://www.engscope.com/pic24-tutorial/
https://www.microchip.com/CodeExamplesByFunc.aspx

Bei den Codeexamples gibts ein Beispiel.

von WehOhWeh (Gast)


Angehängte Dateien:

Lesenswert?

Anbei die SPI.
Das ist eigentlich eine Ansteuerung für ein GLCD (DOGS 102), die 
verwendet aber die SPI des PIC.

Die initfunktion ist:
1
void init_hardware(uint8_t g_enable)
2
{
3
    if(g_enable == 1)
4
    {
5
        //switch power on
6
        oDISP_POWER = 0;
7
        tDISP_POWER = 0;
8
9
        //Special function pins
10
        oDISP_NRST      = 0;    //set display in reset
11
        tDISP_NRST      = 0;
12
        oDISP_CD        = 0;    //default : command
13
        tDISP_CD        = 0;
14
        //SPI
15
        oDISP_NCSN      = 0;
16
        tDISP_NCSN      = 0;
17
        oDISP_SCK       = 0;
18
        tDISP_NCSN      = 0;
19
        oDISP_MOSI      = 0;
20
        tDISP_MOSI      = 0;    //INOUT : default is OUT
21
22
        /*initialize SPI*/
23
        //attach remappable pins to SPI module
24
        //RPINR20bits.SDI1R = 21; //RP21 = oDISP_MOSI (BIDIR)
25
        OSCCON = 0x46;
26
        OSCCON = 0x57; //unlock sequence 46,57
27
        OSCCONbits.IOLOCK = 0;
28
        RPOR14bits.RP28R   = 8;  //RP19 = oDISP_SCK (Clockout) RB4 RP28
29
        RPOR9bits.RP18R  = 7;  //RP21 = oDISP_MOSI (BIDIR RB5 RP18
30
        OSCCONbits.IOLOCK = 1;
31
        //RPOR13bits.RP26R  = 9;  //RP26 = oDISP_NCSN (chipselect)
32
33
34
        //init SPI module : no Interrupt, 8MHz SPI clock
35
        SPI1CON1 = SPI1CON2 = 0;
36
        SPI1CON1bits.DISSCK     = 0;    //SPI clock Enable
37
        SPI1CON1bits.DISSDO     = 0;    //SPI data out enable
38
        SPI1CON1bits.MODE16     = 0;    //bytewise communication
39
        SPI1CON1bits.SMP        = 0;
40
        SPI1CON1bits.CKE        = 0;
41
        SPI1CON1bits.SSEN       = 0;
42
        SPI1CON1bits.CKP        = 1;    //clock is active low
43
        SPI1CON1bits.MSTEN      = 1;    //master mode
44
        SPI1CON1bits.SPRE       = 0b111;//Secondary Clock Prescale 1:1
45
        SPI1CON1bits.PPRE       = 0b11; //Primary Prescaler 1:1
46
                                        //--> SPI-Clock = 8MHz
47
        SPI1CON2bits.FRMEN      = 0;    //Framed SPI Support disabled
48
        SPI1CON2bits.SPIFSD     = 0;    //Framed SPI pulse output
49
        SPI1CON2bits.SPIFPOL    = 0;    //Frame Sync Pulse output
50
        SPI1CON2bits.SPIFE      = 0;    //Frame Sync Pulse Polarity active low
51
        SPI1CON2bits.SPIBEN     = 1;    //Enhanced Buffer Mode Disabled
52
53
        SPI1STATbits.SPIROV     = 0;    //Overflow Flag rücksetzen
54
        SPI1STATbits.SPIEN      = 1;    //SPI-Modul 1 Enable
55
        SPI1STATbits.SISEL      = 0b100;    //Interrupt, if TX FIFO is writable
56
    }
57
    else
58
    {
59
        SPI1STATbits.SPIEN      = 0;    //SPI-Modul 1 Enable
60
        SPI1CON1 = SPI1CON2 = 0;
61
62
        //switch all to out and drive Low
63
        tDISP_NRST = oDISP_NRST = 0;
64
        tDISP_NCSN = oDISP_NCSN = 0;
65
        tDISP_MOSI = oDISP_MOSI = 0;
66
        tDISP_CD   = oDISP_CD   = 0;
67
        tDISP_SCK  = oDISP_SCK  = 0;
68
         //switch power off
69
        oDISP_POWER = 1;
70
    }
71
}

SPI-Transfer ist:
1
inline uint8_t SPI_WRITE(uint8_t IN)
2
{
3
    SPI1BUF = IN;          // write to buffer for TX
4
    while(SPI1STATbits.SPITBF);// wait for transfer to complete
5
    return SPI1BUF;            // read the received value
6
}//writeSPI2

ACHTUNG: Chipselect wird hier nicht bedient, das müsste man eventuell 
dazutun.

So wie das jetzt konfiguriert ist, ist es mit glaube ich 8MHz 
SPI-Frequenz - kein Teiler. Weil das RAM des Display < 1kByte groß ist, 
habe ich mich nicht mit Interrupts oder DMA gequält - mit 8MHz geht das 
auch so schnell genug.

Ich hätte ein Beispiel mit DMA allerdings auch noch herumfliegen...

Einschränkend muss ich sagen, dass ich noch nie auch nur ein einzelnes 
Bit vom Display gelesen habe, funktionieren sollte es aber. Das 
Schreiben geht aber sicher.

von Patrick (Gast)


Lesenswert?

Hallo,

der Fehler war das ich
1
void spi_2_init(void)
genommen habe. Die (void) lies es nicht zu das die Funktion abgefragt 
werden konnte... ^^

Clock und Enable Signal kommen nun

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.