Forum: Mikrocontroller und Digitale Elektronik dsPIC33EV32GM102 Direct Memory Access


von Robin (Gast)


Lesenswert?

Morgen Leute,

ich habe da ein kleines Problem mit meinem dsPIC33EV32GM102. Und zwar 
schreibt er irgendwie die Konfiguration der DMA Kanäle nicht in die 
Register (jedenfalls laut PICkit3 Debugger) und dementsprechend 
funktioniert auch DMA nicht.

Hatte jemand schonmal so ein Problem?

Danke und Grüße

Robin

von Michael K. (Gast)


Lesenswert?

Ja, wir hatten hier schon oft das Problem das jemand Hilfe zu seinem 
Code sucht den er uns aber nicht zeigt.

von Robin (Gast)


Lesenswert?

Michael K. schrieb:
> Ja, wir hatten hier schon oft das Problem das jemand Hilfe zu seinem
> Code sucht den er uns aber nicht zeigt.

Letztes Mal als ich meinen Code direkt mit eingefügt habe, habe ich erst 
gar keine Antwort bekommen...

Das ist die Funktion die Nachrichten sendet: Meine Konfiguration 
speichert er inzwischen in den Registern aber er überträgt den Wer aus 
canbuf nicht in C1TXD...
1
bool SendMessage(uint16_t data_bytes[])
2
{
3
    /*      CAN data frame                                                     *
4
     *                                                                         *
5
     * Word 0:                                                                 *
6
     * bit 13-15    unimplemented                                              *
7
     * bit 2-12     Standard Identifier (SID)                                  *
8
     * bit 1        SRR - Substitute Remote Request bit                        *
9
     *              0 (normal message) - 1 (request remote message)            *
10
     *              MUST be 1 for extended message format                      *
11
     * bit 0        IDE bit - Identifier Extension bit                         *
12
     *              0 (standard message format) - 1 (extended message format)  *
13
     *                                                                         *
14
     * Word 1:                                                                 *
15
     * bit 12-15    unimplemented                                              *
16
     * bit 0-11     Extended Identifier (EID)                                  *
17
     *                                                                         *
18
     * Word 2:                                                                 *
19
     * bit 10-15    Extended Identifier (EID)                                  *
20
     * bit 9        Remote Transmission Request (RTR)                          *
21
     *              0 (normal message) - 1 (request remote transmission)       *
22
     *              IGNORED for standard message format                        *
23
     * bit 8        RB1 bit - MUST be set to 0                                 *
24
     * bit 5-7      unimplemented                                              *
25
     * bit 4        RB0 - MUST be set to 0                                     *
26
     * bit 0-3      Data Length Code - Numnber of bytes to send                * 
27
     *                                                                         *
28
     * Word 3:                                                                 *
29
     * bit 8-15     message byte 1                                             *
30
     * bit 0-7      message byte 0                                             *       
31
     *                                                                         *
32
     * Word 4:                                                                 *
33
     * bit 8-15     message byte 3                                             *
34
     * bit 0-7      message byte 2                                             *       
35
     *                                                                         *
36
     * Word 5:                                                                 *
37
     * bit 8-15     message byte 5                                             *
38
     * bit 0-7      message byte 4                                             *       
39
     *                                                                         *
40
     * Word 6:                                                                 *
41
     * bit 8-15     message byte 7                                             *
42
     * bit 0-7      message byte 6                                             *       
43
     *                                                                         *
44
     * Word 7:                                                                 *
45
     * bit 0-15     unimplemented                                              *      
46
     *                                                                        */
47
    
48
    
49
    unsigned int i, k, n;
50
    unsigned int j = 0;
51
    unsigned int number_of_bytes = sizeof(data_bytes)+1;
52
    
53
    n = (number_of_bytes/8)+1; //determine how many messages are needed
54
    if(number_of_bytes % 8 == 0) n--;
55
    for(k=0;k<n;k++) //send n messages 
56
    {
57
        for(i=0;i<3;i++) canbuf[0][i] = 0; //reset send buffer
58
        for(i=3;i<8;i++) canbuf[0][i] = 0xDEAD; //reset send buffer
59
60
        //save message to buffer
61
        canbuf[0][0] = (SID_OF_MAIN_CONTROLLER << 2) | 0x0003; //SID and send extended message 
62
        canbuf[0][1] = 0x000; //write EID
63
        if((number_of_bytes - k*8) <= 8) canbuf[0][2] = number_of_bytes;
64
        else canbuf[0][2] = 0x0008; //number of bytes to send
65
    
66
        if(canbuf[0][2] % 2 != 0) //if odd number of bytes to send write highest one out of normal flow
67
        {
68
            canbuf[0][3+(canbuf[0][2]/2)] = data_bytes[number_of_bytes - 1];
69
        }
70
        
71
        for(i=0;i<(canbuf[0][2]/2);i++)
72
        {
73
            canbuf[0][i+3] = data_bytes[j+1] << 8; //place upper byte
74
            canbuf[0][i+3] = canbuf[0][i+3] | (data_bytes[j] & 0x00FF); //place lower byte  
75
            j = j+2;
76
        }
77
78
        C1TR01CONbits.TXREQ0 = 1; //request message sending
79
    
80
        while(C1TR01CONbits.TXREQ0 == 1 && !C1INTFbits.ERRIF && !C1INTFbits.IVRIF); //wait for transmission
81
        if(C1INTFbits.ERRIF || C1INTFbits.IVRIF) //if error occured
82
        {
83
            C1TR01CONbits.TXREQ0 = 0; //request message abort in case of error
84
            while(C1TR01CONbits.TXABT0 == 0) //wait for transmission to be aborted
85
            DMA1CONbits.CHEN = 0; //toogle DMA1 channel enale to reset Force bit
86
            DMA1CONbits.CHEN = 1;
87
                  
88
            return false;
89
        }
90
    }
91
  
92
    return true; //messages sent without errors
93
}



