[TUT] Using 8 bit AVR Controller Area Network (CAN) register

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Using the basic 8 bit AVR CAN registers:

The CAN controller hardware is a built-in state machine that handles low level CAN protocol operations. Its interface to control/use this hardware is through the AVR Special Function I/O Registers (SFIORs).

First there are CAN General registers (see the data sheet chapter). These registers have reset default bit values. When the AVR is reset or when the CAN General register CANGCON.SWRES bit is set and the CAN hardware is reset, the General registers have their bits set to the default values from the AVR data sheet. For example look at an 8 bit AVR CAN data sheet description for CAN General Control Register "“ CANGCON. Under the figure showing all the bit names there is an Initial Value row. The Initial Value row shows you what the reset default bit values are.

Second there are CAN Mob registers (see the data sheet chapter). These registers have no reset default values and have garbage values in them after a reset. The Mob registers are actually duplicate register groups that are accessed using the General register CANPAGE as a pointer to one specific register group. Look in the data sheet at CAN Page MOb Register - CANPAGE. The CANPAGE MOBNB3, MOBNB2, MOBNB1 and MOBNB0 bits address which Mob register group your code may access. For example in the AT90CANxxx family there are 15 Mob register groups. Setting the CANPAGE MOBNBn bits points to the specific Mob register group number n, only one specific number n of the 15 register groups that your code may access. Think of each different Mob number n register group as assigning a single task to the CAN state machine hardware.

The CANCDMOB register CONMOB1 and CONMOB0 bits determine the CAN task being assigned to each MOb and writing CANCDMOB also starts the CAN task. So, writing CANCDMOB is always done last after all the other registers have already been setup. Since writing to any bit in CANCDMOB will always also write to the CONMOBn bits, writing CANCDMOB is only done one time for each MOb task. When a Tx or Rx CAN MOb task is started, the read only CANEN register ENMOBn bit corresponding to the MOb number n is automatically set and the MOb is busy. After the CAN hardware finishes with the MOb task, then it automatically clears this CANEN register ENMOBn bit. Writing the CONMOBn bits =0 disable is also a valid CAN MOb task (except the MOb CANEN bit is not automatically set). Like all CAN MOb tasks, the disable task is only a request sent to the CAN hardware and your code must detect when the actual MOb disable task completes by checking its CANEN bit.

In the data sheet, the Read/Write row R/W means the bit value may be Read or Written by your code and a R means your code may only Read this bit value. This is very important to pay attention to if you ever want to understand how the CAN hardware interface operates. If you ever think you want to write any value to any CAN register bit, but that bit is Read only, your understanding of how to use the CAN hardware is wrong!

Each Mob register group includes 8 CANMSG bytes. Each Mob number n register group addresses each individual CANMSG byte using the CANPAGE INDX2, INDX1 and INDX0 pointer bits. These INDXn bits always determine which CANMSG byte your code accesses when CANMSG is read or written. The CANPAGE.AINC bit may be cleared to automatically increment the CANPAGE.INDXn bits after CANMSG is read or written by your code.

For example; CANPAGE = 0x32 points at MOb register group 3, CANMSG byte 2 with automatic increment of the CANPAGE INDXn bit value after any read or write of the CANMSG register. In the AT90CANXXX family the fifteen MOb group CANMSG MOBNBn values are zero to fourteen and the CANMSG INDXn index values are zero to seven. The CANPAGE.AINC=0 automatic CANPAGE.INDXn increment overflows the INDXn value from seven back to zero.

After a CAN reset when your code initializes the CAN registers, every MOb CANPAGE register group (even if your code never uses the MOb register group), must set its CANCDMOB and CANSTMOB registers to zero before CANGCON.ENASTB is set to enable the CAN hardware. This disables each MOb and clears all the MOb register interrupt/polling flags. All the other MOb registers do not have to be set to any value until later when you actually assign a task to the MOb. The CAN reset initializes all the General register bits.

The data sheet chapter on CAN interrupts figure shows which registers configure the interrupt or polling CAN MOb activity detection. Only if CANGIE.ENIT is set you must provide the AVR interrupt vector 19 CAN IT interrupt code. If CANGIE.ENIT is cleared, your code polls the CANGIT.CANIT bit to detect MOb task activity. Notice there are read only registers and read only register bits in this figure. There are also other R/W CANGIT General register activity flags in addition to the CANSTMOB MOb register activity flags.

The read only CANSIT register bits work with the CANHPMOB register to use the CAN hardware to find which MObs have any activity in their CANSTMOB register. The CANSIT bits are only set for the corresponding CANSTMOB bits enabled with CANGIE.ENTX, CANGIE.ENRX or CANGIE.ENERR bits. See the data sheet CANHPMOB explanation. This CANHPMOB register support allows your code to rapidly find out which MObs need to have active CANSTMOB flags serviced and ignore MObs with no CANSTMOB activity.

When the CAN hardware sets any CANSTMOB register bit in any MOb group and that CANSTMOB bit is enabled by CANGIE.ENTX, CANGIE.ENRX or CANGIE.ENERR bits, the read only CANSIT register SITn bit for the MOb is set. The CANSIT register may be read by your software, but its primary purpose is to support CANHPMOB. When your software clears the enabled CANSTMOB bits, the CANSIT bit for the MOb is cleared and CANHPMOB now ignores this serviced MOb. Next any MOb that has any task assigned must have its CANIE register IEMOBn bit for the MOb set. In fact the CANIE bits may be set for any MOb that could ever be used, during CAN initialization and left that way.

After a MOb task completes and a CANSTMOB.RXOK or CANSTMOB.TXOK bit is set by the CAN hardware, the MOb is automatically disabled and its corresponding CANEN register ENMOBn bit is cleared. The CAN hardware sets the MOb CANSTMOB RXOK or TXOK bit and your program code must clear CANSTMOB after responding to this MOb task activity. Unlike RXOK or TXOK, when any CANSTMOB error bits are set by the CAN hardware the MOb CANEN register bit is not automatically disabled, unless the current MOb task is a just completed MOb disable command that ended with a final MOb error. The CANGCON.ABRQ abort all MObs request also takes time to complete and the single possible MOb that might already be busy using the CAN bus could still complete normally and set any of its CANSTMOB flags (MOb disable commands and aborts do not immediately terminate the active on-going communication MOb already using the CAN bus). Clearing CANGCON.ENASTB=0 (disabling the entire CAN module) also has on-going communication issues. Only setting CANGCON.SWRES=1 will immediately terminate all on-going communication and probably cause errors in other CAN nodes by doing this.

When the MOb CANEN bit is already cleared, writing a CANCDMOB command to disable the MOb is immediate with no delay because the MOb is already disabled. Anytime a MOb CANEN bit is already set, writing a CANCDMOB command to disable the MOb is a request that takes time to complete before the CAN hardware clears the MOb CANEN bit. If the busy MOb disable request fails, the MOb may possibly still complete and disable with a CANSTMOB RXOK, TXOK or final error flag.

CAN Initialization:

    Write CANGCON.SWRES=1
    Initialize any CAN code global variables here while the CAN hardware is idle
    For all MOb groups:
        Write CANPAGE=MOb number
        Write CANCDMOB=0
        Write CANSTMOB=0
    Write CANBT1, CANBT2 and CANBT3 with the CAN baud setup values
    Write CANGIE to your desired configuration
        CANGIE.ENIT=0 for polling using the read only CANGIT.CANIT bit
        CANGIE.ENIT=1 for interrupts using AVR interrupt vector 19
        See the data sheet Figure CAN Controller Interrupt Structure for more CANGIE info
    Write CANIE1 and CANIE2 bits, typically =1 for all MObs to be used
    If desired write the CANHPMOB CGP3, CGP2, CGP1 and CGP0 bits
        Typically the General register CANHPMOB reset default is the most useful
    If you are using time stamping write CANTCON with any desired non-zero value
        The General register CANTCON reset default is already zero
    All other CAN General registers are initialized by the SWRES above
    Write CANGCON.ENASTB=1

The CANGCON.SWRES=1 resets the CAN hardware, which always recovers from any CAN Rx state machine confusion. Since the General CAN registers are all initialized by this reset, all CAN interrupts and activity are safely disabled until after CANGCON.ENASTB=1 (you do not need to disable AVR global interrupts for CAN initialization when you use SWRES). You do not need to wait for the CAN hardware to set CANGSTA.ENFG, but if you do wait you must provide a wait length time out in case the CAN hardware fails to start. For example, if the physical CAN bus is stuck in a dominant state the CAN hardware will never set ENGF and you do not want to disable the entire AVR chip forever waiting on something that will never happen. After CANGCON.ENASTB=1 the CAN will accept new tasks, but none of these tasks will run or complete until after the CAN hardware sets CANGSTA.ENFG.

