Hot!dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode

Author
DrHappyfeet
New Member
  • Total Posts : 15
  • Reward points : 0
  • Joined: 2017/04/12 07:37:08
  • Location: 0
  • Status: offline
2017/04/20 07:23:47 (permalink)
0

dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode

Hello fellow forum members!
I'm running into two problems when I (try to) run my ECAN Code.
 
First off: when I enable my DMA chanel after configuring it for CAN (DMA0CONbits.CHEN = 1) and the program leaves the function (CAN_DMA0_TX_Config(void)), the Simulator window shows the next error:
"W1402-DMA: The desired IRQ is not associated with a DMA peripheral: 70." 
double checking the dsPIC33E datasheet DMA chapter reconfirms: "ECAN1 – TX Data Request, DMAxREQbits.IRQSEL =01000110 DMAxPAD (value to read from peripheral) 0x0442 (C1TXD)


Initializing DMA1 for ECAN RX gives a similar error, only this time the number reads 34 (just like with channel 0, the datasheet gives binary 34 for the DMAxREQ value for ECAN RX ready)
So I'm kinda stumped as to whats happening here, any insight much appreciated!
 
For problem two, we move on to the C1CTRL register, specifically the REQOP/OPMODE fields. When i try to configure my board for ECAN, all is well untill i try to request normal mode (REQOP = ob000) and wait for the mode switch (while OPMODE !=0b000)
 
In short, the mode never switches. I added a disableInterrupt function prior to calling for config mode, nuking all IE/IF registers to 0, and it doesn't change a thing.
 
Again, any insight is very welcome!
 
For clarity: added to this post are main config and function files.
post edited by DrHappyfeet - 2017/04/20 07:25:10
#1