Hier noch die Initialisierung zu canbuf:
1
unsigned int canbuf[NUM_OF_ECAN_BUFFERS][8] 
2
__attribute__((aligned(NUM_OF_ECAN_BUFFERS * 16))); //16 buffers with 8 words each (256 byte)




Und hier die CAN und DMA Initialisierung:
1
//CAN
2
    C1CTRL1bits.REQOP = 0b100; //Switch to configuration mode
3
    while(C1CTRL1bits.OPMODE != 0b100); //Wait for operation mode to change
4
    
5
    C1CTRL1bits.WIN = 1; //filter window
6
    C1CTRL1bits.CSIDL = 0; //CAN module continues operation in device IDLE
7
    C1CTRL1bits.CANCKS = 0; //F_CAN is equal to F_P=17,5MHz
8
    C1CFG1bits.BRP = 0b000111; //T_Q is 2x7x1/F_CAN= 800ns 
9
    C1CFG1bits.SJW = 0b00; //SJW is 1T_Q
10
    C1CFG2bits.PRSEG = 0b100; //Prop segment is 3T_Q
11
    C1CFG2bits.SEG1PH = 0b100; //Segment 1 is 3T_Q
12
    C1CFG2bits.SEG2PH = 0b100; //Segment 2 is 3T_Q
13
    C1CFG2bits.SEG2PHTS = 0; 
14
    C1CFG2bits.SAM = 1; //Bus line is sampled three times per sample point
15
    C1CFG2bits.WAKFIL = 0; //CAN bus line filter is used for wake up
16
    C1FEN1 = 0x3FFF; //Enable Filter 0:13
17
    C1BUFPNT1 = 0xFFFF; //messages are received in FIFO buffer
18
    C1BUFPNT2 = 0xFFFF;
19
    C1BUFPNT3 = 0xFFFF;
20
    C1BUFPNT4 = 0x00FF;
21
    
22
    C1RXF0SIDbits.SID = 0b00000000001; //Filter 0
23
    C1RXF0SIDbits.EID = 0b00; //Filter 0 (Extended Identifier)
24
    C1RXF0EID = 0x0000; //Filter 0 (Extended Identifier)
25
    C1RXF1SIDbits.SID = 0b00000000010; //Filter 1
26
    C1RXF1SIDbits.EID = 0b00; //Filter 1 (Extended Identifier)