CAN MOb Tx task initialization:

    Make sure the MOb n CANEN1, CANEN2 ENMOBn bit is cleared (the MOb is not busy)*
        Never use an already busy MOb to Tx
    Write CANPAGE.MOBNBn=MOb number and CANPAGE.INDXn=0
        CANPAGE.AINC=0 is the usual setting
    Make sure the MOb CANSTMOB value is cleared*
        The polling or interrupt code must finish with and clear CANSTMOB for this MOb first
    Write CANIDT1, CANIDT2, CANIDT3 and CANIDT4 to the CAN ID value (see IDE bit below)
        Write all unused/reserved bits=0
    Write CANIDT4.RTRTAG=0 for CAN Data Frame, or =1 for CAN Remote Frame
    Write CANIDM1, CANIDM2, CANIDM3 and CANIDM4 all =0
        None of the CANIDM registers are used by a Tx, but the data sheet said to clear all reserved bits
    Sequentially write all CANMSG bytes to be sent in the Tx (8 bytes maximum)
        If CANPAGE.AINC=0 the CANPAGE.INDXn value will auto-increment after each write
        If CANPAGE.AINC=1 you must change the CANPAGE.INDXn value for each CANMSG write
    Write CANCDMOB.CONMOBn=01 enable transmission
        Also write CANCDMOB.IDE=0 for 11 bit IDs, or =1 for 29 bit IDs
        Also write CANCDMOB.DLCn to match the number of CANMSG bytes written (8 bytes maximum)
        Also always write CANCDMOB.RPLV=0
        All four of these CANCDMOB register bit writes are all done together one time only for each MOb task

CAN MOb normal Rx task initialization:

    Make sure the MOb n CANEN1, CANEN2 ENMOBn bit is cleared (the MOb is not busy)*
        Never use an already busy MOb to Rx
    Write CANPAGE.MOBNBn=MOb number and CANPAGE.INDXn=0
        CANPAGE.AINC=0 is the usual setting
    Make sure the MOb CANSTMOB value is cleared*
        The polling or interrupt code must finish with and clear CANSTMOB for this MOb first
    Write CANIDT1, CANIDT2, CANIDT3 and CANIDT4 to the CAN ID value (see IDE bit below)
        Write all unused/reserved bits=0
    Write CANIDT4.RTRTAG=0 for CAN Data Frame, or =1 for CAN Remote Frame
    Write CANIDM1, CANIDM2, CANIDM3 and CANIDM4 IDMSKn bits to:
        =0 for any IDMSKn bit you want to mask (ignore the corresponding CANIDT.IDTn bit value)
        =1 for any IDMSKn bit you want to match (use the corresponding CANIDT.IDTn bit value)
        Write all unused/reserved bits=0
    Write CANIDM4.RTRMSK=1 to match CANIDT4.RTRTAG, or =0 to ignore CANIDT4.RTRTAG
        =0 will Rx either CAN Data Frames or CAN Remote Fames
        =1 will only Rx the CAN frame type set in CANIDT4.RTRTAG
    Write CANIDM4.IDEMSK=1 to match CANCDMOB.IDE, or =0 to ignore CANCDMOB.IDE
        =0 will Rx either 11 bit CAN IDs or 29 bit CAN IDs
        =1 will only Rx the CAN ID length set in CANCDMOB.IDE
    Write CANCDMOB.CONMOBn=10 enable reception for a normal Rx
        If CANIDM4.IDEMSK is zero
            Also write CANCDMOB.IDE=1 (only use 29 bit IDs in this case)
        if CANIDM4.IDEMSK is one
            Also write CANCDMOB.IDE=0 for 11 bit IDs, or =1 for 29 bit IDs
        Also write CANCDMOB.DLCn to match the number of CANMSG bytes expected to Rx (8 bytes maximum)
        Also write CANCDMOB.RPLV=0 for a normal Rx
        All four of these CANCDMOB register bit writes are all done together one time only for each MOb task

*The CANEN check for MOb busy and CANSTMOB cleared check may be skipped the very first use after the CAN hardware is initialized. If your program never sets a MOb disable task and your program code flow always waits for the CANSTMOB.TXOK or CANSTMOB.RXOK code to finish first, you may skip these two checks. If your program code only uses a CANCDMOB.CONMOBn=0 MOb busy check and does not ever check CANEN1 or CANEN2 for MOb busy, you must never set any MOb disable task, because the write CONMOBn=0 disable command reads as zero (false not busy) when the CANEN MOb bit is still set to busy while a disable request is active (the correct CANEN1 or CANEN2 MOb bit is the only true MOb busy indicator). If you really need to use a busy MOb for a new MOb Tx or Rx task, use a MOb disable task, wait for the CANEN MOb busy bit to clear first, process any MOb activity if any (CANSTMOB) and then use the MOb for the new task.

It is important to preserve the General register CANEN ENMOBn bit check, set MOb n register CANPAGE value and then check CANSTMOB sequence. Since in theory the CANEN bit and CANSTMOB values are changed simultaneously by the CAN hardware, using this sequence ensures they are always detected accurately by your program code.

When CANIDM4.IDEMSK=0 always use CANCDMOB.IDE=1 (29 bit long ID). If CANCDMOB.IDE=0 and CANIDM4.IDEMSK=0 you are setting up an 11 bit ID Rx MOb that might return a 29 bit ID result because IDEMSK=0 (it makes no sense and cripples your Rx MOb setup to use an 11 bit ID setup for a possible 29 bit ID read). A CANCDMOB.IDE=0 with CANIDM4.IDEMSK=0 and all CANIDM IDEMSKn bits =0 with all CANIDT IDTn bits =0 exception is seen in the "CAN transmission after 3-bit intermission" AT90CANxxx family errata. This only works correctly because all 29 CANIDM IDEMSKn bits are =0 (masked).

Anytime any MOb disables and automatically clears its corresponding CANEN register ENMOBn bit (disables), this MOb CANCDMOB register CONMOB1 and CONMOB0 bits are not changed. The last MOb command is still shown in these CANCDMOB bits after the MOb completes. The MOb will not re-enable until your code writes CANCDMOB with another command. If you want to clear these CANCDMOB command bits to zero, your code will have to do it after the MOb disables and clears its CANEN bit (when RXOK or TXOK is handled is a good place to do this clear if you want to do it).

The CANPAGE register INDXn=0 CANMSG byte is always the first one sent or received on the CAN bus. It does not matter what INDXn order your code writes CANMSG bytes in, but the order they are used in by the CAN hardware is fixed starting at CANMSG byte number 0 up to CANMSG byte number 7 depending on the DLCn length value.

How to process CANSTMOB.TXOK activity set by the CAN hardware:

    Write CANPAGE.MOBNBn=MOb number
    Check that CANSTMOB.TXOK is set
        When TXOK is set all CANSTMOB error bits are cleared
    Read CANSTMH and CANSTML if your code uses time stamps
    Write CANSTMOB=0

If CANCDMOB.RPLV was set when the Rx MOb Remote Frame task was initialized, the CANSTMOB.TXOK response becomes a composite of a Rx MOb Remote Frame with an automatic reply Tx Data Frame from the same MOb that ends with a TXOK (there is no RXOK and the RPLV bit is cleared before the TXOK). This complicates any RPLV enabled TXOK processing (see the data sheet).

I find it is simpler, cleaner and more flexible to never use CANCDMOB.RPLV=1 and do this function (if you want to use it) in your software instead. Using software allows your Tx reply to use fresh node data and even use a different reply ID if desired. Using RPLV=1 must set up the reply data first thing when the Rx Remote Frame MOb task is initialized, possibly long before this Rx MOb receives the actual request, and the automatic Tx Data Frame reply ID must match the same Rx Remote Frame request ID (no choice).