9 Replies Related Threads

    CinziaG
    morite
    • Total Posts : 3144
    • Reward points : 0
    • Joined: 2016/12/07 14:20:36
    • Location: Wien
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2017/04/20 07:29:38 (permalink)
    5 (1)
    Mmmm you're just SIMulating?
    I would not believe CAN module is simulated correctly/completely...
     
    I recently finished a board that uses a PIC24GU (sounds similar to yours) and everything was more or less ok as from Microchip AN/docs. I remember those 34 and 70, I guess Smile

    mi fate schifo, umani di merda.
    #2
    DrHappyfeet
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/04/12 07:37:08
    • Location: 0
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2017/04/20 07:37:25 (permalink)
    3 (1)
    Ah, interesting... Since I got everything wired up here I had the assumption the program was actually executed by the PIC... Will have to take a dive into the Real Ice manual i guess.
     
    However my program still hangs while waiting for the mode change... Any ideas on that front? 
    #3
    CinziaG
    morite
    • Total Posts : 3144
    • Reward points : 0
    • Joined: 2016/12/07 14:20:36
    • Location: Wien
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2017/04/20 08:01:53 (permalink)
    0
    DrHappyfeet
     
    However my program still hangs while waiting for the mode change... Any ideas on that front? 




    Well no - I mean, if simulator is cheating, it will cheat on this too Smile

    mi fate schifo, umani di merda.
    #4
    DrHappyfeet
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/04/12 07:37:08
    • Location: 0
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2017/04/21 03:21:39 (permalink)
    3 (1)
    So, after a good 'talk' I won the 'argument' and Real Ice is talking with my dsPIC :)
    So far everything seems to execute just fine, up until I hit the main loop. It appears the message is being received by the transceiver (I can see the line changing, at the connector as CAN-H/CAN-L and after the node as CAN Rx) but the interrupt is not generated (the breakpoint has not been hit). As a node we're using the Texas Instruments TCAN332DR. 
    As far as i can gather from the ref manual and operation guide for ECAN, I've set up the DMA/ECAN registers as should be and interrupts for CAN are enabled (IEC2bits.C1IE/C1INTEbits.TBIE/C1INTEbits.RBIE =1). Then there is the ISR function ofc, declared as: void __attribute ((interrupt (no_auto_psv))) _C1Interrupt (void) In here I clear the flags (C1IF/TBIF) and update my 'nextReadArray' with the fifo address and increment my nextRead flag. Flag triggers the main loop, or at least that was the design...
     
    Can someone perhaps share some insight on DMA/CAN interrupts for dsPICs? As far as i can tell from the many ref guides it should be up to standards for ECAN operation... but then again I've been wrong before trusting the maze of documentation.
    #5
    DrHappyfeet
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/04/12 07:37:08
    • Location: 0
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2017/04/21 07:38:13 (permalink)
    3 (1)
    After some more testing and double checking, I managed to deduce that the message never gets transferred by the DMA controller, thus not generating the interrupt ect. 
    Looking trough the reference manuals again I'm pretty sure the configuration of the 2 DMA channels are done correctly... If anyone has some insight as to what might be happening here, it's much appreciated!
    #6
    DrHappyfeet
    New Member
    • Total Posts : 15
    • Reward points : 0
    • Joined: 2017/04/12 07:37:08
    • Location: 0
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2017/04/25 03:41:01 (permalink)
    0
    Shameless bump, since the problem is still present with no clear solution in sight.
     
    Did some more testing; it seems DMA does not trigger at all.
    When receiving a message (from an Anagate CANduo) the IRS does not get called and as far as i can tell from the watch on my gCanmsgbuff nothing gets transferred.
     
    When sending a message, the code gets stuck in a while loop: 
    switch (aTxBuf)
    {
       case 0: C1TR01CONbits.TXREQ0 = 1;
                  while (C1TR01CONbits.TXREQ0)
                  break;
    (more cases like this)
    }
     
    So far I've:
    -Enabled DMA0 and 1 in the PMD7bits.DMA0MD (and DMA1MD) SFR
    -Enabled DMA Interrupts (as wel as ECAN interrupts)
    -Rewrote my DMAxPAD agrument to: (volatile uint16_t) &C1TXD (also for C1RXD ofc)
    -Set C1CTRL1bits.CANCAP = 0x1 (this one somehow slipped my net, i guess?)
    -Recalculated (double checked) NBT -> 12Mhz HS crystal, 120Mhz Fosc(60 Mhz Fcy)
    -Shifted around the order in which I config, now i first run CAN_SetClock() and afterwards call config mode
    -Confirmed the CANbuildAndSend() function fills the desired values into the desired buffers, before stopping in its tracks waiting for it to send.
     
    If someone with some experience with either DMA, CAN, or just dsPIC33E in general could take a look over my code that would be great. So far my strategy has been double checking all the reference manuals, example codes, migration guide ect ect. I'm pretty sure it's something rather small and stupid... And that I just don't see it...
     
    ##### CONFIG.C
    /*
     * File: dsCAN_config.c
     * Author: kdk
     *
     * Created on 23 March 2017, 14:02
     */

    #include <xc.h>
    #include <stdint.h>
    #include "dsCAN_config.h"
    #include "dsCAN_funct.h"


    __eds__ CAN1BUFF_t gCanmsgbuff __attribute__((eds, aligned(CAN1_MSG_FRAME_LENGTH*8*2) ));

    void disableInterrupts (void);

    void CAN_SetClock (void) //function to set clock values
    {
        C1CTRL1bits.CANCAP = 0x1;
        C1CTRL1bits.CANCKS = 0; //set FCAN to be equal to 2*Fcy
        C1CFG1bits.SJW = 0x0; //Synchronisation jump = 1 TQ
        C1CFG1bits.BRP = BRP_VAL; //Calculate Baud rate Prescaler (its 2)
        C1CFG2bits.SEG1PH = 0x7; //Phase segment 1 is 8 TQ
        C1CFG2bits.SEG2PHTS = 0x1; //Phase segment 2 is programmable
        C1CFG2bits.SEG2PH = 0x5; //Phase segment 2 is 6 TQ
        C1CFG2bits.PRSEG = 0x4; //Propagation segment is 5 TQ
        C1CFG2bits.SAM = 0x0; //Line is sampled 1 time at sample point (70%)
    }

    void CAN_setDMAbuffer (void)
    {
      //Reset all "full" and "overflow" flags
      C1RXFUL1 = C1RXFUL2 = C1RXOVF1 = C1RXOVF2 = 0x0000;
      PMD7bits.DMA0MD = 0;
      PMD7bits.DMA1MD = 0;
      C1CTRL1bits.WIN = 0; //set window bit to buffer, to avoid shenanigans
      C1FCTRLbits.DMABS = 0b011; //Declare 12 buffers in device RAM
      
      C1TR01CONbits.TXEN0 = 1; //Buffer 0-3 are transmit buffers
      C1TR01CONbits.TXEN1 = 1;
      C1TR23CONbits.TXEN2 = 1;
      C1TR23CONbits.TXEN3 = 1;
      C1TR45CONbits.TXEN4 = 0; //Buffer 4 and up are receive buffers
      C1TR45CONbits.TXEN5 = 0;
      C1TR67CONbits.TXEN6 = 0;
      C1TR67CONbits.TXEN7 = 0;
      
      C1FCTRLbits.FSA = (uint16_t) 0b100; //Declare FIFO buffering to start at buffer 4 (all RX buffers)
      
      //Declare buffer priorities, writing a message to specific buffer will transfer the prio (not FIFO)
      C1TR01CONbits.TX0PRI=0b00; // Message Buffer 0 Priority Level
      C1TR01CONbits.TX1PRI=0b00; // Message Buffer 1 Priority Level
      C1TR23CONbits.TX2PRI=0b00; // Message Buffer 2 Priority Level
      C1TR23CONbits.TX3PRI=0b00; // Message Buffer 3 Priority Level
      C1TR45CONbits.TX4PRI=0b00; // Message Buffer 4 Priority Level
      C1TR45CONbits.TX5PRI=0b00; // Message Buffer 5 Priority Level
      C1TR67CONbits.TX6PRI=0b00; // Message Buffer 6 Priority Level
      C1TR67CONbits.TX7PRI=0b00; // Message Buffer 7 Priority Level
    }

    /*Set filter "aNr" to filter "aSID" bits from Standard Identifier messages

    Inputs:
    aNr-> Filter number [0-15]
    aSID-> Bit ordering is given below

    Filter Identifier (11-bits) : 0b0000 0000 0000 0000 0000 0fff ffff ffff
                    |___________|
                     SID10:0
    Function only works for standard Identifiers!

    aBufPnt -> Message buffer to store filtered message [0-15] DISABLED FOR FIFO!
     aBufPnt for all filters set to 0x1111 (RX FIFO buffer) in C1BUFPNT(n) registers
    aMaskSel -> Optinal Masking of identifier bits [0-3]
          
    */
    void CAN_setFilter (int16_t aNr, int32_t aSID, uint16_t aMaskSel)
    {
      C1CTRL1bits.WIN = 1; //Window bit for register modification
      
      uint32_t lSid10_0 = 0;
      uint16_t* lSidRegAddr;
      uint16_t* lBufPntRegAddr;
      uint16_t* lMaskSelRegAddr;
      uint16_t* lFiltEnableRegAddr;
      
      //Obtaining the register addresses
      lSidRegAddr = (uint16_t*)(&C1RXF0SID + (aNr << 1)); //Obtain register addresses for filter "aNr"
      lBufPntRegAddr = (uint16_t*)(&C1BUFPNT1 + (aNr >> 2)); //obtain buffer pointer address
      lMaskSelRegAddr = (uint16_t*)(&C1FMSKSEL1 + (aNr >> 3)); //obtain mask select register address
      lFiltEnableRegAddr =(uint16_t*)(&C1FEN1); //Filter enable address
      
      
      //Some more bit shifting to write the filter SID
      lSid10_0 = (aSID & 0xFFF);
      *lSidRegAddr = (lSid10_0) << 5; //write to C1RXF(0-15)SID register
      *(lSidRegAddr+1) = 0; //Write Extended ID bit Low
      
     /* *lBufPntRegAddr = (*lBufPntRegAddr) & (0xFFFF - (0xF << (4 *(aNr & 3)))); //clear nibble (whatever that may be)
      *lBufPntRegAddr = ((aBufPnt << (4 *(aNr & 3))) | (*lBufPntRegAddr)); //write to C1BUFPNT(n) register
      *lBufPntRegAddr = 0b1111; //Set mask aNr to use FIFO RX buffers
     */
      *lMaskSelRegAddr = (*lMaskSelRegAddr) & (0xFFFF - (0x3 << ((aNr & 7) *2)) );//clear two bits
      *lMaskSelRegAddr = ((aMaskSel << (2 * (aNr & 7))) | (*lMaskSelRegAddr)); //Write to C1FNSKSEL(n) register
      
      *lFiltEnableRegAddr = ((0x1 << aNr) | (*lFiltEnableRegAddr)); //Write to C1FEN(n) register

      C1CTRL1bits.WIN = 0;
    }

    void CAN_FIFO_config ()
    {
      //Filters 0- 7 are set to FIFO
      C1BUFPNT1 = 0xFFFF;
      C1BUFPNT2 = 0xFFFF;
    }

    /*Set mask "aMskNr" to mask "aMID" bits during filtering a Standard ID message
     
    Inputs:
    aMskNr-> Mask number [0-2]
    aMID-> mask bit identifier, bit ordering is given below

    Filter Mask Identifier (11-bits) : 0b0000 0000 0000 0000 0000 0fff ffff ffff
                         |___________|
                         SID10:0

    Function only works for Standard messages! <mide> and <exide> bits are IGNORED
    Mask reads <mide=0> and ignores <exide>, accepting only messages that fit the Sid10_0 bit filter
    and mask
    */
    void CAN_setMask (int16_t aMskNr, int32_t aMID)
    {
      uint32_t lSid10_0 = 0;
      uint16_t *lMaskRegAddr;
      
      C1CTRL1bits.WIN = 1; //Set window bit to "filter window"
      
      lMaskRegAddr = (uint16_t*)(&C1RXM0SID + (aMskNr << 1)); //Obtain register address for mask number "aMskNr"
      
      //More bit shifting to write to the FilterMask register
      lSid10_0 = (aMID & 0x7FF); //form the mask bit array
      *lMaskRegAddr = (lSid10_0) << 5; //Write to C1RXM(n)SID register (standard ID)
      *(lMaskRegAddr+1) = 0; //Write to C1RXM(n)EID register (extended ID)
      
      C1CTRL1bits.WIN = 0; //Reset window bit to "buffer window"
    }

    //configure DMA chanel 0 for Transmitting messages
    void CAN_DMA0_TX_Config (void)
    {
      DMAPWC = 0; //Clear Write Collision status register
      DMARQC = 0; //Clear Request Collision status register
      
      DMA0CONbits.MODE = 00; //Set DMA chanel 0 to Continuous, "ping pong" disabled
      DMA0CONbits.AMODE = 0x2; //Set chanel 0 to "Peripheral Indirect Addressing" mode
      DMA0CONbits.DIR = 0x1; //Set chanel 0 to [Read RAM -> Write to peripheral] -aka transmit
      DMA0CONbits.SIZE = 0; //Set chanel 0 to transfer 'word' data size
      
      DMA0PAD = (volatile uint16_t) &C1TXD; //Set chanel 0 to write TO peripheral (C1TXD)
      DMA0CNT = 7; //Set chanel 0 to transfer 8 words when called
      DMA0REQbits.FORCE = 0; //Sets chanel to automatic transfer
      DMA0REQbits.IRQSEL = 0b01000110; //Links chanel 0 to service ECAN1 TX Data Request
      
      //set the DMA start address, code not verified due to __builtin is actually built in...
     DMA0STAH = 0x0000; //Stores the offset to DMA memory address
     DMA0STAL = __builtin_dmaoffset (&gCanmsgbuff); //register is 32 bit, thus requires 2 commands
      
     
     DMA0CONbits.CHEN = 1; //Enable chanel 0;
    }

    //configure DMA chanel 1 for Receiving messages
    void CAN_DMA1_RX_Config (void)
    {
      DMAPWC = 0; //Clear Write Collision status register
      DMARQC = 0; //Clear Request Collision status register
      
      DMA1CONbits.MODE = 00; //Set DMA chanel 1 to Continuous, "ping pong" disabled
      DMA1CONbits.AMODE = 0b10; //Set chanel 1 to "Peripheral Indirect Addressing" mode
      DMA1CONbits.DIR = 0; //Set chanel 1 to [Read Peripheral -> Write to RAM] -aka receive
      DMA1CONbits.SIZE = 0; //Set chanel 1 to transfer 'word' data size
      
      DMA1PAD = (volatile uint16_t) &C1RXD; //Set chanel 1 to read FROM peripheral (C1RXD)
      DMA1CNT = 7; //Set chanel 1 to transfer 8 words when called
      
      DMA1REQbits.FORCE = 0; //Sets chanel to automatic transfer
      DMA1REQbits.IRQSEL = 0b00100010; //Links chanel 1 to service ECAN1 RX Data Request
      
      //set the DMA start address, code not verified due to __builtin is actually built in...
      DMA1STAH = 0x0000; //Stores the offset to DMA memory address
      DMA1STAL = __builtin_dmaoffset (&gCanmsgbuff); //register is 32 bit, thus requires 2 commands
      
      DMA1CONbits.CHEN = 1;
    }


    //Enables interrupts for CAN, handling of interrupts is done by the CAN_ISR
    void CAN_interuptConfig (void)
    {
      C1CTRL1bits.WIN = 0; //Set window bit to avoid shenanigans
      IFS2 = C1INTF = 0; //Reset the interrupt flags to 0 to avoid errors
      C1INTEbits.TBIE = 1; //Enable C1TX interrupts
      C1INTEbits.RBIE = 1; //Enable C1RX interrupts
      IEC2bits.C1IE = 1; //Enable ECAN1 RX ready interrupts
      IEC0bits.DMA0IE = 1; //Enable DMA0 Interrupts
      IEC0bits.DMA1IE = 1; //Enable DMA1 Interrupts
      INTCON1bits.NSTDIS = 1; //Disable nested interrupts
    }

    //Function prototype to configure the dsPIC for ECAN
    void Config_CAN1 (void)
    {
     disableInterrupts(); //Clear all Interrupt enable/flag registers
     //void function
      CAN_SetClock(); //Set Clock
      
     C1CTRL1bits.REQOP = 0b100; //Request configuration mode
      while (C1CTRL1bits.OPMODE != 0b100);
      //void function
      CAN_setDMAbuffer(); //Declare DMA buffers (4 TX 8 RX)
      //(FilterNumber, ID to filter, MaskNumber)
      CAN_setFilter(0, 0x001, 0); //Set filter 0 to use mask 0 and SiD 0x001
      //(MaskNumber, Bits to mask)
      CAN_setMask (0, 0x00F); //Set mask 0 to mask 0x00F bits
      //void function
      CAN_FIFO_config(); //Enable FIFO buffering
      //void function
      CAN_DMA0_TX_Config(); //Configure DMA0 to service TX requests
      //void function
      CAN_DMA1_RX_Config(); //Configure DMA1 to service RX requests
      //Void function
      PMD1bits.C1MD = 0; //Enable the ECAN pheripheral
      CAN_interuptConfig(); //Configure and enable interrupts for DMA<->ECAN
      
      C1CTRL1bits.REQOP = 0b000; //Request normal operation mode
      while (C1CTRL1bits.OPMODE != 0b000);
    }

    void disableInterrupts (void)
    {
    /* Clearing the Interrupt Enable Registers */
      IEC0 = 0;
      IEC1 = 0;
      IEC2 = 0;
      IEC3 = 0;
      IEC4 = 0;
      IEC5 = 0;
      IEC6 = 0;
      IEC8 = 0;
      IEC9 = 0;
      
      
    /* Clearing the Interrupt Flag Registers */
      IFS0 = 0;
      IFS1 = 0;
      IFS2 = 0;
      IFS3 = 0;
      IFS4 = 0;
      IFS5 = 0;
      IFS6 = 0;
      IFS8 = 0;
      IFS9 = 0;
    }
    ######CONFIG.H
    /* Microchip Technology Inc. and its subsidiaries. You may use this software
     * and any derivatives exclusively with Microchip products.
     *
     * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
     * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
     * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
     * PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
     * WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
     *
     * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
     * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
     * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
     * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
     * FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS
     * IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF
     * ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
     *
     * MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
     * TERMS.
     */

    /*
     * File:
     * Author: KdK
     * Comments:
     * Revision history:
     */

    // This is a guard condition so that contents of this file are not included
    // more than once.
    #ifndef __DSCAN_CONFIG_H
    #define __DSCAN_CONFIG_H

    #include <xc.h> // include processor files - each processor file is guarded.
    #include <stdint.h>


    #define CLK 120000000 //CPU clock = CLK/2 (60mips)
    #define BITRATE 1000000 //bitrate 1 mbs
    #define NTQ 20 //20 time quanta per message
    #define BRP_VAL ((CLK/(2*NTQ*BITRATE))-1)

    /*#define gCAN_Filter1 0x0 //filter bits tbd, define is here anyway
    #define gCAN_Filter2 0x0 //idem, max is 16 filters

    #define gCAN_Mask1 0x0 //mask bits define
    #define gCAN_Mask2 0x0 //idem, max is 3 masks
    */
    #define CAN1_MSG_BUF_LENGTH 12 //Define nr of buffers in DMA
    #define CAN1_MSG_FRAME_LENGTH 8 //8 words in each buffer (standard CAN)*/

    //Reserve and align bytes in DMA RAM (extended data space)
    typedef uint16_t CAN1BUFF_t [CAN1_MSG_BUF_LENGTH][8];
    __eds__ extern CAN1BUFF_t gCanmsgbuff __attribute__((eds, aligned (CAN1_MSG_FRAME_LENGTH*8*2) )); //Reserves (12*8*2)=192 bytes



     /*============================================================================
      uint16_t lSid10_0 = 0; //prototype function
      lSid10_0 = (gCAN_Filter1 & 0x7FF); //Extract 11 bits of the standardID
      C1RXF0SIDbits.SID = (lSid10_0 << 5); //Should write SID to RX filter register (should....)
      C1RXF0SIDbits.EXIDE = 0; //If <MIDE:1>, <EXIDE:0> matches only SID messages
      ============================================================================== */
    void Config_CAN1 (void);

    #endif //__DSCAN_CONFIG_H

    #####FUNCT.C
    /*
     * File: dsCAN_funct.c
     * Author: kdk
     *
     * Created on 23 March 2017, 14:33
     */

    #include <xc.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "dsCAN_funct.h"
    #include "dsCAN_config.h"

    //__eds__ CAN1BUFF_t gCanmsgbuff __attribute__((eds, aligned(CAN1_MSG_FRAME_LENGTH*8*2) ));

    typedef struct CANrxMsg_t //Structure to store the CAN message and execute/interpret the data
    { //Once the message is read from DMA it's only kept INSIDE this function
       uint16_t SID; //Standard Identifier is stored here
       uint8_t DLC; //Data Length Code (nr of data bytes)
       uint8_t DataByte[7]; //Data bytes to store CAN data (0-7)
    } CANrxMsg;

    CANrxMsg lCANrxMsg;

    volatile int8_t gCAN_writepoint; //Write index for NextReadBuffer, only changed during interrupts
    volatile int8_t gCAN_readpoint; //Read index for NextReadBuffer, only changed in CANReadAndExecute
    volatile int16_t gCAN_ERROR; //Error flag for gCAN_NxtReadBuffer, use to communicate error

    /*volatile bool gReadCANMessage; //Bool flag to trigger the main loop to copy the message from DMA RAM to CPU RAM, and do stuff
    bool gSendTestResponse; //Bool flag to trigger main() to respond
     */
    //Buffer to point to the next DMA buffer to read in the main loop, Write actions are done during CAN ISR
    //Read actions only in CANReadAndExecute

    volatile CANItem gCAN_NextReadBuffer[7]; //Array has 8 rows (same as DMA) and 2 colums

    MyCanFrame gCAN_txBuf[2]; //structure to hold and build CAN the TX message in CPU RAM, 3 rows of 8 words

    uint8_t gCAN_FIFOPointer; //Global to hold the C1FIFO.FNRB register value, which contains the next read buffer number
    uint16_t gRxFullbits; //Global to hold the C1RXFUL1 register, in this 16 bit array bit position represents a buffer (0-15)
    //and set/unset represents a message being available

    /*CAN Interrupt Service Routine
     * First up it resets the interrupt flag and checks for a Receive Interrupt
     * If a new message is added to the DMA buffer:
     * -A flag for main() get set
     * -The buffer number (in BINARY!) gets added to the NxtReadBuffer
     * -The NextWrite pointer for the NxtReadBuffer gets incremented (if its not overflowing)
     * -The RX interrupt gets cleared
     */
    void __attribute ((interrupt (no_auto_psv)))_C1Interrupt (void)
    {
       IFS2bits.C1IF = 0; //Clear interrupt flag

       if (C1INTFbits.TBIF) //Check if its a Transmit Interrupt
       {
          C1INTFbits.TBIF = 0; //Reset interrupt flag

       }
       if (C1INTFbits.RBIF == 1) //Check if its a Receive Interrupt
       {
          gCAN_FIFOPointer = C1FIFObits.FNRB; //Read the NextRead pointer from FIFO (ob00000 aka 0-31 dec)
          gRxFullbits = (C1RXFUL1 >> 3); //Read the BufferFull register, shift 3 bits right to remove buffer 0-3 (TX)and leave buffer 4-15 (4-11 RX)

          //((gCAN_FIFOPointer & gRxFullbits) == gCAN_FIFOPointer);
          if (((gRxFullbits >> gCAN_FIFOPointer) & 0x1) == 0x1) //Compare RXFULL with the NextReadPointer to see if it points to a filled buffer
          {
             //Set the main loop flag for reading a buffer
             gCAN_NextReadBuffer [gCAN_writepoint].Address = gCAN_FIFOPointer; //Load the buffer pointer into the array
             gCAN_NextReadBuffer [gCAN_writepoint].Occupied = true; //Set the buffer flag

             if (gCAN_writepoint > 8) //Check if the read pointer needs recycling
             {
                if (!gCAN_NextReadBuffer [0].Occupied) //Check for an overflow error on the first row
                {
                   gCAN_writepoint = 0; //Recycle the write pointer
                }
                else
                {
                   gCAN_ERROR = BUFFOVERFLOW; //Or set the Overflow error flag
                }
             }
             else
             {
                if (!gCAN_NextReadBuffer [gCAN_writepoint + 1].Occupied) //Check for overflow error on the next row
                {
                   gCAN_writepoint++; //Increment read pointer if its free
                }
                else
                {
                   gCAN_ERROR = BUFFOVERFLOW; //Or set the overflow error flag
                }
             }
             gReadCANMessage = TRUE;
          }
          C1INTFbits.RBIF = 0; //Reset Interrupt flag
       }
    }

    /*Function to read the next CAN message into local RAM and Execute the command
     *Execute can also mean another function is called or a flag is set for main()
     *
     * Main purpose is to drag the message from DMA RAM to a local structure so the command/data/request
     * can be acted upon.
     *
     * Upon reading the final word from DMA RAM, the RXFUL1<15_0> bit of the buffer
     * must be cleared to ensure FIFO operation does not lead to errors
     *
     * Main tool for FIFO handling of messages outside the ISR is the gCAN_NextReadBuffer[] array
     * and gCAN_writepoint/gCAN_readpoint pointers.
     *
     * To avoid errors; ONLY the ISR modifies the gCAN_writepoint,
     * and ONLY CANReadAndExecute() modifies the gCAN_readpoint.
     *
     * This way a write command can never be executed on a row/colum that is being read from in main()
     * and if a new message is entered in DMA mid function, the CANReadAndExecute can continue with that
     * message directly after servicing the last
     *
     * Standard Message Format:
     * Word0 : 0bUUUx xxxx xxxx xxxx
     * |____________|||
     * SID10:0 SRR IDE(bit 0)
     * Word1 : 0bUUUU xxxx xxxx xxxx <-- Ignore Word 1 (SiD only)
     * |____________|
     * EID17:6
     * Word2 : 0bxxxx xxx0 UUU0 xxxx
     * |_____|| |__|
     * EID5:0 RTR DLC
     * word3-word6: data bytes
     * word7: filter hit code bits
     *
     * Substitute Remote Request Bit
     * SRR-> "0" Normal Message
     * "1" Message will request remote transmission
     *
     * Extended Identifier Bit
     * IDE-> "0" Message will transmit standard identifier
     * "1" Message will transmit extended identifier
     *
     * Remote Transmission Request Bit
     * RTR-> "0" Message transmitted is a normal message
     * "1" Message transmitted is a remote message */


    void CAN_ReadAndExecute (void)
    {
       uint16_t lBuffer; //Pointer to hold the DMA buffer address
       //from gCAN_NextReadBuffer[gCAN_readpoint]

       if (gCAN_NextReadBuffer [gCAN_readpoint].Occupied) //Confirm the read pointer is pointing at a valid buffer
       {
          lBuffer = gCAN_NextReadBuffer [gCAN_readpoint].Address; //Copy the address from the buffer


          lCANrxMsg.SID = (uint16_t) (gCanmsgbuff [lBuffer][0] & 0xFFC) >> 2; //Store the sID by masking the SID(10_0) bits and shifting
          lCANrxMsg.DLC = (uint8_t) (gCanmsgbuff [lBuffer][2] & 0x00F); //Store the Data Length Code
          lCANrxMsg.DataByte[0] = (uint8_t) gCanmsgbuff [lBuffer][3]; //Break the Words in DMA up in CAN-Data-Bytes
          lCANrxMsg.DataByte[1] = (uint8_t) ((gCanmsgbuff [lBuffer][3] & 0xFF00) >> 8);
          lCANrxMsg.DataByte[2] = (uint8_t) gCanmsgbuff [lBuffer][4];
          lCANrxMsg.DataByte[3] = (uint8_t) ((gCanmsgbuff [lBuffer][4] & 0xFF00) >> 8);
          lCANrxMsg.DataByte[4] = (uint8_t) gCanmsgbuff [lBuffer][5];
          lCANrxMsg.DataByte[5] = (uint8_t) ((gCanmsgbuff [lBuffer][5] & 0xFF00) >> 8);
          lCANrxMsg.DataByte[6] = (uint8_t) gCanmsgbuff [lBuffer][6];
          lCANrxMsg.DataByte[7] = (uint8_t) ((gCanmsgbuff [lBuffer][6] & 0xFF00) >> 8);

          //IMPORTANT; after reading the message the RXFULL1 <15_0> register needs to be adjusted
          //__builtin_btg(&lBuffer, lBuffer);
          C1RXFUL1 &= ~(0x001 << lBuffer);
          gReadCANMessage = false; //Reset the main Flag

          if (gCAN_readpoint > 8) //Check if the pointer needs recycling
          {
             gCAN_readpoint = 0; //Reset the pointer
          }
          else
          {
             gCAN_readpoint++; //Or increment to the next buffer
          }

          switch (lCANrxMsg.DataByte[0]) //Switch case to execute the contents of the message
          {
          case A: gSendTestResponse = true;
             break;
             /* case B : ;
              break;
              case C : ;
              break;
              case D : ;
              ExecuteSpecific ();
              break;
              default :
              ExecuteRightNow ();*/
          }
       }
    }

    /*Function to build a CAN message and send it on the bus
     * aSiD = Standard Identifier for the message to send (11 bits)
     * aDataLC = Data Length Code, specifies amount of data words in the message (4 bits)
     * *aResponsePointer = pointer to the structure that holds the response data bytes
     * aTxBuf = buffer pointer to the next available TX buffer (DMA buff 0-3)
     * lwordN/lSiD are needed to prepare the accurate values and keep readability of code
     */
    void CAN_BuildAndSend (uint8_t aSiD, uint8_t aDataLC, uint8_t aTxBuf)
    {
       uint16_t lword0 = 0, lword1 = 0, lword2 = 0;
       uint16_t lSiD10_0 = 0;


       lSiD10_0 = (aSiD);
       lSiD10_0 = (lSiD10_0 & 0x7FF);

       lword0 = (lSiD10_0 << 2);

       gCanmsgbuff[aTxBuf][0] = lword0;
       gCanmsgbuff[aTxBuf][1] = lword1;
       gCanmsgbuff[aTxBuf][2] = lword2;

       gCanmsgbuff[aTxBuf][2] = ((gCanmsgbuff[aTxBuf][2] & 0xFFF0) + aDataLC);

       gCanmsgbuff[aTxBuf][3] = (uint16_t) gCAN_txBuf[aTxBuf].DataByte1;
       gCanmsgbuff[aTxBuf][3] = (((gCanmsgbuff[aTxBuf][3] & 0x00FF) << 8) | gCAN_txBuf[aTxBuf].DataByte0);

       gCanmsgbuff[aTxBuf][4] = (uint16_t) gCAN_txBuf[aTxBuf].DataByte3;
       gCanmsgbuff[aTxBuf][4] = (((gCanmsgbuff[aTxBuf][4] & 0x00FF) << 8) | gCAN_txBuf[aTxBuf].DataByte2);

       gCanmsgbuff[aTxBuf][5] = (uint16_t) gCAN_txBuf[aTxBuf].DataByte5;
       gCanmsgbuff[aTxBuf][5] = (((gCanmsgbuff[aTxBuf][5] & 0x00FF) << 8) | gCAN_txBuf[aTxBuf].DataByte4);

       gCanmsgbuff[aTxBuf][6] = (uint16_t) gCAN_txBuf[aTxBuf].DataByte7;
       gCanmsgbuff[aTxBuf][6] = (((gCanmsgbuff[aTxBuf][6] & 0x00FF) << 8) | gCAN_txBuf[aTxBuf].DataByte6);

       switch (aTxBuf)
       {
       case 0: C1TR01CONbits.TXREQ0 = 1;
          while (C1TR01CONbits.TXREQ0);
          break;
       case 1: C1TR01CONbits.TXREQ1 = 1;
          while (C1TR01CONbits.TXREQ1);
          break;
       case 2: C1TR23CONbits.TXREQ2 = 1;
          while (C1TR23CONbits.TXREQ2);
          break;
       case 3: C1TR23CONbits.TXREQ3 = 1;
          while (C1TR23CONbits.TXREQ3);
          break;
       }



    }

    //Function to write the Data bits into an Array to prepare for sending on the Bus
    //aTxbuff can be controlled in main() to make sure a new message is put in an empty TX buffer
    //aDataN bytes will have to be filled in main(), depending on the actual message being send
    //this will most likely follow from a switch case function, aDataLC can be calculated from the data being send (DataLengthCode specifies amount of data bytes)

    void CAN_writeDATA (uint16_t aTxbuff, uint8_t aData0, uint8_t aData1, uint8_t aData2, uint8_t aData3, uint8_t aData4, uint8_t aData5, uint8_t aData6, uint8_t aData7)
    {
       gCAN_txBuf[aTxbuff].DataByte0 = aData0;
       gCAN_txBuf[aTxbuff].DataByte1 = aData1;
       gCAN_txBuf[aTxbuff].DataByte2 = aData2;
       gCAN_txBuf[aTxbuff].DataByte3 = aData3;
       gCAN_txBuf[aTxbuff].DataByte4 = aData4;
       gCAN_txBuf[aTxbuff].DataByte5 = aData5;
       gCAN_txBuf[aTxbuff].DataByte6 = aData6;
       gCAN_txBuf[aTxbuff].DataByte7 = aData7;
    }

    /*void ExecuteCANTest()
    {
      
    }

    void ExecuteRightNow(void) //Function prototype for immediate response
    {
      CAN_writeDATA();
      CAN_buildAndSend();
    }

    void ExecuteSpecific(void)
    {
      
    }*/

    #####FUNCT.H
    /* Microchip Technology Inc. and its subsidiaries. You may use this software
     * and any derivatives exclusively with Microchip products.
     *
     * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
     * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
     * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
     * PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
     * WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
     *
     * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
     * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
     * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
     * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
     * FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS
     * IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF
     * ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
     *
     * MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
     * TERMS.
     */

    /*
     * File:
     * Author: KdK
     * Comments:
     * Revision history:
     */
    #include <xc.h> // include processor files - each processor file is guarded.
    #include <stdint.h>
    #include <stdbool.h>


    // This is a guard condition so that contents of this file are not included
    // more than once.
    #ifndef __DSCAN_FUNCT_H
    #define __DSCAN_FUNCT_H

    #define TRUE 1
    #define FALSE 0
    #define SET 1
    #define RESET 0
    #define BUFFOVERFLOW 0b001

    //__eds__ CAN1BUFF_t gCanmsgbuff __attribute__((eds, aligned (CAN1_MSG_FRAME_LENGTH*8*2) ));

    //Buffer to point to the next DMA buffer to read in the main loop, Write actions are done during CAN ISR
    //Read actions only in CANReadAndExecute
    typedef struct CANItem_t
    {
      uint8_t Address;
      bool Occupied;
    } CANItem;
    extern volatile CANItem gCAN_NextReadBuffer [7]; //Array has 8 rows (same as DMA) and 2 colums


    //extern volatile uint16_t gCAN_txBuf [2][7]; //Array to hold and build CAN the TX message in CPU RAM, 3 rows of 8 words

    extern volatile int8_t gCAN_writepoint; //Write index for NextReadBuffer, only changed during interrupts
    extern volatile int8_t gCAN_readpoint; //Read index for NextReadBuffer, only changed in CANReadAndExecute
    extern volatile int16_t gCAN_ERROR; //Error flag for gCAN_NxtReadBuffer, use to communicate error

    extern volatile bool gReadCANMessage;
    extern bool gSendTestResponse;

    typedef struct MyCanFrame_t
    {
      uint8_t DataByte0;
      uint8_t DataByte1;
      uint8_t DataByte2;
      uint8_t DataByte3;
      uint8_t DataByte4;
      uint8_t DataByte5;
      uint8_t DataByte6;
      uint8_t DataByte7;
    } MyCanFrame;

    extern MyCanFrame gCAN_txBuf[2] ; //Array to hold and build CAN the TX message in CPU RAM, 3 rows of 8 words

    //CAN MACRO SPACE ==============================================================
    #define A 0x01
    #define B 0x2
    #define C 0x3
    #define D 0x4

    void CAN_ReadAndExecute(void);

    void CAN_writeDATA(uint16_t aTxbuff, uint8_t aData0,uint8_t aData1,uint8_t aData2,uint8_t aData3,uint8_t aData4,uint8_t aData5,uint8_t aData6,uint8_t aData7);


    void CAN_BuildAndSend (uint8_t aSiD, uint8_t aDataLC, uint8_t aTxBuf);

    #endif //__DSCAN_FUNCT_H
            
    ######MAIN.C
    /*
     * File: dsCAN_main.c
     * Author: kdk
     *
     * Created on 29 March 2017, 16:37
     */


    #include <xc.h>

    #define FCY 60000000UL
    #include <libpic30.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "dsCAN_config.h"
    #include "dsCAN_funct.h"
    #include "mcc_generated_files/mcc.h"


    volatile bool gReadCANMessage;
    bool gSendTestResponse;

    //CAN_writeDATA(aTxbuff, aData0, aData1, aData2, aData3, aData4, aData5, aData6, aData7)
    //CAN_BuildAndSend (aSiD, aDataLC, aTxBuf)

    void ExecuteCANTest(void)
    {
      CAN_writeDATA(0, 0x01, 0, 0, 0, 0, 0, 0, 0);
      
      CAN_BuildAndSend(0x001, 0b0001, 0);
      
      return;
    }

    void SendCANTest(void)
    {
      CAN_writeDATA(0, 0x0F, 0, 0, 0, 0, 0, 0, 0);
      
      CAN_BuildAndSend(0x001, 0b0001, 0);
      
      return;
    }

    //Prototype test program to bounce a bit around
    int16_t main (void)
    {
      gSendTestResponse = FALSE;
      
      SYSTEM_Initialize();
      Config_CAN1(); //Function to configure registers/masks/DMA for CAN
      
      do
        {
          stal_led_SetHigh();
          if (gReadCANMessage == TRUE) //check if a new message has been accepted into SRAM
            {
             fault_led_Toggle();
              CAN_ReadAndExecute(); //Read the message and execute the command
            }
          if (gSendTestResponse == TRUE) //If a message was received with Data[0] 0x01
            {
              ExecuteCANTest(); //Return a test message
            }
          if(gReadCANMessage == FALSE || gSendTestResponse == FALSE)
          {
         stal_led_SetLow();
          SendCANTest();
          }
          
          __delay_ms(100);
        }
      while (gCAN_ERROR != BUFFOVERFLOW);
      
      return 0;
    }






     
    If I had been allowed to, I'd posted it as attachments like before... ah well...
     
    #7
    CinziaG
    morite
    • Total Posts : 3144
    • Reward points : 0
    • Joined: 2016/12/07 14:20:36
    • Location: Wien
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2017/04/25 03:53:00 (permalink)
    0
    Sounds good enough, but...
     
    I can only point you (again) at this document
    dsPIC33E_PIC24E_ECAN_FRM_70353C.pdf
    http://ww1.microchip.com/downloads/en/DeviceDoc/70353C.pdf
    and recheck everything...
     
    Maybe you could try using non-EDS buffers?
     

    mi fate schifo, umani di merda.
    #8
    framuga
    New Member
    • Total Posts : 6
    • Reward points : 0
    • Joined: 2017/04/21 04:54:05
    • Location: 0
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2018/04/08 05:24:54 (permalink)
    0
    I have the same problems with a dsPIC33EP512MC806.
    Two points:
    ** Regarding the change of operation mode, in debugeer mode the CAN manual says:
    "The operating modes are requested by the user application that is writing to the Request
    Operation Mode bits (REQOP <2: 0>) in the ECAN Control Register 1 (CiCTRL1 <10: 8>). The
    ECAN module acknowledges entry into the requested mode by the OPMODE <2: 0>
    bits (CiCTRL1 <7: 5>). Mode transition is performed in synchronization with the CAN network.
    That is, the ECAN module waits until it detects a bus idle sequence (11 recessive bits) before it
    changes mode. "
    that is, it does not change because in debugger mode there are no 11 recessive bits.
    ** As for the W1402-DMA I have not found a solution.
    I still can not make the ECAN module operational.
    Any advance?
    Thank you
    #9
    marcov
    Super Member
    • Total Posts : 216
    • Reward points : 0
    • Joined: 2006/10/08 01:59:40
    • Location: Eindhoven, NL.
    • Status: offline
    Re: dsPIC33E(256MC506) Debugging problem: DMA association and ECAN mode 2018/04/17 01:47:50 (permalink)
    0
    Don't forget to check errata (in the MU the CANCKS bits are inverted)!
     
    I've posted some of my MU806/810/814 code here: http://www.microchip.com/forums/m790729.aspx
    #10
    Jump to:
    © 2018 APG vNext Trial Version 4.5