27
    C1RXF1EID = 0x0000; //Filter 1 (Extended Identifier)
28
    C1RXF2SIDbits.SID = 0b00000000011; //Filter 2
29
    C1RXF2SIDbits.EID = 0b00; //Filter 2 (Extended Identifier)
30
    C1RXF2EID = 0x0000; //Filter 2 (Extended Identifier)
31
    C1RXF3SIDbits.SID = 0b00000000100; //Filter 3
32
    C1RXF3SIDbits.EID = 0b00; //Filter 3 (Extended Identifier)
33
    C1RXF3EID = 0x0000; //Filter 3 (Extended Identifier)
34
    C1RXF4SIDbits.SID = 0b00000000101; //Filter 4
35
    C1RXF4SIDbits.EID = 0b00; //Filter 4 (Extended Identifier)
36
    C1RXF4EID = 0x0000; //Filter 4 (Extended Identifier)
37
    C1RXF5SIDbits.SID = 0b00000000110; //Filter 5
38
    C1RXF5SIDbits.EID = 0b00; //Filter 5 (Extended Identifier)
39
    C1RXF5EID = 0x0000; //Filter 5 (Extended Identifier)
40
    C1RXF6SIDbits.SID = 0b00000000111; //Filter 6
41
    C1RXF6SIDbits.EID = 0b00; //Filter 6 (Extended Identifier)
42
    C1RXF6EID = 0x0000; //Filter 6 (Extended Identifier)
43
    C1RXF7SIDbits.SID = 0b00000001000; //Filter 7
44
    C1RXF7SIDbits.EID = 0b00; //Filter 7 (Extended Identifier)
45
    C1RXF7EID = 0x0000; //Filter 7 (Extended Identifier)
46
    C1RXF8SIDbits.SID = 0b00000001001; //Filter 8
47
    C1RXF8SIDbits.EID = 0b00; //Filter 8 (Extended Identifier)
48
    C1RXF8EID = 0x0000; //Filter 8 (Extended Identifier)
49
    C1RXF9SIDbits.SID = 0b00000001010; //Filter 9
50
    C1RXF9SIDbits.EID = 0b00; //Filter 9 (Extended Identifier)
51
    C1RXF9EID = 0x0000; //Filter 9 (Extended Identifier)
52
    C1RXF10SIDbits.SID = 0b0000001011; //Filter 10
53
    C1RXF10SIDbits.EID = 0b00; //Filter 10 (Extended Identifier)
54
    C1RXF10EID = 0x0000; //Filter 10 (Extended Identifier)
55
    C1RXF11SIDbits.SID = 0b00000001100; //Filter 11
56
    C1RXF11SIDbits.EID = 0b00; //Filter 11 (Extended Identifier
57
    C1RXF11EID = 0x0000; //Filter 11 (Extended Identifier)
58
    C1RXF12SIDbits.SID = 0b00000001101; //Filter 12
59
    C1RXF12SIDbits.EID = 0b00; //Filter 12
60
    C1RXF12EID = 0x0000; //Filter 12
61
    C1RXF13SIDbits.SID = 0b00000001110; //Filter 13
62
    C1RXF13SIDbits.EID = 0b00; //Filter 13 (Extended Identifier)
63
    C1RXF13EID = 0x0000; //Filter 13 (Extended Identifier)
64
    
65
    C1FMSKSEL1 = 0x0000; //Mask0 determines the acceptance mask for all used filters
66
    C1FMSKSEL2 = 0x0000;
67
    C1RXM0SID = 0xFFF7; //All identifier digits are relevant, standard fames and extended frames are receivable
68
    C1RXM0EID = 0xFFFF;
69
    
70
    C1CTRL1bits.WIN = 0; //buffer window   
71
    C1FCTRLbits.DMABS = 0b100; //16 DMA buffers in RAM
72
    C1FCTRLbits.FSA = 0b00001; // FIFO area from TRB1 to RB15
73
    C1TR01CONbits.TXEN0 = 1; //Set TRB0 as transmit buffer
74
    IEC4bits.C1TXIE = 0; //deactivate interrpt processing by CPU