How to process CANSTMOB.RXOK activity set by the CAN hardware:

    Write CANPAGE.MOBNBn=MOb number and CANPAGE.INDXn=0
        CANPAGE.AINC=0 is the usual setting
    Check that CANSTMOB.RXOK is set
        When RXOK is set all CANSTMOB error bits are cleared
        Only when RXOK is set the DLCW bit might also be set
    Read CANSTMH and CANSTML if your code uses time stamps
    If CANIDM4.IDEMSK is zero
        Read CANCDMOB.IDE to get the new Rx ID length (=0 is 11 bit ID, =1 is 29 bit ID)
        You must know IDE to read the CANIDT1, CANIDT2, CANIDT3 and CANIDT4 ID value
        If the old IDE is changed by the new IDE value you must (also true if IDMSKn bits=0):
            Read the new CANIDT1, CANIDT2, CANIDT3 and CANIDT4 ID value using the new IDE value    
    If CANIDM4.RTRMSK is zero
        Read CANIDT4.RTRTAG to get the new Rx frame type (=0 is Data Frame, =1 is Remote Frame)
    If CANIDM1, CANIDM2, CANIDM3 or CANIDM4 have any IDMSKn bits=0 you must:
        Read the new CANIDT1, CANIDT2, CANIDT3 and CANIDT4 ID value using the IDE value
    If CANCDMOB.IDE is zero, CANIDM4.IDEMSK is zero and you might re-enable this MOb task later:
        Restore the original CANIDT2, CANIDT3 and CANIDT4 bit values numbered 20 through 3 + clear bit 1
    If CANCDMOB.IDE is zero, CANIDM4.IDEMSK is one and you might re-enable this MOb task later:
        Clear the CANIDT2, CANIDT3 and CANIDT4 reserved bits numbered 20 through 3 + bit 1
    Read the new CANCDMOB.DLCn value and limit it to a value of 8 maximum (very important)
    If CANIDT4.RTRTAG is zero (only a CAN Data Frame has any CANMSG bytes)
        Sequentially read the limited DLCn number of CANMSG bytes to get the CAN data
            If CANPAGE.AINC=0 the CANPAGE.INDXn value will auto-increment after each read
            If CANPAGE.AINC=1 you must change the CANPAGE.INDXn value for each CANMSG read
    Write CANSTMOB=0

The CANSTMOB TXOK and RXOK bits are never set together at the same time by the CAN hardware. Never forget CANSTMOB is a MOb register, so setting a known General CANPAGE register value is always required first before accessing any specific MOb CANSTMOB value (or before accessing any other MOb register).

When using a MOb n 11 bit ID (CANCDMOB.IDE=0), after the CANSTMOB.RXOK the CANIDT2, CANIDT3 and CANIDT4 reserved bits numbered 20 to 3 plus bit 1 are updated with random values (see the data sheet CAN Identifier Tag Registers - CANIDT1, CANIDT2, CANIDT3, and CANIDT4). If CANIDM4.IDEMSK=1 and you reuse these CANIDT2, CANIDT3 and CANIDT4 register values to re-enable the MOb n Rx task, you must clear all of these updated randomized reserved bits first. If CANIDM4.IDEMSK=0 and you reuse these CANIDT2, CANIDT3 and CANIDT4 register values to re-enable the MOb n Rx task, you must restore all of these updated randomized reserved bits to their original value first. Only if CANCDMOB.IDE=0, CANIDM4.IDEMSK=0 and all CANIDM2, CANIDM3, CANIDM4 bit numbers 20 through 3 are all zero values (masked) then the original value of the CANIDT2, CANIDT3 and CANIDT4 register bits 20 through 3 does not matter (CANIDT4 bit 1 still must be cleared). When re-enabling the Rx MOb n, the other solution is not to use the existing CANIDT2, CANIDT3 and CANIDT4 values and always start over by writing new values if you re-enable this MOb.

Upon CANSTMOB.RXOK the DLCW bit use is optional. When you setup the Rx MOb the CANCDMOB.DLCn value is set to the expected number of CANMSG bytes to Rx. The actual CAN Rx will overwrite the expected DLCn value, and if the actual DLCn value is different from the original now overwritten and lost expected DLCn value, the CANSTMOB.DLCW bit will be set. If you always get the new DLCn value after a RXOK, the CANSTMOB.DLCW bit is only really important when CANCDMOB.RPLV=1 in a CAN Remote Frame Rx MOb.

As shown above, several CAN MOb register values may be updated and changed by a CAN Rx. The CANSTMOB.RXOK response may be simpler. For example, if your program only ever uses CANIDM4.IDEMSK=1 you know the ID length will always be exactly what you set in CANCDMOB.IDE. If you always have CANIDT4.RTRTAG=0 and CANIDM4.RTRMSK=1 is always true, you never need to check for CAN Remote Frames and you will always have DLCn number of CANMSG bytes to read. If none of the CANIDM1, CANIDM2, CANIDM3 or CANIDM4 values have any IDMSKn bits=0 and CANIDM4.IDEMSK=1 the CANIDT1, CANIDT2, CANIDT3 and CANIDT4 ID Rx value will not change, so you may substitute the RXOK MOb number n for this known ID value and not bother reading the CANIDT registers ID value. If you never re-enable an 11 bit ID Rx MOb with old CANIDT values it gets simpler.

The above TXOK and RXOK processing descriptions do not cover if software polling of CANGIT.CANIT or if the hardware CAN IT AVR vector 19 interrupt is used to respond to the MOb activity. Your software must clear CANSTMOB when finished processing the polling or interrupt MOb activity response. If you use the CAN IT interrupt, you must first save the CANPAGE value, then restore this saved CANPAGE value before returning from the interrupt response. If you fail to clear any active MOb CANSTMOB bits while using interrupts, you will get really slowed down in an infinite CAN IT interrupt response loop (one single non-interrupt instruction always executes between repeated interrupt responses).

The CANHPMOB register may be used in a polling or CAN IT interrupt response to quickly locate only the MOb CANSTMOB registers that require attention and ignore any MObs that do not need service.

The General CANGIT flags are cleared by writing a one to the flag bit or flag bits you want to clear. This is how AVR interrupt flags are normally cleared. It is the CANSTMOB flags that are different and are cleared by writing a zero.

What the data sheet said about the CANSTMOB flag bits "It must be cleared using a read-modify-write software routine on the whole CANSTMOB register.", what was actually meant is the must only applies to only clearing a specific bit. It is perfectly acceptable to simply write CANSTMOB=0 when without any read-modify-write cycle when you want to clear the entire CANSTMOB register, but the MOb should already be disabled (except for the busy MOb clear CANSTMOB error flags exception - see below).

Keep in mind the MOb CANSTMOB.TXOK or CANSTMOB.RXOK automatically disables the MOb (the MOb CANEN bit is cleared). When a MOb is disabled it is safe to read or write the MOb registers, up until CANCDMOB is written again. Safe means the CAN hardware will not change any MOb register values or get confused if your program code changes any MOb register values. Anytime the MOb CANEN1 or CANEN2 MOb bit is set and the MOb is busy, it is not safe to read or write any MOb registers (except reading any CANSTMOB is always safe). The only three unsafe write exceptions are when writing a new MOb disable task to a busy MOb, when clearing CANSTMOB error flags when CANGIE.ENRR=1, or when writing CANCDMOB for the "CAN transmission after 3-bit intermission" AT90CANxxx family errata. If CANGIE.ENRR=0 the CANSTMOB error flags will not be responded to, so just ignore the CANSTMOB error flags.

After a MOb CANSTMOB TXOK or RXOK bit is automatically set (the MOb disables), all the information in the MOb registers is safe until you write to any of those MOb registers or start another MOb task by writing to that CANCDMOB. You must extract (read) all MOb information from a completed MOb before you may reuse that MOb for a new task. This means the polling or interrupt code may extract the MOb information immediately then re-enable the MOb, or the MOb information may be extracted later from the still unchanged disabled MOb registers. If you are using interrupts this means you may delay extracting MOb information, as in do it later after the CAN IT interrupt code clears CANSTMOB and returns. Usually in this delayed case a dedicated MOb global software flag value is used to signal the non-interrupt code that it needs to extract MOb information. Either choice of an immediate extraction or a delayed extraction depends on how fast you may need to re-enable a MOb. An immediate extraction usually takes more SRAM to copy MOb information into.

A new 11 bit ID CAN Frame Rx has 19 CAN bit times (bit times depend on the CAN baud) after the RXOK to re-enable the MOb without any possibility of missing any new CAN Frames. A new 29 bit ID CAN Frame Rx has 39 CAN bit times after the RXOK to re-enable. If you need additional time to re-enable a RXOK automatically disabled Rx MOb task, you may create duplicate Rx MOb tasks in multiple Rx MObs. The lowest MOb number n will take the first RXOK, leaving all higher numbered MOb n tasks still enabled and ready for the next Rx without any delay. The extra duplicate MOb or MObs will give you lots of time to extract MOb data and re-enable the disabled MOb or MObs without any loss of any new Rx CAN Frames.

Whenever possible, 8 bit AVR chip global software flags shared in an interrupt should be a single byte (8 bits). When accessing multiple byte single flag values (more than one byte long flags), this non-interrupt code access may be split by an interrupt response. Splitting the access may corrupt the 16 bit or greater global flag value. Non-interrupt code multiple byte single global flag access like this requires global interrupts are disabled before any access and global interrupts are restored after the access. Single byte access non-interrupt code does not require global interrupt disable/enable protection since an 8 bit AVR cannot split access to a single byte.