75
    IEC2bits.C1RXIE = 0;
76
    C1INTEbits.ERRIE = 1;
77
    C1INTEbits.IVRIE = 1;
78
    
79
    //DMA
80
    DMA0CONbits.CHEN = 0; //Disable DMA channel 0 for CAN RX
81
    DMA1CONbits.CHEN = 0; //Disable DMA channel 1 for CAN TX
82
    DMA0CONbits.AMODE = 0b10; //Peripheral indirect mode
83
    DMA0REQbits.IRQSEL = 0b00100010; //Connect to CAN RX peripheral
84
    DMA0PAD = (volatile unsigned int) &C1RXD; //Read from CAN1 RX register (address) 
85
    IEC0bits.DMA0IE = 1; //Enable interrupt for DMA channel 0
86
    DMA0CNT = 7; //8 words to be transmitted
87
    DMA1CONbits.AMODE = 0b10; //Peripheral indirect mode
88
    DMA1CONbits.DIR = 1; //Channel 1 reads data from RAM to CAN
89
    DMA1REQbits.IRQSEL = 0b01000110; //Connect to CAN TX peripheral
90
    DMA1PAD = (volatile unsigned int) &C1TXD; //Writes to CAN1 TX register (address)
91
    DMA1CNT = 7; //8 words to be transmitted
92
    
93
    DMA0STAL = (unsigned int) &canbuf; //CAN receive FIFO buffer (16 buffer, 8 words each)
94
    DMA0STAH = 0x0000;
95
    DMA1STAL = (unsigned int) &canbuf;
96
    DMA1STAH = 0x0000;
97
    
98
    DMA0CONbits.CHEN = 1; //Enable DMA channel 0 for CAN RX
99
    DMA1CONbits.CHEN = 1; //Enable DMA channel 1 for CAN TX
100
    
101
    C1CTRL1bits.REQOP = 0b000; //Switch to normal CAN operation mode
102
    while(C1CTRL1bits.OPMODE != 0b000); //Wait for opeation mode to change

von Steffen R. (steffen_rose)


Lesenswert?

Robin schrieb:
> Hier noch die Initialisierung zu canbuf:unsigned int
> canbuf[NUM_OF_ECAN_BUFFERS][8]
> __attribute__((aligned(NUM_OF_ECAN_BUFFERS * 16))); //16 buffers with 8
> words each (256 byte)

Ich habe einen pic24ep..., sollte aber das gleiche sein. Der Puffer muss 
in einem speziellen Speicher sein und nicht irgendwo.
1
__eds__ ECAN_MSGBUF_T ecanMsgBuf __attribute__((eds,space(dma),aligned(ECAN_MSG_BUF_LENGTH*16)));

Und die Adresse des Puffers
1
    DMA0STAL= __builtin_dmaoffset(ecanMsgBuf);
2
    DMA0STAH= __builtin_dmapage(ecanMsgBuf);

Robin schrieb:
> DMA1CONbits.CHEN = 0; //toogle DMA1 channel enale to reset
> Force bit
>             DMA1CONbits.CHEN = 1;

Sowas kenne ich garnicht. Die DMA für den CAN arbeitet im Hintergrund 
autonom. Mußte diese nachd er Initialisierung nie wieder anfassen.

: Bearbeitet durch User
von Robin (Gast)


Lesenswert?

Steffen R. schrieb:
> Ich habe einen pic24ep..., sollte aber das gleiche sein. Der Puffer muss
> in einem speziellen Speicher sein und nicht irgendwo.
> _eds_ ECAN_MSGBUF_T ecanMsgBuf
> __attribute__((eds,space(dma),aligned(ECAN_MSG_BUF_LENGTH*16)));

Erstmal vielen Dank für deine Hilfe! Das hatte ich schon versucht, mein 
Controller hat aber keinen separaten DMA-RAM und deswegen habe ich die 
Initialisierung aus dem Family Reference Data Sheet für dsPIC33E 
verwendet.