Never put slow code with long delays or USART output in any interrupt response code. If you are using AVR interrupt vector 19 CAN IT and you have slow interrupt response code anywhere, it will mess up the ability of vector 19 to rapidly respond to new CAN activity. For example, never use USART output debug code in any interrupt response code (this type of slow ISR debug code will cause bugs all by itself)!

Whenever CANCDMOB.IDE is masked (CANIDM4.IDEMSK=0) it adds some complexity to using the CAN hardware correctly. The only exception is the "CAN transmission after 3-bit intermission" AT90CANxxx family errata which remains simple to use. This is because this errata only re-enables the errata MOb and never uses any information from this errata MOb.

/* These are just C examples of some ways to code the CANIDT and CANIDM values.
   For numerically identical Tx ID values with different CAN Frame types or ID lengths:
       11 bit ID (CANCMOB.IDE=0) Data Frame (CANIDT4.RTRTAG=0) is a unique Tx ID.
       11 bit ID (CANCMOB.IDE=0) Remote Frame (CANIDT4.RTRTAG=1) is a unique Tx ID.
       29 bit ID (CANCMOB.IDE=1) Data Frame (CANIDT4.RTRTAG=0) is a unique Tx ID.
       29 bit ID (CANCMOB.IDE=1) Remote Frame (CANIDT4.RTRTAG=1) is a unique Tx ID.

All Tx Data Frame IDs sent by any CAN node MUST be unique (only be sent by that one
CAN node). Tx Remote Frame IDs do not have to be unique as long as the CANCDMOB.DLCn
value always matches. Any CAN node may Rx any ID of any type. */

/* The conditional structure of all these examples are as follows:

    #ifdef (32 bit SFIOR name)
        // Handle the entire 32 bit value with a single read or write.
    #else (this compiler does not support 32 bit SFIORs)
        // Handle the 32 bit value by reading or writing 8 bits at a time.
    #endif

If your compiler supports 32 bit SFIORs choose which one you want to use. */

//*******************************************************
// Set an 11 bit CAN Data Frame (RTRTAG=0) ID
//   - CANCDMOB.IDE bit should be cleared when CANCDMOB is written later

    unsigned int set_id_11f;         // Preset 11 bit format ID value (0x7EF max)

    CANPAGE = (mob << MOBNB0);       // Select MOb, AINC = 0, INDEX2:0 = 0

    #ifdef CANIDT
            // Set 11 bit format ID.
        CANIDT = ((unsigned long) set_id_11f << 21) | (0UL << RTRTAG);
    #else
        CANIDT1 = (unsigned char) (set_id_11f >> 3); // Set 11 bit format ID.
        CANIDT2 = (unsigned char) (set_id_11f << 5);
        CANIDT3 = 0x00;
        CANIDT4 = (0 << RTRTAG);
    #endif
    // RTRTAG (data frame = 0) and RB0TAG are both zero.

//*******************************************************
// Set an 11 bit Rx ID mask with no masked bits - 0x7FF is no mask
//   - CANCDMOB.IDE bit should be cleared when CANCDMOB is written later

    CANPAGE = (mob << MOBNB0);       // Select MOb, AINC = 0, INDEX2:0 = 0

    #ifdef CANIDM
        CANIDM = (0x7FFUL << 21) | (1UL << RTRMSK) | (1UL << IDEMSK);
    #else
        CANIDM1 = (unsigned char) (0x7FF >> 3); // No ID mask is set.
        CANIDM2 = (unsigned char) (0x7FF << 5);
        CANIDM3 = 0x00;
        CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK);
    #endif

//*******************************************************
// Read an 11 bit ID value and convert it into an integer
//   - first check that the CANCDMOB.IDE bit was cleared by the RXOK

    unsigned int read_id_11f;        // Rx updated ID value when any CANIDM bits = 0

    CANPAGE = (mob << MOBNB0);       // Select MOb, AINC = 0, INDEX2:0 = 0

    #ifdef CANIDT
        read_id_11f = (unsigned int) (CANIDT >> 21);
    #else
        read_id_11f = ((unsigned int) CANIDT1 << 3) |
                      ((unsigned int) CANIDT2 >> 5);
    #endif

//*******************************************************
// Set a 29 bit CAN Data Frame (RTRTAG=0) ID
//   - CANCDMOB.IDE bit must be set when CANCDMOB is written later

    unsigned long set_id_29f;    // Preset 29 bit format ID value (0x1FBFFFFF max)

    CANPAGE = (mob << MOBNB0);   // Select MOb, AINC = 0, INDEX2:0 = 0

    #ifdef CANIDT
        CANIDT = (set_id_29f << 3) | (0UL << RTRTAG); // Set 29 bit format ID.
    #else
        CANIDT1 = (unsigned char) (set_id_29f >> 21); // Set 29 bit format ID.
        CANIDT2 = (unsigned char) (set_id_29f >> 13);
        CANIDT3 = (unsigned char) (set_id_29f >> 5);
        CANIDT4 = (unsigned char) (set_id_29f << 3) | (0 << RTRTAG);
    #endif
    // RTRTAG (data frame = 0), RB0TAG and RB1TAG are all zero.

//*******************************************************
// Set a 29 bit Rx ID mask with no masked bits - 0x1FFFFFFF is no mask
//   - CANCDMOB.IDE bit must be set when CANCDMOB is written later

    CANPAGE = (mob << MOBNB0);       // Select MOb, AINC = 0, INDEX2:0 = 0

    #ifdef CANIDM
        CANIDM = (0x1FFFFFFFUL << 3) | (1UL << RTRMSK) | (1UL << IDEMSK);
    #else
        CANIDM1 = (unsigned char) (0x1FFFFFFFUL >> 21); // No ID mask is set.
        CANIDM2 = (unsigned char) (0x1FFFFFFFUL >> 13);
        CANIDM3 = (unsigned char) (0x1FFFFFFFUL >> 5);
        CANIDM4 = (unsigned char) (0x1FFFFFFFUL << 3) | (1 << RTRMSK) |
                                  (1 << IDEMSK);
    #endif

//*******************************************************
// Read a 29 bit ID value and convert it into a long
//   - first check that the CANCDMOB.IDE bit was set by the RXOK

    unsigned long read_id_29f;       // Rx updated ID value when any CANIDM bits = 0

    CANPAGE = (mob << MOBNB0);       // Select MOb, AINC = 0, INDEX2:0 = 0

    #ifdef CANIDT
        read_id_29f = (CANIDT >> 3);
    #else
        read_id_29f = ((unsigned long) CANIDT1 << 21) |
                      ((unsigned long) CANIDT2 << 13) |
                      ((unsigned long) CANIDT3 << 5) |
                      ((unsigned long) CANIDT4 >> 3);
    #endif

// For compilers that support 32 bit AVR Special Function I/O Register (SFIOR)
// access, both types of register access are shown, except AVR instruction cycle
// efficiency varies and does not consistently favor either 32 bit or 8 bit type
// of access. Not all compilers support 32 bit SFIORs.

// The unsigned char mob value details are missing in the above code snippets.

The difference between Rx General CANGIT error bits and Rx MOb CANSTMOB error bits is the CAN acceptance filter recognition (see the data sheet acceptance filter section). Any CAN Rx error that happens before the Rx acceptance filter hit will go into the General CANGIT register. Any CAN Rx error that happens after the Rx acceptance filter hit will go into the matching hit number MOb CANSTMOB register. Because a Tx MOb is required for any AVR CAN Tx, all Tx errors always go into the Tx MOb CANSTMOB register. Since the CANSMOTB.BERR bit is only a Tx error bit, there is no equivalent error bit in the CANGIT register. Errors in the General CANGIT register may be from CAN Rx activity that never matched any MOb Rx task, or may be CAN Rx activity errors early in the CAN arbitration field that made any acceptance filter hit test impossible.

The main point and intent of the acceptance filter is too screen out any Rx CAN message traffic your CAN node does not care about. This is because CAN is a broadcast bus and all CAN Tx messages are received by every CAN node. The acceptance filter hardware relieves the AVR CAN node software from the choir of having to filter out unwanted Rx CAN messages in real time. Using the Rx CANIDM1, CANIDM2, CANIDM3 and CANIDM4 mask registers allows your AVR CAN node to filter (only Rx the specific CANIDT registers and CANCDMOB.IDE ID value) or allow (mask) any/all CAN ID message traffic as desired.

An important point is the acceptance filter searches for matching enabled Rx MObs starting from the lowest number MOb group up to the highest numbered enabled Rx MOb. If a lower numbered enabled Rx MOb gets an acceptance filter match hit, then any higher numbered enabled Rx MOb that also matches will not get that acceptance filter hit. This is why the "CAN transmission after 3-bit intermission" MOb AT90CANxxx family errata, which matches every possible Rx CAN traffic (all CANIDM registers bits are zero), is always the highest numbered MOb possible. This makes the enabled errata MOb the last one searched and it only picks up any Rx CAN traffic all the other enabled Rx MObs ignored. This also means the errata MOb receives CANSTMOB errors that would have normally gone into the CANGIT register (only if the errata MOb got the match hit, otherwise early errors that make the acceptance filter hit test impossible still go into CANGIT).

If you are curious, the acceptance filter hit that happens after the live CAN data stream arbitration field ends is what drives the 19 or 39 CAN bit times to re-enable an automatically RXOK disabled Rx MOb for continuous Rx coverage. If the Rx MOb is not re-enabled before the filter hit is checked for, then that MOb will not receive the new CAN message traffic. The delay required to Rx and process the new arbitration field CAN data stream is why the Rx MOb re-enable does not have to be instant. Other ways to extend this CAN bit time limit have already been mentioned.

Last Edited: Fri. Jul 6, 2012 - 08:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is C compiler version of the basic CAN hardware initialization code:

void can_init (void) {

    unsigned char mob;          // Temporary MOb register set selection number.

    // The next 3 lines of commented out code are completely optional. Do not
    //  use them unless you have a specific reason to do so.
//  CANGIE = 0;                     // Disable all CAN interrupts.
//  CANGCON = (0 << ENASTB);        // Force standby mode.
//  while (CANGSTA & (1 << ENFG));  // Wait for CAN hardware to disable.

        // Reset the CAN controller hardware and general registers.
    CANGCON = (1 << SWRES);

        // Use 6 instead of 15 for the ATmega CAN chips.
    for (mob = 0; mob < 15; mob++) {
        CANPAGE = (mob << MOBNB0);  // Set the MOb page number for each MOb.
        CANCDMOB = 0;         // Set each MOb to disabled *CRITICAL*.
        CANSTMOB = 0;         // Clear all MOb interrupt/polling flags *CRITICAL*.
    }
    // All other MOb registers only need to be setup before using the MOb.

        // Use your own values, only if you need to use another value than zero.
        // Default zero values from CANGCON.SWRES are shown.
        // Setup the CANPAGE AINC bit and INDX initial values.
//  CANHPMOB = (0 << CGP3) | (0 << CGP2) | (0 << CGP1) | (0 << CGP0);

        // Only if you use CANSTM and need to use another value than zero.
        // Default zero value from CANGCON.SWRES is shown.
//  CANTCON = 0x00;             // Set the CAN Timer Prescaler Control Register.

        // Use your own values (this is just an example).
        // Setup the CAN baud timing.
    CANBT1 = 0x12;              // Timing - See the data sheet errata if CANBT1=0.
    CANBT2 = 0x0C;              // Timing - Jump Width and Propagation.
    CANBT3 = 0x37;              // Timing - Phase Segments 2, 1 and Sample Point.

        // Use your own values (this is just an example).
        // Enable CAN IT interrupts for CANSTMOB RXOK and TXOK.
    CANGIE = (1 << ENIT) | (1 << ENRX) | (1 << ENTX);

        // Enable all the AT90CAN MObs for polling or interrupts.
    CANIE2 = 0xFF;              // Use 0x3F for the ATmega CAN chips.
    CANIE1 = 0x7F;              // Do not use this for the ATmega CAN chips.

    CANGCON = (1 << ENASTB);    // Enable the CAN and start the CANTIM counter.

    // If you wait for CANGSTA.ENFG to be set, you must provide a wait time
    // out in case the CAN fails to set ENFG.
}

This example is for the AT90CANxxx family CAN chips and includes comments about changes for the ATmegaxxxx family CAN chips.

This is C compiler version of a CAN IT interrupt TXOK/RXOK/ERROR handler template:

#define MOB_RX_CMD      ((1 << CONMOB1) | (0 << CONMOB0))
#define MOB_TX_CMD      ((0 << CONMOB1) | (1 << CONMOB0))
#define MOB_MAX_DLC     ((1 << DLC3) | (0 << DLC2) | (0 << DLC1) | (0 << DLC0))
#define MOB_RXOK        (1 << RXOK)
#define MOB_TXOK        (1 << TXOK)
#define MOB_ENERR_FLGS  ((1 << BERR) | (1 << SERR) | (1 << CERR) | (1 << FERR) | (1 << AERR))

    // This is used to limit Rx CANCDMOB.DLC values to a maximum of 8. This is very important.
#define MOB_DLC_LIMIT(dlc) (((dlc) > MOB_MAX_DLC) ? MOB_MAX_DLC : (dlc))

INTERRUPT CAN IT () {       // Use the correct syntax for your embedded C compiler.

    unsigned char save_page;    // Pre-interrupt CANPAGE value storage.
    unsigned char mob;          // Temporary MOb number value.
    unsigned char isr_flags;    // Temporary interrupt flags value.

    save_page = CANPAGE;        // Save the pre-interrupt CANPAGE value.

        // CANGIE ENTX, ENRX and ENERR in can_init() enables the MOb interrupt
        // CAMSTMOB flags that CANSIT and CANHPMOB will respond to.
        // Only use CANPAGE = CANHPMOB one time for each MOb while loop.
        // See CANHPMOB.CGPn bits for initial CANPAGE AINC and INDX values.
        // See CANHPMOB.HPMOBn bits description for the reason 0xF0 is used.
        // The CANSIT.SITn bit must be set for CANHPMOB to select that MObn value.
    while ((CANPAGE = CANHPMOB) < 0xF0) {

  #ifdef OPTIONAL_AT90CAN_ERRATA
  //AT90CAN...ERRATA*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*AT90CAN...ERRATA
    // AT90CAN... errata SPY MOb (see the data sheet errata). Notice that the SPY
    // errata is handled outside of the CANHPMOB priority ordering to ensure
    // consistent fast as possible SPY errata interrupt handling.
        // A small optimization to use the correct CANSIT 8 bit register, rather than the entire 16 bit register.
      #if (SPY_MOB > 7)
        if (CANSIT1 & (1 << (SPY_MOB - 8)))     // SPY_MOB interrupt CANSIT[SPY_MOB]=non-zero.
      #else
        if (CANSIT2 & (1 << SPY_MOB))           // SPY_MOB interrupt CANSIT[SPY_MOB]=non-zero.
      #endif
        {
            // Since CANSTMOB error bits do not disable the MOb and no SPY Rx updated
            // information is ever read or used, this simplified re-enabling an
            // already enabled MOb tactic is not a problem. For normal MOb usage,
            // you would never write a Rx enable command to an already enabled MOb.
            CANPAGE = (SPY_MOB << MOBNB0);          // Select the SPY_MOB.
            CANSTMOB = 0x00;                        // Clear all of the SPY_MOB interrupt flags.
            CANIDT4 = 0x00;                         // Ensure bit 1 is cleared in case a RXOK randomized it.
            CANCDMOB = MOB_RX_CMD | MOB_MAX_DLC;    // Re-enable the SPY MOb Rx (as shown in the data sheet).
            continue;                               // The SPY_MOB has no Rx info to process.
        }
  //AT90CAN...ERRATA*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*^*AT90CAN...ERRATA
  #endif

            // Extract the MOb number value of the MOb being processed.
        mob = (CANPAGE >> MOBNB0);
        isr_flags = CANSTMOB;         // Save the MOb interrupt flags state.
            // Clear the MOb interrupt flags when you process each MOb. This also
            // clears the read only CANSIT.SITn bit for this MOb number n (now
            // CANHPMOB will ignore this MOb when the CANSIT.SITn bit is cleared).
        CANSTMOB = 0;                 // Immediately clear the flags.

        // ******* process this active CANSTMOB interrupt MOb number *******
        // You must use isr_flags since CANSTMOB was cleared.
        if (isr_flags & MOB_TXOK) {       // Only if CANGIE.ENTX is set.
            // Process MOb number mob TXOK activity. Add your code here.
        }
        if (isr_flags & MOB_RXOK) {       // Only if CANGIE.ENRX is set.
            // Process MOb number mob RXOK activity. Add your code here.
            // Always use MOB_DLC_LIMIT(CANCDMOB.DLC) to get the DLC value.
        }
        if (isr_flags & MOB_ENERR_FLGS) { // Only if CANGIE.ENERR is set.
            // Process any isr_flags error bits here (if you care).
            // Optional: recover any wiped out TXOK, RXOK or DLCW bits in isr_flags (see below).
        }

    } // ===> end of the while(CANHPMOB) MOb processing loop <===

    // CANGIE in can_init() selects the enabled General interrupt flags.

        // First save and then clear the general interrupt flags.
    isr_flags = CANGIT;         // Save the current general interrupt flags state.
        // OVRTIM does not belong to this CAN IT interrupt vector.
        // Using isr_flags instead of CANGIT prevents clearing any new interrupts.
        // Clear only the General interrupt flags that will be processed next.
    CANGIT = isr_flags & ~(1 << OVRTIM);

    // ***** process all enabled general CANGIT interrupts using isr_flags *****
    // An example of using isr_flags instead of CANGIT would be:
    //  if (isr_flags & (1 << BOFFIT)) - CANGIT is not used since it was cleared.

    CANPAGE = save_page;        // Restore the pre-interrupt CANPAGE value.
}