Das mit dem DMA-Channel Enable togglen habe ich wieder raus genommen. 
Ich habe nochmal die Bit-Timings des CAN-Busses neu dimensioniert und 
ein paar kleinere Änerungen vorgenommen und jetzt sagt er zumindest 
nicht mehr dass die zu sendende Message ungültig sei. Er spuckt auch 
keinen Transmit Error aus. Dafür setzt er aber den Transmit Request 
zurück (was laut Datenblatt bedeutet dass eine Message korrekt 
übertragen wurde). Das ist schon mal sehr gut, und endlich ein 
Fortschritt nach einer Woche Fehlersuche. Allerdings ist jetzt das 
Problem dass das Microchip Demo Board dass die Nachricht empfangen soll, 
nichts anzeigt. Soweit ich das verstanden habe müssen beim CAN-Bus die 
Bittimings nicht identisch sein zwischen den einzelnen Nodes sondern nur 
die Baudrate Einstellungen. Richtig?

Das ist das Microchip Board: 
http://www.microchip.com/DevelopmentTools/ProductDetails.aspx?PartNO=mcp2515dm-bm

von Steffen R. (steffen_rose)


Lesenswert?

Robin schrieb:
> Soweit ich das verstanden habe müssen beim CAN-Bus die
> Bittimings nicht identisch sein zwischen den einzelnen Nodes sondern nur
> die Baudrate Einstellungen. Richtig?

Schreib mal genauer, was du auf beiden Seiten eingestellt hast.

Es ist richtig, dass die Bitrate auf beiden Seiten gleich sein muss und 
die genaue Einstellung des Samplepoints und Anzahl der Timequanten eher 
unkritisch ist, zumindest bei kleineren Bitraten (125kbit/s, 250kbit/s).
Aber es ist schon günstig, wenn der Samplepoint halbwegs passt.

Da dein Sender den Senderequest gelöscht hat, muss er einen Acknowledge 
vom Empfänger erhalten haben oder es der Sender muss zeitweise in den 
Busoff Zustand gewechselt haben.

Um die Bitrate zu prüfen würde ich zu allererst beide Boards getrennt 
voneinander Senden lassen und die Timings überprüfen.
Womit analysierst Du? CAN Interface am PC? Oszi?
Nutzt du das verlinkte Board als PC Interface mit einer fertigen 
Software?

Am ehesten würde ich darauf tippen, dass auf dem dsPic33 Board das 
Bittiming nicht passt. Da wäre aber ein Oszi nicht schlecht.

Robin schrieb:
> C1CFG2bits.PRSEG = 0b100; //Prop segment is 3T_Q
>     C1CFG2bits.SEG1PH = 0b100; //Segment 1 is 3T_Q
>     C1CFG2bits.SEG2PH = 0b100; //Segment 2 is 3T_Q

Der Kommentar stimmt nicht. Die Anzahl der Timequanten ist um eins höher 
als der Registerwert.

Robin schrieb:
> C1CTRL1bits.CANCKS = 0; //F_CAN is equal to F_P=17,5MHz

Schaue bitte mal in das Errata deines Chips. Es gab Derivate, da war die 
Logik verdreht.

von Robin (Gast)


Lesenswert?

Steffen R. schrieb:
> Robin schrieb:
>> C1CFG2bits.PRSEG = 0b100; //Prop segment is 3T_Q
>>     C1CFG2bits.SEG1PH = 0b100; //Segment 1 is 3T_Q
>>     C1CFG2bits.SEG2PH = 0b100; //Segment 2 is 3T_Q
>
> Der Kommentar stimmt nicht. Die Anzahl der Timequanten ist um eins höher
> als der Registerwert.

Hier lag der Fehler letztlich. Jetzt kann ich problemlos kommunizieren.

Die Baudrate ist auf 125kbit/s eingestellt und mein Modul auf 16 T_Q pro 
T_bit mit je 5 T_Q pro Segment und einer SJW von 4 T_Q. Mein Empfänger 
Modul ist auf 10 T_Q pro T_bit eingestellt und auf je 3 T_Q pro Segment 
und eine SJW von 3 T_Q. Mit diesen Einstellungen klappt es jetzt. Damit 
liegt der Sampling Point bei 68,75% bzw. 70%.

Vielen Dank für die kompetente Hilfe!

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.