How you process each MOb TXOK or RXOK is up to you. For example the RXOK may immediately extract MOb information, or it may set a volatile global software variable so that non-interrupt code may detect and process the RXOK activity and extract the MOb information later.

When using the AT90CAN... family ERRATA, the SPY_MOB number is always the highest numbered MOb used (usually MOb number 14 decimal - the 15th MOb). Remove this AT90CAN... ERRATA code if you are using the ATmega.... family CAN chips.

If CANGIE.ENERR is set, the required CANSTMOB=0 clear of the error bits could under very rare circumstances wipe out a new CANSTMOB RXOK, DLCW or TXOK. There is a fix for this very rare bug that is not shown in this simple typical use example. These two sequential operations make it possible to test for this problem:

isr_flags = CANSTMOB;     // Save the MOb interrupt flags state. - First operation
CANSTMOB = 0;             // Immediately clear the MOb interrupt flags. - Second operation
    // Test for unexpectedly disabled MOb here.
    // The MOb CANCDMOB.CONMOBn MOb command bits are not set to disable the MOb...
    // The MOb CANEN busy bit is cleared...
    // The CANGCON.ABRQ bit is not set...
    // The CANGCON.ENASTB is still set...
        // If all these tests are true, use the CANCDMOB.CONMOBn MOb command bits
        // to determine if a TXOK or RXOK was lost and correct isr_flags. This does
        // not work if the CANCDMOB.RPLV bit was set. If you want to recover the
        // CANSTMOB.DLCW bit, you will need a saved copy of the original CANCDMOB.DLC
        // value. If the CANGCON.ABRQ is set outside the interrupt code, make sure
        // all MOb CANCDMOB.CONMOBn MOb command bits are set to disable before clearing
        // the CANGCON.ABRQ bit (disable AVR interrupts during the ABORT).
        // This way a CAN IT interrupt response after the ABRQ event will
        // not accidentally cause a false unexpected disable detection here.

        // If CANGCON.TTC is set do not make any TXOK corrections.

If isr_flags has any error bits set and the MOb is disabled (CANENn bit n is cleared) for no known reason, indicates a RXOK or TXOK flag was wiped out. Quickly responding to and clearing CANSTMOB errors reduces this rare bug risk. When CANGIE.ENIT is set, quick response requires correctly implemented AVR interrupts. Any AVR interrupts that are very slow to execute could prevent a quick response. For example: a typical beginner mistake of putting USART output debug code in an interrupt response may easily cause very significant response delays (this type of slow USART debug code in an ISR typically breaks the program and creates bugs all by itself).

When in TTC mode a Tx will not have any automatic retries and it will disable itself when it gets any Tx error. This TTC mode Tx behavior mimics the non-TTC mode TXOK flag write CANSTMOB conflict problem, so this conflict correction does not work for Tx in TTC mode.

In order for this rare bug to happen the sequence timing is: after the CANSTMOB read with only error flag bits set (first operation), the CAN hardware sets a TXOK, RXOK or DLCW in CANSTMOB and then the following software CANSTMOB=0 (second operation) wipes out these new TXOK, RXOK or DLCW bits without ever knowing they were just set. This is why the CANSTMOB read must be immediately followed by the CANSTMOB=0. This immediate paring minimizes the window of opportunity for this bug to occur. Since an entire error free CAN frame is required for TXOK or RXOK to be set after the last error CAN frame, this bug requires a significant delay in processing the TXOK or RXOK event after an error. This is why rapid responses to any CANSTMOB error flags is the first/best defense for preventing this bug. This bug is rare because of the complex trigger conditions and extremely tight timing it needs to occur, but rare does not mean impossible and in this case rare means not reproducible if you are trying to debug it!

Edit: 9-28-2012 added new TTC information.

Last Edited: Sat. Sep 29, 2012 - 01:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PDF versions would be nice :) so we can stash the info on our HDDs easily....as long as the MOB doesn't get heavy handed. It CAN happen if you CON MOB.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a heads up for users of the ATmega CAN chips that now have an improved Watch Dog Timer (WDT). This WDT has new initialization requirements:

ATmega CAN data sheet wrote:
Note: If the Watchdog is accidentally enabled, for example by a runaway pointer or brown-out condition, the device will be reset and the Watchdog Timer will stay enabled. If the code is not set up to handle the Watchdog, this might lead to an eternal loop of time-out resets. To avoid this situation, the application software should always clear the Watchdog System Reset Flag (WDRF) and the WDE control bit in the initialization routine, even if the Watchdog is not in use.
When using WinAVR this may be handled by this code (from the on-line manual-see below):
    #include 
    #include 

    uint8_t mcusr_mirror __attribute__ ((section (".noinit")));

    void get_mcusr(void) \
      __attribute__((naked)) \
      __attribute__((section(".init3")));
    void get_mcusr(void)
    {
      mcusr_mirror = MCUSR;
      MCUSR = 0;
      wdt_disable();
    }

See the WinAVR/GCC documentation on the watchdog:
http://www.nongnu.org/avr-libc/u...
I copied the above code because web links are not always forever. However, the latest documentation should always be consulted.

The CodeVisionAVR C compiler (CVAVR) automatically performs this required WDT initialization in the start up code after an AVR reset.

Imagecraft does not handle this required initialization automatically:

Imagecraft ICCV8 support wrote:
You should be able to disable *[the WDT] in your main() routine - unless there is a lot of initialized data (which the startup code copies from ROM to RAM), from reset to main() should not take too many cycles (i.e. if there is no initialized global, then it should just be a dozen cycles.

If you have a lot of initialized data, then you can always modify the startup code to add the disable sequence at the beginning. See the Help file on Startup FIle for details.

*[edit] - I added [the WDT] for clarity.

Other embedded C compilers will have their own unique methods of dealing with this new WDT requirement, so the WinAVR, CVAVR and Imagecraft methods are only examples. I do not have examples for other compilers (anyone care to contribute?). This will also work on the AT90CAN family chips, but is not required by the data sheet.

*edit: added CVAVR information 6-29-2012. Thanks to Pavel Haiduc at HP InfoTech. Added Imagecraft information 7-6-2012. Thanks to Richard at Imagecraft.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I still get questions on the order of CANMSG bytes. Each MOb has 8 CANMSG bytes and the MOb number is selected by writing the CANPAGE register MOBNB3, MOBNB2, MOBNB1 and MOBNB0 bits. Then CANPAGE register INDX2, INDX1 and INDX0 bits point at the MOb CANMSG byte to be read or written for the selected MOb. The CANPAGE.AINC=0 bit will enable automatic increment of the INDXn 3 bit value after CANMSG is read or written, or CANPAGE.AINC=1 bit will disable the automatic increment.

Read the CAN data bytes for a Rx MOb example C code:

CANPAGE = (4 << MOBNB0);  // MOb 4, AINC=0 enabled, first CANMSG byte
  can_data0 = CANMSG;    // MOb 4, first CANMSG byte 0, INDXn=0 then INDXn=1 after
  can_data1 = CANMSG;    // MOb 4, second CANMSG byte 1, INDXn=1 then INDXn=2 after
  can_data2 = CANMSG;    // MOb 4, third CANMSG byte 2, INDXn=2 then INDXn=3 after
  can_data3 = CANMSG;    // MOb 4, forth CANMSG byte 3, INDXn=3 then INDXn=4 after
  can_data4 = CANMSG;    // MOb 4, fifth CANMSG byte 4, INDXn=4 then INDXn=5 after
  can_data5 = CANMSG;    // MOb 4, sixth CANMSG byte 5, INDXn=5 then INDXn=6 after
  can_data6 = CANMSG;    // MOb 4, seventh CANMSG byte 6, INDXn=6 then INDXn=7 after
  can_data7 = CANMSG;    // MOb 4, eighth CANMSG byte 7, INDXn=7 then INDXn=0 after

The first CAN data byte sent on the CAN bus serial data stream will always be received by MOb4 Rx as can_data0 and so on. The Rx MOb will update CANCDMOB.DLCn with the actual number of CAN data bytes received after the CANSTMOB.RXOK bit is set. The CANCDMOB.DLCn value you set when the Rx MOb was initialized is only the number of CANMSG bytes expected and the CANSTMOB.DLCW bit will be set if the updated DLC value is different from the expected DLC value (notice the updated DLC value overwrites the original expected DLC you set and your old expected DLC value is lost).

Write the CAN data bytes for a Tx MOb example C code:

CANPAGE = (2 << MOBNB0);  // MOb 2, AINC=0 enabled, first CANMSG byte
  CANMSG = can_data0;    // MOb 2, first CANMSG byte 0, INDXn=0 then INDXn=1 after
  CANMSG = can_data1;    // MOb 2, second CANMSG byte 1, INDXn=1 then INDXn=2 after
  CANMSG = can_data2;    // MOb 2, third CANMSG byte 2, INDXn=2 then INDXn=3 after
  CANMSG = can_data3;    // MOb 2, forth CANMSG byte 3, INDXn=3 then INDXn=4 after
  CANMSG = can_data4;    // MOb 2, fifth CANMSG byte 4, INDXn=4 then INDXn=5 after
  CANMSG = can_data5;    // MOb 2, sixth CANMSG byte 5, INDXn=5 then INDXn=6 after
  CANMSG = can_data6;    // MOb 2, seventh CANMSG byte 6, INDXn=6 then INDXn=7 after
  CANMSG = can_data7;    // MOb 2, eighth CANMSG byte 7, INDXn=7 then INDXn=0 after

The first CAN data byte sent on the CAN bus serial data stream by MOb2 Tx will always be can_data0 and so on. The Tx MOb will automatically send CANCDMOB.DLCn number of CAN data bytes starting with can_data0. If you fail to write any valid data to any CANMSG bytes sent by the Tx MOb, the CAN hardware will send whatever garbage values happen to be in them.

Other examples:

CANPAGE = (2 << MOBNB0) | 0x05;  // MOb 2, AINC=0 enabled, sixth CANMSG byte
  CANMSG = can_data5;    // MOb 2, sixth CANMSG byte 5, INDXn=5 then INDXn=6 after
  CANMSG = can_data6;    // MOb 2, seventh CANMSG byte 6, INDXn=6 then INDXn=7 after
  CANMSG = can_data7;    // MOb 2, eighth CANMSG byte 7, INDXn=7 then INDXn=0 after
  CANMSG = can_data0;    // MOb 2, first CANMSG byte 0, INDXn=0 then INDXn=1 after
  CANMSG = can_data1;    // MOb 2, second CANMSG byte 1, INDXn=1 then INDXn=2 after
  CANMSG = can_data2;    // MOb 2, third CANMSG byte 2, INDXn=2 then INDXn=3 after
  CANMSG = can_data3;    // MOb 2, forth CANMSG byte 3, INDXn=3 then INDXn=4 after
  CANMSG = can_data4;    // MOb 2, fifth CANMSG byte 4, INDXn=4 then INDXn=5 after
  // The actual MOb 2 Tx on the CAN bus will start with the can_data0 byte.

CANPAGE = (4 << MOBNB0) | (1 << AINC) | 0x01;  // MOb 4, AINC=1 disabled, second CANMSG byte
  can_data1 = CANMSG;    // MOb 4, second CANMSG byte 1, INDXn=1 then INDXn=1 after
  can_data1 = CANMSG;    // MOb 4, second CANMSG byte 1, INDXn=1 then INDXn=1 after
CANPAGE = (4 << MOBNB0) | (1 << AINC) | 0x04;  // MOb 4, AINC=1 disabled, fifth CANMSG byte
  can_data4 = CANMSG;    // MOb 4, fifth CANMSG byte 4, INDXn=4 then INDXn=4 after

If CANPAGE.AINC=1 and the automatic increment is disabled, then CANPAGE must be written with new INDXn bit values to access any different CANMSG byte to be read or written.

Notice that INDXn=7 will auto-increment and overflow back to INDXn=0. If you read or write CANMSG more than 8 times this INDXn value overflow and will start over again with CANMSG bytes that have already been read or written. Beware, when AINC=0 (enabled) these:

unsigned char value;
  CANMSG |= value;        // This is the same as CANMSG = CANMSG | value;
-or-
  CANMSG &= value;        // This is the same as CANMSG = CANMSG & value;
-or-
  CANMSG ^= value;        // This is the same as CANMSG = CANMSG ^ value;
-or-
  CANMSG %= value;        // This is the same as CANMSG = CANMSG % value;
-or-
  CANMSG <<= value;       // This is the same as CANMSG = CANMSG << value;
-or-
  CANMSG >>= value;       // This is the same as CANMSG = CANMSG >> value;
-or-
  CANMSG += value;        // This is the same as CANMSG = CANMSG + value;
-or-
  CANMSG -= value;        // This is the same as CANMSG = CANMSG - value;
-or-
  CANMSG *= value;        // This is the same as CANMSG = CANMSG * value;
-or-
  CANMSG /= value;        // This is the same as CANMSG = CANMSG / value;

will read then write CANMSG, causing a double AINC enabled increment of the CANPAGE.INDXn bit pointer value. These types of C value assignment operations obviously do not work when CANPAGE.AINC=0, so CANPAGE.AINC=1 (disabled) must be set to use these on CANMSG.

Keep in mind the CAN bus hardware will only allow 8 CAN data bytes maximum, but the CANCDMOB register DLC3, DLC2, DLC1 and DLC0 bits are a 4 bit long value that may be from 0x0F to 0x00. A CANCDMOB.DLCn value of zero is allowed and there will not be any CANMSG data for that MOb. However, CANCDMOB.DLCn values from 0x0F to 0x09 are technically the same as a value of 0x08 to the CAN hardware. Your software should never send any CANCDMOB.DLCn value larger than 0x08, however you may receive (Rx) a CANCDMOB.DLCn value larger than 8 even though there will never be more than 8 CAN data bytes. Your software must limit all Rx CANCDMOB.DLCn values to 0x08 maximum. The result of ignoring this is typically Rx CAN data bytes are stored in a memory array of 8 bytes, then a CANCDMOB.DLCn value larger then 0x08 that is not limited will cause your software to overflow the memory array and crash your program. If you make your software behave like the CAN hardware and always limit the DLC to 8 maximum you will not experience this type of crash.

Example code to limit DLC:

#define BF_MOB_DLC   (CANCDMOB & ((1 << DLC3) | (1 << DLC2) | (1 << DLC1) | (1 << DLC0)))
#define MOB_MAX_DLC  ((1 << DLC3) | (0 << DLC2) | (0 << DLC1) | (0 << DLC0))

#define MOB_DLC_LIMIT(dlc) (((dlc) > MOB_MAX_DLC) ? MOB_MAX_DLC : (dlc))

    // Set CANPAGE to your Rx MOb number first
    // After the CANSTMOB.RXOK bit is set (the CAN Rx completed)
    actual_rx_dlc = MOB_DLC_LIMIT(BF_MOB_DLC);
Last Edited: Thu. Sep 6, 2012 - 05:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't know if it's just me, but I'm finding this really hard to read.
Like a big wall of text.

Don't take it the wrong way, this looks like a very thorough and in depth tutorial and looks like you've put a lot of effort in to it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I agree, it is like a big wall of text. Sorry, my graphics department is out on strike :wink:.

I'm working on a PDF that breaks it up into lots of very small walls of text :(. It gets complex, yet once you get through it the CAN hardware does all the protocol work for you making it easy to actually use.

I also plan on providing a simple direct example of a working program. It is just there are so may different ways to manage the CAN hardware (it is a very flexible and powerful interface design) that its use would be limited by the design tradeoffs I choose for the example.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is a new CAN FD (Flexible Data rate) specification that has limited compatibility with the current ATMEL CAN 2.0 specification CAN nodes. CAN FD is able to accelerate the CAN data byte transfer rate above the old CAN limit of 1 mbps and it is capable of transferring up to 64 bytes in a single CAN FD Data Frame (CAN 2.0 is limited to 8 data bytes maximum). This limited CAN 2.0 and CAN FD compatibility depends on implementing ISO 11898-1 on your CAN 2.0 network, keeping all CAN 2.0 nodes in standby during CAN FD accelerated data Tx and using the CAN 2.0 reserved bits correctly (always a dominant zero value).

In CAN FD the acceleration Data-Phase is limited to a factor of about 5 (this is 5x the old CAN 1 mbps maximum baud rate). The actual data acceleration depends on several factors.

Since CAN FD requires new CAN controller hardware, which ATMEL does not currently have, the point of this post is:

1) to point out the ATMEL CAN 2.0 CANIDT.RB0TAG and CANIDT.RB1TAG reserved bits must always be dominant zero values, as per the ATMEL data sheet.

2) to point out CAN FD compatibility requires using the ISO 11898-1 specification in your CAN 2.0 network.

So, if you plan on ever using CAN FD with an existing CAN 2.0 specification keep all of this in mind when you build your ATMEL CAN 2.0 specification CAN network. In addition a mixed CAN 2.0 w/ CAN FD will require a method for keeping the CAN 2.0 nodes in standby during CAN FD accelerated data Tx. Since this standby mechanism must work in CAN 2.0, which CAN FD will also do, you might build this capability into your CAN 2.0 design if you anticipate future CAN FD upgrades added to your CAN 2.0 network. Of course an all CAN FD node network does not require keeping any CAN FD nodes in standby.

BOSCH CAN Specification 2.0:
http://www.semiconductors.bosch....

BOSCH CAN with Flexible Data-Rate Specification 1.0:
http://www.bosch-semiconductors....

BOSCH CAN with Flexible Data-Rate White Paper:
http://www.semiconductors.bosch....

BOSCH CAN with Flexible Data-Rate 1.1 White Paper:
http://www.bosch-semiconductors....

CiA Using CAN with flexible data-rate in CANopen systems:
http://www.can-cia.org/fileadmin...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CAN physical layer discussion. The CAN physical layer in all current AVR chips with CAN controllers are implemented using external circuitry. It is possible to implement a simple single wire CAN bus using discrete components or an open collector buffer with pull up resistors. However, this is usually taken care of with an external CAN transceiver chip using a differential wired CAN bus. Typical CAN bus 5 volt external CAN transceiver chip part numbers are:

Quote:
ATA6600, B10011S, ISO1050, MAX3050, MAX3057, MCP2551, PCA82C250, SN65HVD230, SN65HVD231, SN65HVD232, SN65HVD251, SN65HVD1040, SN65HVD1050, TJA1040, TJA1041, TJA1042, TJA1043, TJA1048, TJA1050, TJA1051, TJA1054, TJA1055 or TLE6250.
Typical CAN bus 3.3 volt only external CAN transceiver chip part numbers are:
Quote:
SN65HVD230, SN65HVD231 and SN65HVD232.
Typical 3.3 volt CAN controller to 5 volt CAN bus level convertery external CAN transceiver chip part numbers are:
Quote:
ISO1050, TJA1041T, TJA1042T/3, TJA1048T, TJA1055T/3 and TLE6250 V33.
External CAN bus transceiver chips conform to differential two wire copper physical standards like:
Quote:
SAE-J1939, NMEA-2000, ISO-1050, ISO-11783, ISO-11898, etc.
You may ask why is the physical CAN bus layer interface not in the same chip with the CAN controller? The answer is with all the different CAN bus standards, the CAN controller chip manufacturers would have make almost endless variations of CAN controller chips with internal transceiver circuits for each different standard. It could also be troublesome if your particular variant of integrated controller/transceiver was no carried or not in stock with your suppliers. Then what happens if you want to make a fiber optic CAN bus without any wiring? It turns out making a CAN controller without any physical layer interface is necessary anyway. There is at least one company making an ARM CAN controller with a one particular type of built in transceiver circuit, but they still make the normal ARM CAN controller chip without the internal transceiver circuit.

Having separate controller/transceiver chips gives the CAN bus designer the freedom to choose a desired CAN bus interface specification for any AVR CAN controller chip.

Yes it matters if your CAN controller chip runs on 3.3 volts and your CAN bus is based on a 5 volt physical CAN bus specification. Depending on which CAN bus standard you are using, your combination of controller and transceiver must be compatible. If you are doing high speed 1 mbps CAN with a 3.3 volt controller and a 5 volt CAN bus, then use one of the CAN transceiver chips with the built in level converter. At 1 mbps the propagation delay on the CAN signal path is critical and the chips with built in level converters have been tested to comply with whatever maximum CAN bus speed standard they are documented to support. If you make your own custom level converters for high speed CAN then it is up to you to ensure the extra propagation delay your custom circuit adds does not prevent the CAN transceiver chip from performing to its specified high speed standard. If you have a 3.3 volt controller and a 3.3 volt CAN bus there are a few chips that do this too.

Each CAN node CAN controller chip (AT90CANxxx, ATmegaxxC1 or ATmegaxxM1) must have an external circuit for the CAN bus physical layer interface. They work in controller/transceiver pairs for each CAN node.

Some chips may support special options. Take a look at the data sheet for an ATMEL ATA6600. Then compare it to a MAXIM MAX13041. There is a huge difference in complexity and features. In general use the simplest CAN transceiver chip that does the job you designed your physical CAN bus layer to do.

Any CAN bus wiring carrying CAN signals is an actual transmission line. If you want to understand what is happening in real time with CAN bus signals then you need to understand transmission lines. This also explains the need for termination at each CAN bus end point. If you use an oscilloscope to look at the CAN bus signal remember the scope grounding is critical. For example a very long ground lead on a scope probe will cause distortion (usually ringing) in the scope display that is really not there when the probe is not connected. You will also see the CAN bus is NRZ format and there is CAN bus bit stuffing that is only visible on the actual bus using a test instrument (CAN bus bit stuffing/de-stuffing is automatic and is hidden from the software interface).

Most CAN bus specifications are intended for 120 ohm termination and 120 ohm impedance CAN bus wiring. The 120 ohm termination must be present at each end of the CAN bus. There are different ways of doing this with split resistors and there is an exotic variation that uses weak termination on each CAN node. Split termination is a technique to reduce radiated noise from the CAN bus. Some CAN bus designs with transceiver chip SPLIT pins take this reduced noise a step farther when CAN nodes are allowed to be in standby or unpowered.

Some CAN bus designs use external discrete common mode chokes and other components to reduce radiated noise. If used these require extra design effort and engineering. If not done correctly the coils EMF spikes could endanger your entire CAN bus. Also anything that causes CAN bus signal distortion may cause CAN bus errors and make your CAN bus unusable (again more design thought/effort).

Allot of CAN transceiver chips have a RS or slope control input pin (see the chip data sheet). This is used to limit radiated noise from the CAN bus wiring. However, when enabled it does cause some distortion in the CAN bus signal. So, typically this is more useful for CAN bus speeds around 125 kbps or slower. You may push higher CAN bus speeds with very short CAN bus lengths and still use slope control. Anyway you do it, it always requires you engineer your CAN bus to work as required however you choose to build your actual CAN bus.

There are maximum CAN bus lengths determined by the signal propagation delay and CAN baud rate. High speed CAN 1 mbps is 40 meters maximum and you may not even be able to get this. A 500 kbps theoretical maximum length is 100 meters, but you will have a very hard time finding any CAN bus transceiver chip specified to drive physical CAN bus wiring longer than 80 meters total.

Please when developing your own CAN driver software, for your own sanity, separate the physical CAN bus design from the driver software effort. If possible only use a short CAN bus length (about 1 meter or less), typically a standard 120 ohm termination at each CAN bus end, put the transceiver chip in high speed mode (disable the RS slope control if you have one), use a slower CAN bus baud rate (125 kbps or lower) and ensure a good signal ground between your CAN nodes (you always need at least two CAN nodes minimum to do anything with CAN). This configuration will give you the best results for testing your CAN driver software. Do the best you are able to do. For example in some cases you will not be able to change the baud rate on some CAN nodes and therefore you must use their CAN baud, etc.

After you have known stable working CAN driver software, then take on the additional CAN bus requirements like high speeds, maximum CAN bus length, slope control, split termination, SPLIT pin support, common mode chokes, ground voltage offsets between CAN nodes, and so on. If you do software and also push difficult physical CAN bus designs all at the same time, you will most likely end up chasing what you think is a driver software problem when you really have physical implementation CAN bus problems or the other way around.

I will add some links later.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mike,

I'm concerned about the total CAN interrupt execution causing issues and possibly losing messages as you've referenced in prior posts.

 

We are using 11 bit addresses in our system using the AT90CAN128 processor at 57600 baud with ~100 nodes traveling up to 1000ft.

 

My previous build had a "SPY" mob (per the Atmel errata) for the receive MOB so we stopped loosing the RX data chunks and

1 transmit MOB for a total of 3 MOB's used. This build is working quite well at this time with few issues.

 

This new build will have 2 different functions/ID's running, each with a Receive MOB, transmit MOB and receive "SPY" Mob for a total of 6 MOB's.

 

The question was brought up if it would benefit us to have more than 1 MOB receiving for each function/ID address with the "SPY" MOB?

 

Thank you for all your help in the forums here as your comments have been VERY helpful to usgetting our

applications running smoothly in a short time.

 

Also on a related note are you the Mike B that wrote the draft of "CAN on the AVR"?

 

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Deleting above.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly