Search |
 |
|
 |
| Author |
Message |
|
|
Posted: Feb 26, 2012 - 09:26 PM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
I Have purchased the AVR-CAN development board made by Olimex. I am sending CAN messages with use of the USB-to-CAN Compact from Ixxat. Even with flashing demo code onto the board, there seems to be no communication between both nodeds (ie the warning lights indicate that the transmission is not being received by the AVR-CAN board. Are there maybe some jumper settings that are not referred to in the olimex data sheet? I do infact have 120 ohm termination resistors in use, as well as equal baud rates on both nodes. Perhaps someone has had a similar problem with this hardware? If anyone could shed some light on the situation it would be greatly appreciated
-kev |
|
|
| |
|
|
|
|
|
Posted: Feb 26, 2012 - 11:17 PM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
|
khayes22 wrote:
Even with flashing demo code onto the board...
I take it this demo code is not the Olimex AVR-CAN Blinking LED demo code. Since Olimex does not provide actual CAN hardware demo code for this board, are you sure you have a good AVR AT90CAN128 based CAN demo program? The software must configure and enable the AVR CAN hardware before it will receive any CAN traffic at all. If the AVR CAN is not receiving, another Tx CAN node will never get any acknowledge back and therefore correctly indicate its Tx is not being received.
I take it your warning lights are on the Ixxat??
Are you able to run a simple test program like the LED blink code on the AVR-CAN to see if the Olimex board works at all?
Are you using the CAN DB-9 connector and not using the RS-232 connector instead ? I know, its a silly question, but I had to ask anyway . Are you certain you have the correct DB-9 pin out for your CAN cable connections? The Olimex 120 ohm termination is factory enabled on mine, make sure this is the termination you are using for this board and not paralleling it with another built-in CAN cable connector terminator (some CAN cables have CAN bus resistor termination built into the cable assembly that do not use on-board termination resistors).
Is there a good ground between your CAN nodes? Is the CAN bus wiring polarity correct. Use a short cable for initial testing.
I have an AVR-CAN board where the on board regulator was putting out over 6 volts, check yours with a volt meter. According to AVRStudio, the same AVR-CAN board came with the AVR TA0SEL (Reserved for factory tests) fuse programmed, check all of your AVR fuse settings and unprogram TA0SEL if it is programmed. |
|
|
| |
|
|
|
|
|
Posted: Feb 27, 2012 - 01:31 AM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
Mr. Mike B,
The demo code I am referring to is that of the "CAN bus Driver for AT90CAN128 under FreeRTOS with AVRGCC". I was initially wanting to make sure I would atleast get a response from any transmission.
Yes the warning lights are on the Ixxat side.
The LED blink program, as well as the push button program work correctly on my board.
The CAN connector is purchased along with the USB to CAN Compact device from ixxat and is made for CAN connection. I did infact have a 120 ohm termination resistor plugged in on the AVR-CAN node. I have removed it.
I have now unprogrammed TAOSEL.
As far as the grounding issue, is there a good way to create a ground other than plugging in the CAN connector securely? The can bus is of a pretty short y-splitter cable.
Is the demo code I reffered to reliable?(assuming you are aware of this program) |
|
|
| |
|
|
|
|
|
Posted: Feb 27, 2012 - 05:47 AM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
Sorry, I do not know that demo code.
I would double check the manufactured CAN cable pin out against the Olimex connector pin out. Your cable may already have a ground wire in your cable? Sometimes the CAN cable ground is not actually grounded to the CAN node in the PCB traces. A hand held meter can measure any ground offset voltage between the CAN nodes. If possible, slower CAN baud rates are less demanding on the cabling for testing.
Sorry, it has never been compiled (I hope there are no coding errors) and is missing things that depend on your C compiler and baud rate, but I just created a simple small CAN program that should make your AVR-CAN board Rx any/all CAN traffic.
Code:
// Your includes from your C compiler library go here
//*******************************************************
#define AT90CAN_MOBS 15
#define MOB_DIS_CMD ((0 << CONMOB1) | (0 << CONMOB0))
#define MOB_RX_CMD ((1 << CONMOB1) | (0 << CONMOB0))
#define MOB_TX_CMD ((0 << CONMOB1) | (1 << CONMOB0))
#define MOB_IDE_11F (0 << IDE)
#define MOB_IDE_29F (1 << IDE)
#define MOB_DLC_FIELD ((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))
//*******************************************************
//
// Simple CAN setup. CANGIE and CANIE2 are not actually used by this code.
//
void can_init (void)
{
unsigned char mob; // Temporary MOb register set selection number value.
CANGCON = (1 << SWRES); // Reset the CAN controller hardware and general CAN registers.
// All MObs must be initialized because MObs have no reset initial value.
for (mob = 0; mob < AT90CAN_MOBS; mob++) {
CANPAGE = (mob << MOBNB0); // Set the MOb page number for each MOb 0 to 14 (15 MObs total).
CANCDMOB = MOB_DIS_CMD; // Set each MOb configuration to disabled *CRITICAL*.
CANSTMOB = 0; // Clear all the MOb interrupt/polling flags *CRITICAL*.
}
//****
// This is a randomly selected CAN Baud setting, you need to put your real values based on CLKio here.
// See the CAN baud examples and the Baud Rate Prescaler errata in the ATMEL data sheet.
//****
CANBT1 = 0x12; // Timing - Baud Rate Prescaler.
CANBT2 = 0x0C; // Timing - Re-Synchronization Jump Width and Propagation.
CANBT3 = 0x37; // Timing - Phase Segment 2, Phase Segment 1 and Sample Point.
CANGIE = (1 << ENRX); // Enable polling for CANSTMOB.RXOK flags.
CANIE2 = (1 << IEMOB0); // Enable MOb 0 RXOK for polling.
CANGCON = (1 << ENASTB); // Enable the CAN.
}
//*******************************************************
//
// Setup to Rx all CAN traffic. This means all 11/29 bit formats, all Remote/Data frames and all IDs.
//
void rx_mob_0_setup (void)
{
CANPAGE = (0 << MOBNB0); // Select the dedicated Rx MOB 0.
// Set any ID and RTRTAG does not matter because CANIDM4.RTRMSK is cleared.
CANIDT1 = 0;
CANIDT2 = 0;
CANIDT3 = 0;
CANIDT4 = 0;
// Set the mask to allow/accept all CAN IDs, Remote/Data frame, or 11/29 ID bit format.
CANIDM1 = 0;
CANIDM2 = 0;
CANIDM3 = 0;
CANIDM4 = (0 << IDEMSK) | (0 << RTRMSK);
// Send the Rx command to the CAN hardware. The CANIDM4.IDEMSK may change the IDE bit later.
CANCDMOB = MOB_RX_CMD | MOB_IDE_29F | 8;
}
//*******************************************************
//
// This is crude brute force polling with no interrupts, to Rx all CAN traffic for debugging.
// Do not take too long with the debug/display or you may miss new CAN traffic.
//
main ()
{
unsigned char rx_bytes_len; // Number of Rx CANMSG bytes.
unsigned char can_bytes[MOB_MAX_DLC]; // Rx CANMSG bytes storage.
unsigned char flags = 0; // CANSTMOB flag accumulated results.
unsigned char i;
rx_mob_0_setup (); // Setup MOb 0 for Rx everything.
while (1) {
CANPAGE = (0 << MOBNB0); // Select the dedicated Rx MOB 0 and reset the INDXn pointer.
if (CANSTMOB) { // Are any flags set?
flags |= CANSTMOB; // Accumulate all the flag results from CANSTMOB.
CANSTMOB = 0; // Clear the new CANSTMOB flags.
// If you never get any RXOK, look at the flags variable for error bits and CANREC/CANTEC.
}
// After the RXOK MOb disable, allow for some debug/display and re-enable the Rx MOb.
if (flags & (1 << RXOK)) {
// The MOb registers have the actual Rx 11/29 bit format in CANCDMOB.IDE, the actual
// Rx ID in CANIDT.IDTn bits, the actual Remote/Data frame type in CANIDT4.RTRTAG and
// the actual Rx Data Length Code in CANCDMOB.DLCn bits.
rx_bytes_len = MOB_DLC_LIMIT(CANCDMOB & MOB_DLC_FIELD);
if (CANIDT4 & (1 << RTRTAG)) { // If this is a Remote frame with no CANMSG bytes...
rx_bytes_len = 0; // ...then skip the CANMSG debug/display.
}
for (1 = 0; i < rx_bytes_len; i++) {
can_bytes[i] = CANMSG;
// You could just directly display these if you want to.
// Reading CANMSG bytes changes the CANPAGE.INDXn pointer value, which is reset above.
}
// The flags variable has a record of all polled CAN error bits since this MOb 0 was
// enabled. You may look at these bit values for additional debug/display.
// Debug/display the CANREC and CANTEC values also.
flags = 0; // Clear the CANSTMOB flags accumulator for the next Rx cycle.
// Re-enable Rx MOb 0 for the next cycle.
CANCDMOB = MOB_RX_CMD | MOB_IDE_29F | 8;
}
}
}
I hope I didn't forget anything or mess up just typing this off the top of my head. This should Rx all your Ixxat CAN traffic without the RTOS complexity. It gives you a framework to add debugging output or using JTAGICE breakpoints for initial testing. Even without any display, it should make the Ixxat error LED go out if everything else is good. |
|
|
| |
|
|
|
|
|
Posted: Feb 27, 2012 - 05:50 PM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
Thank you for sharing Mr. Mike B,
Because I have a 8Mhz clock I set:
CANBT1 = 0x06 //creating 100kb/s
CANBT2 = 0x0c
CANBT3 = 0x5a
Because my errors are still present, it must be a hardware problem. I have already ordered another board because I fried this one by trying to amplify a PWM output. Perhaps this has a part in my communication errors.
Just to clarify a few things about my components.
Programming: AVR studio 4 compiled with WINavr.
JTAG ICE programming cable
Hardware: USB-to-CAN Compact
(1) 120 ohm termination resistor on the
USB to CAN Compact side
AVR-CAN board connected via CAN cable
Is that enough to successfully create the bus? |
|
|
| |
|
|
|
|
|
Posted: Feb 27, 2012 - 06:29 PM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
Check your CKDIV8 fuse. If this is set you will start with the AVR clock divided by 8, then you must change the CLKPR register with two writes within a 4 AVR clock cycle time limit - see the data sheet. If CKDIV8 is not programmed then your AVR clock is not divided.
khayes22 wrote:
Because I have a 8Mhz clock I set:
I thought the AVR-CAN came with a 16 MHz crystal standard. Although I think there was some mention of custom clock crystal frequencies through special order. Double check your oscillator frequency. If you have the standard 16 MHz AVR-CAN crystal with CKDIV8 set your frequency is actually 2 MHz. If you want 8 MHz you need to use CLKPR to divide the crystal oscillator frequency. If you have a frequency counter you may program the CKOUT fuse and measure the AVR clock frequency at pin 42 PC7/CLKO with your counter. You could also write code to use a timer to blink the LED at a slow calculated rate like 1 second, then measure the blink time. Any gross clock error like 8 MHz instead of 16 MHz will be easy to confirm.
If you are changing the AVR clock source fuses and trying to use the internal RC 8 MHz oscillator, then your CAN node will never work. The internal RC is not stable enough for CAN use and does not come close to the Bosch specification. The RC alone will screw up your CAN baud no matter what you set the baud to. My AVR-CAN came with the AVR fuses already set correctly for the 16 MHz crystal operation, so I did not think anyone might change it back to the useless for CAN internal RC setting.
Get your AVR actual clock frequency sorted out and try your AVR-CAN again. Maybe the CAN part is still good? |
|
|
| |
|
|
|
|
|
Posted: Mar 01, 2012 - 10:42 PM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
Well thank you for your help on receiving messages Mr. Mike B. I was finally able to get rid of my error messages after getting my timing just right. But now I am having some confusion on using the CAN data message register (CANMSG). I want to receive a message from the address 1000 (decimal value) and if the message is equal to all twos, I want to emit a PWM signal. I'm going to attatch the code I have developed so far that isn't working exactly how I want it to
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/sleep.h>
#include <avr/iocan128.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
volatile uint8_t data[8];
volatile uint8_t read =0;
void PWM_Init (void)
{
// COM set, fast PWM, 1024 prescaler
TCCR1A = ((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10));
TCCR1B = ((1<<WGM13) | (1<<WGM12) | (1<<CS12) | (0<<CS11) | (1<<CS10));
// Set PWM value
OCR1A = 0x8;
OCR1B = 0x4;
/* Enable timer 1 comp interrupt. */
TIMSK1 = (1<<OCIE1A)|(1<<OCIE1B);
// Reset timer
TCNT1 = 0;
}
void CAN_INIT(void){
cli();
CANGCON = (1 << SWRES); // Reset the entire CAN controller.
CANGIE = 0b10101010 ; // Enable all interrupts; Enable receive interrupts; Enable MOb Errors Interrupt; Enable General Errors Interrupt
CANIE2 = 0b00000010 ; // MOb1 Interrupt Enabled
CANIE1 = 0x00 ;// All other MObs disabled
CANGIT = CANGIT; // Clear all the active general interrupt flags.
// Initialization of Message Object
int k;
for (k=0;k<15;k++)
{
CANPAGE = k << 4;
CANCDMOB = 0x00;
CANSTMOB = 0x00;
}
// baud rate set at 125kbaud assuming 16Mhz clock
CANBT1 = 0x0e ;
CANBT2 = 0x0c ;
CANBT3 = 0x37 ;
CANTCON = 0x00 ; // CAN Timer Clock Period set to lowest value
CANGCON = 0b00000010 ; // Software Reset Request
// Initialization of Message Object Zero
CANPAGE = 0b00010000; // selection of the MOb number 0
CANIDT1 = 0b01111101;
CANIDT2 = 0x00;
CANIDT3 = 0x00;
CANIDT4 = 0x00;
CANIDM1 = 0x00;
CANIDM2 = 0x00;
CANIDM3 = 0x00;
CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK); // 11 bit message identifier
CANCDMOB = 0b10001000; //sets MOb for reception; sets dlc to 8
sei(); //global interrupt enable
}
void ReceiveByMOb0(void){
int i;
CANPAGE = 0b00010000; //using MOb0
CANIDT1 = 0b01111101;//ID=1000
CANIDT2 = 0x00;
CANIDT3 = 0x00;
CANIDT4 = 0x00;
CANIDM1 = 0x00;
CANIDM2 = 0x00;
CANIDM3 = 0x00;
CANIDM4 = 0x00;
for(i=0; i<8; i++){
data[i]= CANMSG;
}
if(CANMSG==2222222222222222)
{
DDRB = 0x40; //set PB6 output (OC1B)
PWM_Init ();
SREG = (1<<SREG_I);
}
//CAN standard rev 2.0 A (identifiers length = 11 bits)
// (1 << CONMOB1) | (1 << DLC3)
CANCDMOB = 0b10001000; //enable reception and data length code = 8 bytes
}
int main(void) {
CAN_INIT();
sei(); // enable interrupt globally
while(1){
if(read==1){
read=0;
ReceiveByMOb0( );
}
}
return 1;
}
ISR (TIMER1_COMPA_vect) //interrupt is set test
{
;
} ISR (TIMER1_COMPB_vect) //interrupt is set test
{
;
}
I added my PWM output code into the subroutine for ReceiveByMOb1. If anyone notices a significant flaw with my use of the CANMSG register, please let me know. |
|
|
| |
|
|
|
|
|
Posted: Mar 01, 2012 - 11:56 PM |
|


Joined: Sep 04, 2002
Posts: 21257
Location: Orlando Florida
|
|
| I have an Olimex CAN128. It has a 16MHz xtal. I dug out the Atmel GCC canlib.c and canlib.h from somewhere in the bowels of the Atmel website, and managed to compile it with iccv7avr (main edit was moving variables declared in the middle of a block up to the top of the block). The canmain.c example just receives a pkt then sends its back out with a packet count incremented. Whoopee! I've got the thing reading and sending live on a 500kbit can bus in several flavors of hi end vehicles with electronic suspension controllers. |
_________________ Imagecraft compiler user
|
| |
|
|
|
|
|
Posted: Mar 02, 2012 - 07:39 AM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
| There are lots of problems with your code like you are not using the CAN hardware correctly. But, first I do not understand this:
Code:
if(CANMSG==2222222222222222)
Is this supposed to be a 64 bit value made up of all 8 CANMSG bytes (if so is it decimal or hex)? Is this supposed to be all 8 CANMSG bytes with a value of 22 in each CANMSG byte? Is this a decimal value 22 or is it a hex value 0x22?
I can help you write some code that will use the CAN hardware correctly. It is just I cannot figure how to write any code for your 22 value(s) or whatever they are. |
|
|
| |
|
|
|
|
|
Posted: Mar 02, 2012 - 05:39 PM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
| It is supposed to be a 64 bit value made up of all 8 CANMSG bytes like you said. It is a hexadecimal value as transmitted by my USB-to-CAN Compact. I have some message values assigned for three different message objects I will use for recieving messages from three different addresses. However, first I wanted to see a PWM output when the last message sent was ID:3E8 with a data value of 0x22 22 22 22 22 22 22 22. Sorry I didn't make that more clear in my commenting. |
|
|
| |
|
|
|
|
|
Posted: Mar 02, 2012 - 09:10 PM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
I see you are using WinAVR. This limited untested example source code should Rx your MOb 1 ID 1000 decimal CAN traffic and test the CAN data for all 8 bytes each 0x22 value.
I fixed some things I saw as problems like using gobbledygook bit field values and cleaned things up. When you enable CANGIT.ENIT you must provide the ISR(CANIT_vect) routine or your program will not work. So, I added this in. You did not appear to understand how the CANIDM registers work. This example is not much use beyond its limited MOb 1 Rx capability, but it should help you if you figure out what it does and why it does it. I did not put your includes or PWM code in this example.
Code:
#define MOB_DIS_CMD ((0 << CONMOB1) | (0 << CONMOB0))
#define MOB_RX_CMD ((1 << CONMOB1) | (0 << CONMOB0))
#define MOB_TX_CMD ((0 << CONMOB1) | (1 << CONMOB0))
#define MOB_IDE_FIELD (1 << IDE)
#define MOB_IDE_11F (0 << IDE)
#define MOB_IDE_29F (1 << IDE)
#define MOB_DLC_FIELD ((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))
#define MOB1_RX_8_BYTES 8
volatile uint8_t Can_status;
//*******************************************************
void can_init (void) {
CANGCON = (1 << SWRES); // Reset the entire CAN controller.
Can_status = 0; // Default starting value for each CAN initialization.
// Initialization of Message Object
int k;
for (k=0;k<15;k++)
{
CANPAGE = k << 4;
CANCDMOB = 0x00;
CANSTMOB = 0x00;
}
// baud rate set at 125kbaud assuming 16Mhz clock
CANBT1 = 0x0e ;
CANBT2 = 0x0c ;
CANBT3 = 0x37 ;
// CANTCON was cleared by the SWRES (see the data sheet).
CANGIE = (1 << ENIT) | (1 << ENRX) | (1 << ENERR) | (1 << ENERG);
CANIE2 = (1 << IEMOB1); // MOb1 Interrupt Enabled,
// CANIE1 was cleared by the SWRES (see the data sheet).
// CANGIT was cleared by the SWRES (see the data sheet).
CANGCON = (1 << ENASTB) ; // Enable the CAN.
// Initialization of Message Object One
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Set the ID to 1000 decimal (0x3E8).
CANIDT1 = (uint8_t) (1000 >> 3);
CANIDT2 = (uint8_t) (1000 << 5);
CANIDT3 = 0x00;
CANIDT4 = (0 << RTRTAG); // Set data frame.
// Only allow the single 1000 decimal ID value to Rx.
CANIDM1 = (uint8_t) (0x7FF >> 3); // Set all 11 ID mask bits to force matching CANIDT ID.
CANIDM2 = (uint8_t) (0x7FF << 5);
CANIDM3 = 0x00;
CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK); // Force only Rx data frame 11 bit ID.
// This reads much easier than 0b10001000 gobbledygook.
CANCDMOB = MOB_RX_CMD | MOB_IDE_11F | MOB1_RX_8_BYTES; //sets MOb for reception; sets dlc to 8
}
//*******************************************************
// This processes each CAN CANSTMOB (ENRX and ENERR) and CANGIT (ENERG) interrupt providing
// Can_status for use by other functions to detect Mob 1 CAN activity. This is dedicated to
// only MOb 1. After CANSTMOB.RXOK is set MOb 1 is disabled and all MOb register Rx data is
// ready for use in other functions, up until later when Rx MOb 1 is re-enabled by a CANCDMOB
// command Rx write. No MOb 1 Rx data is extracted in this ISR.
ISR (CANIT_vect) {
uint8_t save_page; // Pre-interrupt CANPAGE value storage.
save_page = CANPAGE; // Save the pre-interrupt CANPAGE value.
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Get possible RXOK flag and concatenate with all previous MOb error flags (ENERR).
Can_status |= CANSTMOB;
// Clear the CANSTMOB interrupt flags.
CANSTMOB = 0;
// Concatenate all the MOb error flags (ENERR) with the general error flags (ENERG).
Can_status |= (CANGIT & ((1 << SERG) | (1 << CERG) | (1 << FERG) | (1 << AERG)));
// Clear the ENERG interrupt flags. This works differently from the CANSTMOB clear.
CANGIT = ((1 << SERG) | (1 << CERG) | (1 << FERG) | (1 << AERG));
CANPAGE = save_page; // Restore the pre-interrupt CANPAGE value.
}
//*******************************************************
// The CAN MOb information is extracted here in main() by polling Can_status. Since MOb 1
// was only setup to Rx ID 1000 decimal data frames, we do not need to extract any ID
// information from the Rx MOb 1 result. I did not use the CANSTMOB.DLCW bit in order to
// make this code example more general purpose.
int main(void) {
uint8_t i;
uint8_t result_22; // CANMSG byte == 0x22 compare result.
uint8_t dlc; // CANMSG byte total count.
can_init();
sei(); // enable interrupt globally
while (1) {
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// If you never get any RXOK, you may look at the Can_status concatenated error flag
// values here. Do not forget about CANREC and CANTEC.
// Check to see if the ISR CANIT finished the MOb 1 Rx.
if (Can_status & (1 << RXOK)) { // Ignore all MOb 1 Rx results until a RXOK is set.
// If you want you may look at the Can_status concatenated error flag values here. Do
// not forget about CANREC and CANTEC.
Can_status = 0; // Clear the last status to start over with a new Rx.
// Any new ENERG errors will set the Can_status error bits before the new Rx is started.
result_22 = 0; // Initial test value default.
// Limit dlc to MOB_MAX_DLC and check for the correct number of Rx bytes.
if ((dlc = MOB_DLC_LIMIT(CANCDMOB & MOB_DLC_FIELD)) == MOB1_RX_8_BYTES) {
// Detect when all the CANMSG bytes all have 0x22 values (result_22 will == 0).
for (i = 0; i < dlc; i++) {
result_22 |= CANMSG ^ 0x22; // A CANMSG byte==0x22 XOR with 0x22 == 0;
}
} else {
result_22 = ~0; // ERROR, not enough CANMSG bytes were received.
}
if (result_22 == 0) { // If all MOB1_RX_8_BYTES were 0x22 values then result_22 == 0.
// Trigger the Rx ID 1000 decimal CAN data == 0x2222222222222222 PWM.
}
// Restart the MOb 1 Rx (the RXOK disabled MOb 1, so we know it is ready again).
CANCDMOB = MOB_RX_CMD | MOB_IDE_11F | MOB1_RX_8_BYTES;
} // End of MOb 1 Rx ID 1000 decimal RXOK processing.
} // End of while(1) loop - no more executable code past this point.
}
*edit: fixed an == typo |
Last edited by Mike B on Mar 03, 2012 - 12:09 AM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Mar 03, 2012 - 12:03 AM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
Might I say, &'ing the Can_status with the rxok flag to begin the if statement is a super creative way to announce to the program that the message data is complete.
Thank you for clearly showing how to access the data of a message. This weekend I will work on setting up a PWM signal in correspondance with the data transmission. I will surely let you know what I come up with. Thank you again for the help |
|
|
| |
|
|
|
|
|
Posted: Mar 03, 2012 - 05:23 PM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
Actually, exporting global flag variables from interrupts is not so much super creative as it is a standard method used to streamline interrupt execution for a very small/efficient interrupt resource usage. Any single inefficient ISR code drags down the entire AVR interrupt resource for any/all other ISR code. There are lots of different ways to implement the CAN driver software. In the CAN hardware this example adds the benefit of using the MOb register storage information directly, outside the ISR code (you do not need to make global SRAM copies of all the MOb information inside the ISR).
Since you only had one single MOb enabled, it allowed combining the MOb CANSTMOB errors and the general CANGIT errors into a single Can_status flag value. When multiple MObs are in use, this strategy is really difficult to implement in a way that makes any sense. The example code was not bullet proofed to handle possible race conditions between when new general error flags are set and Can_status is cleared (it is only simple example code and absolutely catching every possible general error no matter what is not critical - the MOb CANSTMOB errors that are all caught are the important ones). However, there is a CAN hardware operational very tiny possibility vulnerability in clearing CANSTMOB error bits while the MOb is still enabled (the CANEN bit for the MOb is set), that is not a problem for this example code because this ISR always responds very quickly to any CANSTMOB errors. If this vulnerability makes you uncomfortable (like a larger/bad program messes up the AVR interrupt resource availability), either do not set CANGIE.ENERR or learn how to detect and correct this very tiny chance of ever occurring, therefore only potential problem. I just wanted to document some of the simple example code design tradeoffs. For now all you need to worry about is getting your first "hello world" CAN program up and working. |
|
|
| |
|
|
|
|
|
Posted: Mar 07, 2012 - 02:13 AM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
As far as receiving messeges from multiple identifiers, is it possible to set the Can identifier TAG registers up to receive data from three different id's with the use of only one MOb?
Perhaps by using OR statements when assigning values to CANIDT1 and CANIDT2? |
|
|
| |
|
|
|
|
|
Posted: Mar 07, 2012 - 03:19 PM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
Every CAN ID sent on the CAN bus by any CAN Tx node consists of the CANCDMOB.IDE bit (11 or 29 bit format), all the CANIDT.IDTn identifier value bits and the CANIDT4.RTRTAG bit (remote or data frame type). See the data sheet Figure 19-1 CAN Standard Frames and Figure 19-2 CAN Extended Frames. You will find all these bits in the arbitration field.
When your CAN node receives CAN traffic from the CAN bus the basic functionality is the IDE CAN bus value must match the MOb CANCDMOB.IDE bit (11 or 29 bit ID format), match the CANIDT.IDTn identifier value bits and match the CANIDT4.RTRTAG bit (data or remote frame). You setup your Rx MOb CANCDMOB and CANIDT registers to match the ID you want to Rx from the CAN bus.
See the data sheet section 19.5.3 Acceptance Filter. The acceptance filter changes how a match is detected. For every identifier value mask bit set to a one value in the CANIDM.IDMSKn bits, the received CAN bus bit must match what you programmed into the CANIDT.IDTn identifier value bits. However, if you clear a CANIDM.IDMSKn bit to zero, then the corresponding CAN bus identifier value bit will be forced to match (it does not matter what identifier value bit is received from the CAN bus, the match is forced).
Lets look at an example 11 bit format identifier CANIDT value with some CANIDM mask bits set to zero.
Code:
CANIDT = 000 0000 0000 - ID zero
CANIDM = 111 1111 1100 - ID mask forces two LSB ID bits to match.
match = 000 0000 00xx - the xx means it does not matter what the actual CAN bus received bit value is
If you expand all the possible IDs with the xx do not care value bits you get:
Code:
000 0000 0000 = ID 0
000 0000 0001 = ID 1
000 0000 0010 = ID 2
000 0000 0011 = ID 3
This works for any ID bit value you program your CAN node to receive.
Another example 11 bit format identifier CANIDT value with some CANIDM mask bits set to zero.
Code:
CANIDT = 000 0000 0100 - ID four
CANIDM = 111 1111 1100 - ID mask forces two LSB ID bits to match.
match = 000 0000 01xx - the xx means it does not matter what the actual CAN bus received bit value is
If you expand all the possible IDs with the xx do not care value bits you get:
Code:
000 0000 0100 = ID 4
000 0000 0101 = ID 5
000 0000 0110 = ID 6
000 0000 0111 = ID 7
I left out the CANCDMOB.IDE and CANIDT4.RTRTAG bits from the above examples. If CANIDM4.IDEMSK is cleared to a zero value, then any 11 bit or 29 bit format CAN traffic will be received. If CANIDM4.RTRMSK is cleared to a zero value, then any data frame or remote frame CAN traffic will be received.
If you clear all the CANIDM register bits, then all CAN traffic 11 and 29 bit format, any identifier value, data and remote frame will all be received.
When any CANIDM mask bit is cleared to a zero value, after the MOb RXOK you must read the MOb registers to find out what was actually received. If the MOb CANIDM4.IDEMSK is cleared then you must read CANCDMOB.IDE after the RXOK to find out if an 11 bit or 29 bit format was received. If CANIDM4.RTRMSK is cleared then you must read CANIDT4.RTRTAG after the RXOK to find out if a data frame or remote frame was received. If any CANIDM.IDEMSKn bits are cleared, then you must read the CANIDT.IDTn bit values after the RXOK to find out what actual identifier value was received. |
|
|
| |
|
|
|
|
|
Posted: Mar 16, 2012 - 10:27 PM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
Well I have 3 different identifiers that I am wanting to read data from that are
-0x3E8
-0x5DC
-0x1F4
So the origional CANIDT registers can remain unaltered like this?
Code:
...
CANIDT1 = (uint8_t) (1000>>3);
CANIDT2 = (uint8_t) (1000<<5);
CANIDT3 = 0x00;
CANIDT4 = (1 << RTRTAG);
...
Now to set the mask registers to receive data from these three identifiers i should do this?
Code:
CANIDM1 = (uint8_t) (0x1C3 >> 3); // 0b00111000
CANIDM2 = (uint8_t) (0x1C3 << 5); // 0b01100000
CANIDM3 = 0x00;
CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK);
...
I beleive by doing this I will receive messeges from all of the 3 earlier mentioned identifiers, as well as many others consequently.
Once I have done this in my can_init routine I was going to do this in my main program.
Code:
...
while (1){
CANPAGE = (1 << MOBNB0);
if (Can_status & (1 << RXOK)){
Can_status = 0;
if ((CANIDT2 = 0b10000000) & (CANIDT1 = 0b10111011)){
...
I used these values to receive messeges from the 0x5DC identifier but it is not working correctly. Maybe I am trying to read the CANIDT registers in the wrong place? I will go ahead and include my complete code for any clarification needed.
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/sleep.h>
#include <avr/iocan128.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <Math.h>
#define MOB_DIS_CMD ((0 << CONMOB1) | (0 << CONMOB0))
#define MOB_RX_CMD ((1 << CONMOB1) | (0 << CONMOB0))
#define MOB_TX_CMD ((0 << CONMOB1) | (1 << CONMOB0))
#define MOB_IDE_FIELD (1 << IDE)
#define MOB_IDE_11F (0 << IDE)
#define MOB_IDE_29F (1 << IDE)
#define MOB_DLC_FIELD ((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))
#define MOB1_RX_8_BYTES 8
volatile uint8_t Can_status;
//*******************************************************
void PWM_Init (int a,int b)
{
// COM set, fast PWM, 1024 prescaler
TCCR1A = ((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10));
TCCR1B = ((1<<WGM13) | (1<<WGM12) | (1<<CS12) | (0<<CS11) | (1<<CS10));
// Set PWM value
OCR1A = a;
OCR1B = b;
/* Enable timer 1 comp interrupt. */
TIMSK1 = (1<<OCIE1A)|(1<<OCIE1B);
// Reset timer
TCNT1 = 0;
}
void can_init (void) {
CANGCON = (1 << SWRES); // Reset the entire CAN controller.
Can_status = 0; // Default starting value for each CAN initialization.
// Initialization of Message Object
int k;
for (k=0;k<15;k++)
{
CANPAGE = k << 4;
CANCDMOB = 0x00;
CANSTMOB = 0x00;
}
// baud rate set at 125kbaud assuming 16Mhz clock
CANBT1 = 0x0e ;
CANBT2 = 0x0c ;
CANBT3 = 0x37 ;
// CANTCON, CANIE1, and CANGIT were cleared by the SWRES (see the data sheet).
CANGIE = (1 << ENIT) | (1 << ENRX) | (1 << ENERR) | (1 << ENERG);
CANIE2 = (1 << IEMOB1); // MOb1 Interrupt Enabled,
CANGCON = (1 << ENASTB) ; // Enable the CAN.
// Initialization of Message Object One
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Set the ID to 1000 decimal (0x3E8).
CANIDT1 = (uint8_t) (1000 >> 3);
CANIDT2 = (uint8_t) (1000 << 5);
CANIDT3 = 0x00;
CANIDT4 = (0 << RTRTAG); // Set data frame.
// Only allow the single 1000 decimal ID value to Rx.
CANIDM1 = (uint8_t) (0x1C3 >> 3); // Set all 11 ID mask bits to force matching CANIDT ID.
CANIDM2 = (uint8_t) (0x1C3 << 5);
CANIDM3 = 0x00;
CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK); // Force only Rx data frame 11 bit ID.
CANCDMOB = MOB_RX_CMD | MOB_IDE_11F | MOB1_RX_8_BYTES; //sets MOb for reception; sets dlc to 8
}
//*******************************************************
ISR (CANIT_vect) {
uint8_t save_page; // Pre-interrupt CANPAGE value storage.
save_page = CANPAGE; // Save the pre-interrupt CANPAGE value.
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Get possible RXOK flag and concatenate with all previous MOb error flags (ENERR).
Can_status |= CANSTMOB;
// Clear the CANSTMOB interrupt flags.
CANSTMOB = 0;
// Concatenate all the MOb error flags (ENERR) with the general error flags (ENERG).
Can_status |= (CANGIT & ((1 << SERG) | (1 << CERG) | (1 << FERG) | (1 << AERG)));
// Clear the ENERG interrupt flags. This works differently from the CANSTMOB clear.
CANGIT = ((1 << SERG) | (1 << CERG) | (1 << FERG) | (1 << AERG));
CANPAGE = save_page; // Restore the pre-interrupt CANPAGE value.
}
//*******************************************************
int main(void) {
uint8_t i;
uint8_t result_1; // CANMSG byte == 0x22 compare result.
uint8_t result_2;
uint8_t result_3;
uint8_t result_4;
uint8_t result_5;
uint8_t result_6;
uint8_t result_7;
uint8_t result_8;
long long master_result_1;
long long master_result_2;
long long master_result_3;
long long master_result_4;
long long master_result_5;
long long master_result_6;
long long master_result_7;
long long master_result_8;
long long master_result;
double x;
uint8_t dlc; // CANMSG byte total count.
can_init();
sei(); // enable interrupt globally
while (1) {
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Check to see if the ISR CANIT finished the MOb 1 Rx.
if (Can_status & (1 << RXOK) ) { // Ignore all MOb 1 Rx results until a RXOK is set.
Can_status = 0; // Clear the last status to start over with a new Rx.
if ((CANIDT2 == 0b10000000) & (CANIDT1 == 0b10111011)){
// Any new ENERG errors will set the Can_status error bits before the new Rx is started.
result_1 = 0; // Initial test value default.
result_2 = 0;
result_3 = 0;
result_4 = 0;
result_5 = 0;
result_6 = 0;
result_7 = 0;
result_8 = 0;
master_result_1 = 0;
master_result_2 = 0;
master_result_3 = 0;
master_result_4 = 0;
master_result_5 = 0;
master_result_6 = 0;
master_result_7 = 0;
master_result_8 = 0;
master_result = 0;
x=0;
// Limit dlc to MOB_MAX_DLC and check for the correct number of Rx bytes.
if ((dlc = MOB_DLC_LIMIT(CANCDMOB & MOB_DLC_FIELD)) == MOB1_RX_8_BYTES) {
.
for (i = 0; i < dlc; i++) {
if (i==0)
result_1 = CANMSG;
if (i==1)
result_2 = CANMSG;
if (i==2)
result_3 = CANMSG;
if (i==3)
result_4 = CANMSG;
if (i==4)
result_5 = CANMSG;
if (i==5)
result_6 = CANMSG;
if (i==6)
result_7 = CANMSG;
if (i==7)
result_8 = CANMSG;
}
} else {
(result_1 = ~0); // ERROR, not enough CANMSG bytes were received.
(result_2 = ~0);
(result_3 = ~0);
(result_4 = ~0);
(result_5 = ~0);
(result_6 = ~0);
(result_7 = ~0);
(result_8 = ~0);
}
master_result_1 = result_1;
master_result_1 = (master_result_1 << 56);
master_result_2 = result_2;
master_result_2 = (master_result_2 << 48);
master_result_3 = result_3;
master_result_3 = (master_result_3 << 40);
master_result_4 = result_4;
master_result_4 = (master_result_4 << 32);
master_result_5 = result_5;
master_result_5 = (master_result_5 << 24);
master_result_6 = result_6;
master_result_6 = (master_result_6 << 16);
master_result_7 = result_7;
master_result_7 = (master_result_7 << 8);
master_result_8 = result_8;
master_result = (master_result_1 + master_result_2 + master_result_3 + master_result_4 + master_result_5 + master_result_6 + master_result_7 + master_result_8);
if ( (master_result >0x0) & (master_result<=0x14)) {
x = (255-((0.5*master_result)+229.5));
DDRB = 0x40; //set PB6 output (OC1B)
PWM_Init (0xFF,x);
SREG = (1<<SREG_I);
}
else {
DDRB = 0x40; //set PB6 output (OC1B)
PWM_Init (0xFF,0xFF);
SREG = (1<<SREG_I);
}
// Restart the MOb 1 Rx (the RXOK disabled MOb 1, so we know it is ready again).
CANCDMOB = MOB_RX_CMD | MOB_IDE_11F | MOB1_RX_8_BYTES;
}} // End of MOb 1 Rx ID 1000 decimal RXOK processing.
} // End of while(1) loop - no more executable code past this point.
}
ISR (TIMER1_COMPA_vect) //just to test if interrupt is set
{
;
}
ISR (TIMER1_COMPB_vect) //just to test if interrupt is set
{
;
}
|
|
|
| |
|
|
|
|
|
Posted: Mar 17, 2012 - 01:56 AM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
|
Code:
...
CANIDT1 = (uint8_t) (1000>>3);
CANIDT2 = (uint8_t) (1000<<5);
CANIDT3 = 0x00;
CANIDT4 = (1 << RTRTAG);
...
I assume you know RTRTAG being set is a remote CAN frame that has no CANMSG bytes. A remote frame is used by a CAN node as a request to another CAN node to Tx a certain (CANCDMOB.DLC Rx value) number of CAN data bytes on the CAN bus. So, obviously the requesting node sending the remote frame request has no CAN data to send itself (a remote frame will not send any data even if you want to Tx data bytes) and only has the number of data bytes wanted. If you actually meant to Rx data frames with CANMSG bytes, but programmed remote frames, you will never get any CANSTMOB.RXOK if only data frames are sent on your CAN bus.
Personally, I use:
Code:
CANIDT4 = (0 << RTRTAG);
allot for CAN data frames. The shifted zero is the same as CANIDT4=0x00, except the source code becomes more readable with the explicit data frame 0 RTRTAG shift.
I see you did your data frame correctly in your actual sample code.
Yes your use of the CANIDM mask is correct. There are two small problems in both of your examples:
Code:
// first example
...
while (1){
CANPAGE = (1 << MOBNB0);
if (Can_status & (1 << RXOK)){
Can_status = 0;
if ((CANIDT2 = 0b10000000) & (CANIDT1 = 0b10111011)){
...
I think you meant this:
Code:
if ((CANIDT2 == 0b10000000) && (CANIDT1 == 0b10111011)){
However, I think this reads allot better:
Code:
if ((CANIDT2 == (0x5DC << 5)) && (CANIDT1 == (0x5DC >> 3))){
Since all the constant value shifts are done at compile time there is no execution time penalty for these shifts and unlike the binary they are easy to read. Also the compiler should do the uint8_t type cast automatically for this 11 bit ID. If you get too busy reading and rejecting CAN messages you do not want to read (because of the wide CANIDM setting and if these “other” unwanted CAN IDs are actually on the CAN bus), you could rewrite your code to use three different Rx MObs just for the three CAN IDs you want to Rx.
Shouldn't you be doing something like this to pickup all three IDs:
Code:
if (((CANIDT2 == (0x3E8 << 5)) && (CANIDT1 == (0x3E8 >> 3))) ||
((CANIDT2 == (0x5DC << 5)) && (CANIDT1 == (0x5DC >> 3))) ||
((CANIDT2 == (0x1F4 << 5)) && (CANIDT1 == (0x1F4 >> 3)))) {
I suspect it was your mixing up of logical and bitwise operations in the if() was your main problem?
Keep in mind that the example code I wrote was for simple Rx testing only. I have an improved version I have not been able to get my hardware setup to test yet. Still this code is probably not going the direction you may need to ultimately go. For one thing the 29 bit format, RTRMSK=0 and IDEMSK=0 are not right for your setup and the ISR is strange being limited to a single MOb etc.:
Code:
//*******************************************************
// This is a WinAVR/GCC compiler 8 bit AT90CANxxx family AVR CAN Rx test program. It
// provides a framework to Rx all CAN traffic and add your own debug output. See the
// comments in main() for adding your own debug output code.
//
// This is intended as working CAN driver code to test new CAN hardware. It requires
// another CAN node to Tx CAN traffic to this AVR CAN node.
//
// This code requires a very high availibility for the ISR (CANIT_vect) interrupt.
// If your code adds anything to degrade this availibility, the results may not be
// reliable.
#include <avr/interrupt.h>
#include <util/atomic.h>
// Place your other CAN chip includes here.
#define AT90CAN_MOBS 15
#define MOB_DIS_CMD ((0 << CONMOB1) | (0 << CONMOB0))
#define MOB_RX_CMD ((1 << CONMOB1) | (0 << CONMOB0))
#define MOB_TX_CMD ((0 << CONMOB1) | (1 << CONMOB0))
#define MOB_IDE_11F (0 << IDE)
#define MOB_IDE_29F (1 << IDE)
#define MOB_DLC_FIELD ((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))
#define MOB1_RX_DLC_DEFAULT 8
volatile uint8_t Can_status; // Used by the CAN ISR and main().
//*******************************************************
// Initialize the CAN hardware and the global status value. The user needs to provide the
// correct baud rate setup (see the data sheet).
//
void can_init (void) {
uint8_t mob; // Temporary MOb register set selection number value.
CANGCON = (1 << SWRES); // Reset the CAN controller hardware and general CAN registers.
Can_status = 0; // Global variable starting value for each CAN initialization.
// All MObs must be initialized because MObs have no reset initial value.
for (mob = 0; mob < AT90CAN_MOBS; mob++) {
CANPAGE = (mob << MOBNB0); // Set the MOb page number for each MOb 0 to 14 (15 MObs total).
CANCDMOB = MOB_DIS_CMD; // Set each MOb configuration to disabled *CRITICAL*.
CANSTMOB = 0; // Clear all the MOb interrupt/polling flags *CRITICAL*.
}
//****
// This is a randomly selected CAN Baud setting, you need to put your real values based on
// CLKio here. See the CAN baud examples and the Baud Rate Prescaler errata in the ATMEL
// data sheet.
//****
CANBT1 = 0x0e;
CANBT2 = 0x0c;
CANBT3 = 0x37;
// CANTCON was cleared by the SWRES (see the data sheet).
CANGIE = (1 << ENIT) | (1 << ENRX) | (1 << ENERR) | (1 << ENERG);
CANIE2 = (1 << IEMOB0); // MOb 0 Interrupt Enabled,
// CANIE1 was cleared by the SWRES (see the data sheet).
// CANGIT was cleared by the SWRES (see the data sheet).
CANGCON = (1 << ENASTB) ; // Enable the CAN.
}
//*******************************************************
// Setup MOb 0 to Rx all CAN traffic. This is any 11 or 29 bit IDE format, any CANIDT ID
// value and any Data or Remote frame RTRTAG CAN traffic. Since this MOb will Rx both 11
// bit and 29 bit ID formats, 29 bit format is used to setup this MOb. This example is
// written to use a 29 bit UL constant to demonstrate setting 29 bit values, even though
// this is not needed for zero values (a uint32_t variable could replace the UL constant).
//
void mob_init (void) {
CANPAGE = (0 << MOBNB0); // Select MOb 0, AINC = 0, INDEX2:0 = 0.
// Put an initial 0x00000000 ID into CANIDT (see the mask below).
CANIDT1 = (uint8_t) (0x00000000UL >> 21); // No ID mask is set.
CANIDT2 = (uint8_t) (0x00000000UL >> 13);
CANIDT3 = (uint8_t) (0x00000000UL >> 5);
CANIDT4 = (uint8_t) (0x00000000UL << 3) | (0 << RTRTAG);
// An alternate 32 bit CANIDT register WinAVR example:
// CANIDT = (0x00000000UL << 3) | (0UL << RTRTAG);
// Mask to Rx all CAN IDs, any frame type and any 11/29 bit format.
CANIDM1 = (uint8_t) (0x00000000UL >> 21);
CANIDM2 = (uint8_t) (0x00000000UL >> 13);
CANIDM3 = (uint8_t) (0x00000000UL >> 5);
CANIDM4 = (uint8_t) (0x00000000UL << 3) | (0 << RTRMSK) | (0 << IDEMSK);
// An alternate 32 bit CANIDM register WinAVR example:
// CANIDM = (0x00000000UL << 3) | (0UL << RTRMSK) | (0UL << IDEMSK);
// Start the MOb 0 CAN Rx command.
CANCDMOB = MOB_RX_CMD | MOB_IDE_29F | MOB1_RX_DLC_DEFAULT;
}
//*******************************************************
// This processes each CAN CANSTMOB (ENRX and ENERR) and CANGIT (ENERG) interrupt providing
// Can_status for use by other functions to detect Mob 0 CAN activity. This is dedicated to
// only MOb 0. After CANSTMOB.RXOK is set MOb 0 is disabled and all MOb register Rx data is
// ready for use in other functions, up until later when Rx MOb 0 is re-enabled by a CANCDMOB
// command Rx write. No MOb 0 Rx data is extracted in this ISR. Combining CANSTMOB and CANGIT
// errors only makes sense because there is only one single MOb enabled in this test code.
//
ISR (CANIT_vect) {
uint8_t save_page; // Pre-interrupt CANPAGE value storage.
uint8_t gen_errors; // CAMGIT general error flag values.
save_page = CANPAGE; // Save the pre-interrupt CANPAGE value.
CANPAGE = (0 << MOBNB0); // Select MOb 0, AINC = 0, INDEX2:0 = 0.
// Only process CANSTMOB if it has something in it. Otherwise the CANSTMOB clear might
// conflict with a new CANSTMOB interrupt flag being set (this prevents a race condition).
if (CANSTMOB) {
// Get possible RXOK flag and concatenate (ENERR) with all previous MOb error flags.
Can_status |= CANSTMOB;
// Clear the CANSTMOB interrupt flags.
CANSTMOB = 0;
}
// Get a copy of all the gneral error flags that are set at this time.
gen_errors = (CANGIT & ((1 << SERG) | (1 << CERG) | (1 << FERG) | (1 << AERG)));
// Clear only the set error ENERG interrupt flags. This works differently from the
// CANSTMOB clear (see the data sheet). This method also avoids loosing any new just
// set now general error flag types when CANGIT is cleared.
CANGIT = gen_errors; // Clear only the already set error flags.
// Concatenate all the MOb error flags (ENERR) with the general error flags (ENERG).
Can_status |= gen_errors;
CANPAGE = save_page; // Restore the pre-interrupt CANPAGE value.
}
//*******************************************************
// The CAN MOb information is extracted here in main() by polling Can_status. Then after
// CANSTMOB.RXOK is detected the MOb 0 register storage has all the Rx updated information.
//
// FYI: Since this code does not have any Tx MObs, the BERR flag should never be set at any time.
//
int main(void) {
uint8_t dlc; // CANMSG byte total count.
uint8_t error_debug_flags = 0;
uint8_t error_debug_flags_last = 0;
uint8_t gen_error_flags_cleanup = 0;
can_init();
mob_init();
sei(); // enable interrupts globally
while (1) {
CANPAGE = (0 << MOBNB0); // Select MOb 0, AINC = 0, INDEX2:0 = 0.
error_debug_flags = Can_status; // Poll Can_status and save the result.
// The error_debug_flags_last ensures this debug only happens one time for each new type
// of error flag. Multiple occurrences of the same error flag are ignored. This is also
// triggered for RXOK even though this is not an error flag.
if (error_debug_flags != error_debug_flags_last) {
// Debug output of the error_debug_flags value.
// Debug output of CANREC and CANTEC values.
error_debug_flags_last = error_debug_flags;
}
// Check to see if the ISR CANIT finished the MOb 0 Rx.
if (error_debug_flags & (1 << RXOK)) { // Ignore all MOb 0 Rx results until a RXOK is set.
// After this any new CANGIT error flags will now be set in Can_status. No CANSTMOB
// flags will be set until after the MOb 0 Rx is restarted.
// Pickup any last new types of general error flags since the debug output above.
// Temporarily stop any new CANGIT error interrupts while cleaning up (the RXOK
// MOb 0 automatic disable has already stopped any CANSTMOB interrupts).
ATOMIC_BLOCK(ATOMIC_FORCEON)
{
gen_error_flags_cleanup = Can_status ^ error_debug_flags;
Can_status = 0; // Clear the last result to start over with a new Rx.
} // Restore CANGIT error interrupts (these are saved and reported in Can_status).
error_debug_flags = 0; // Reset the error_debug_flags for the next MOb 0 Rx cycle.
error_debug_flags_last = 0;
// Always limit RXOK updated CANCDMOB.DLC result to MOB_MAX_DLC.
dlc = MOB_DLC_LIMIT(CANCDMOB & MOB_DLC_FIELD);
// Debug output for gen_error_flags_cleanup.
// Debug output for MOb 0 information after the RXOK update. Add your own output code
// here or perhaps a JTAGICE/DebugWire breakpoint.
// CANCDMOB.IDE bit is the Rx updated 11/29 bit format.
// If CANCDMOB.IDE bit is 0 - 11 bit foramt.
// (CANIDT >> 21) bits are the Rx updated 11 bit ID value.
// If CANCDMOB.IDE bit is 1 - 29 bit format.
// (CANIDT >> 3) bits are the Rx updated 29 bit ID value.
// CANIDT4.RTRTAG bit is the Rx updated Data/Remote frame type.
// If CANIDT4.RTRTAG bit is 0
// read the dlc number of CANMSG bytes to get the CAN data for output.
// Restart the MOb 0 Rx (the RXOK disabled MOb 0, so we know it is ready again).
CANCDMOB = MOB_RX_CMD | MOB_IDE_11F | MOB1_RX_DLC_DEFAULT;
}
} // End of while(1) loop - no more executable code past this point.
}
|
|
|
| |
|
|
|
|
|
Posted: Mar 18, 2012 - 11:03 PM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
Well I want to create different outputs for different identifiers.
I have the masking register set up correctly where i recieve all of the different identifiers I want but when I try to add the if statement that controls what identifier is getting through, I don't get an output when the message is sent.
Basically, I want to accept messages from all three identifiers that I mentioned in my last post (0x3E8, 0x5DC, 0x1F4), and be able to distinguish where the 8 bytes of data is coming from to make an output accordingly.
The data sheet says that the Identifier field is updated with the corresponding value of the remote or data frame received. So this makes me think that using this would work how I described.
Code:
int main(void) {
uint8_t i;
uint8_t result_1; // CANMSG byte == 0x22 compare result.
uint8_t result_2;
uint8_t result_3;
uint8_t result_4;
uint8_t result_5;
uint8_t result_6;
uint8_t result_7;
uint8_t result_8;
long long master_result_1;
long long master_result_2;
long long master_result_3;
long long master_result_4;
long long master_result_5;
long long master_result_6;
long long master_result_7;
long long master_result_8;
long long master_result;
double x;
uint8_t dlc; // CANMSG byte total count.
can_init();
sei(); // enable interrupt globally
while (1) {
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Check to see if the ISR CANIT finished the MOb 1 Rx.
if (Can_status & (1 << RXOK) ) { // Ignore all MOb 1 Rx results until a RXOK is set.
Can_status = 0; // Clear the last status to start over with a new Rx.
if ((CANIDT2 == (0x5DC << 5)) && (CANIDT1 == (0x5DC >> 3))){
// Any new ENERG errors will set the Can_status error bits before the new Rx is started.
result_1 = 0; // Initial test value default.
result_2 = 0;
result_3 = 0;
result_4 = 0;
result_5 = 0;
result_6 = 0;
result_7 = 0;
result_8 = 0;
master_result_1 = 0;
master_result_2 = 0;
master_result_3 = 0;
master_result_4 = 0;
master_result_5 = 0;
master_result_6 = 0;
master_result_7 = 0;
master_result_8 = 0;
master_result = 0;
x=0;
// Limit dlc to MOB_MAX_DLC and check for the correct number of Rx bytes.
if ((dlc = MOB_DLC_LIMIT(CANCDMOB & MOB_DLC_FIELD)) == MOB1_RX_8_BYTES) {
.
for (i = 0; i < dlc; i++) {
if (i==0)
result_1 = CANMSG;
if (i==1)
result_2 = CANMSG;
if (i==2)
result_3 = CANMSG;
if (i==3)
result_4 = CANMSG;
if (i==4)
result_5 = CANMSG;
if (i==5)
result_6 = CANMSG;
if (i==6)
result_7 = CANMSG;
if (i==7)
result_8 = CANMSG;
}
} else {
(result_1 = ~0); // ERROR, not enough CANMSG bytes were received.
(result_2 = ~0);
(result_3 = ~0);
(result_4 = ~0);
(result_5 = ~0);
(result_6 = ~0);
(result_7 = ~0);
(result_8 = ~0);
}
master_result_1 = result_1;
master_result_1 = (master_result_1 << 56);
master_result_2 = result_2;
master_result_2 = (master_result_2 << 48);
master_result_3 = result_3;
master_result_3 = (master_result_3 << 40);
master_result_4 = result_4;
master_result_4 = (master_result_4 << 32);
master_result_5 = result_5;
master_result_5 = (master_result_5 << 24);
master_result_6 = result_6;
master_result_6 = (master_result_6 << 16);
master_result_7 = result_7;
master_result_7 = (master_result_7 << 8);
master_result_8 = result_8;
master_result = (master_result_1 + master_result_2 + master_result_3 + master_result_4 + master_result_5 + master_result_6 + master_result_7 + master_result_8);
if ( (master_result >0x0) & (master_result<=0x14)) {
x = (255-((0.5*master_result)+229.5));
DDRB = 0x40; //set PB6 output (OC1B)
PWM_Init (0xFF,x);
SREG = (1<<SREG_I);
}
else {
DDRB = 0x40; //set PB6 output (OC1B)
PWM_Init (0xFF,0xFF);
SREG = (1<<SREG_I);
}
// Restart the MOb 1 Rx (the RXOK disabled MOb 1, so we know it is ready again).
CANCDMOB = MOB_RX_CMD | MOB_IDE_11F | MOB1_RX_8_BYTES;
}} // End of MOb 1 Rx ID 1000 decimal RXOK processing.
} // End of while(1) loop - no more executable code past this point.
}
I use that if statement for nearly the entirety of my main function to ensure that my output is only changing based on the data from the 0x5DC identifier but I believe I must be using the if statement the wrong way. Is there a specific point between interupts that the IDT registers are updated? |
|
|
| |
|
|
|
|
|
Posted: Mar 19, 2012 - 03:29 AM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
From your description I do not understand what is working or what it not working. You have not even told me if your CAN bus is working at all or not working at all. How about this, try the last program I gave you. Add your own debug output in main() where the comments are. At a minimum send debug output for the error_debug_flags, CANTEC, CANREC, CANIDT and the CANCDMOB registers. If you have a JTAGICE you may set breakpoints instead.
This will tell us first if the AVR CAN is running with errors or not. If there are errors the CANTEC and CANREC counters will tell us the CAN bus state. Then the CANCDMOB and CANIDT registers debug will tell us if the RXOK is being set and absolutely what CAN IDs the AVR is receiving.
The IF() statement you suspect as the problem is not even able to work at all unless there is a RXOK, end of story. If there is a RXOK then you still need your specific ID. If there are too many other CAN Tx IDs form the other CAN node, then put an if(ID match) before the CANCDMOB/CANIDT debug output. This will tell us if your specific ID is even being seen by the AVR at all.
You are jumping too far ahead by trying your PWM code before you even know if the CAN works or not. Keeping it simple and methodical will solve the problem. |
|
|
| |
|
|
|
|
|
Posted: Mar 20, 2012 - 02:14 AM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
Sorry I didn't thouroughly explain my problems. I keep forgetting that you aren't sitting here next to me haha.
Forgetting about trying to acquire the current address I am receiving a message from, my code does this.
1 - CAN message is sent from PC via USB-to-CAN Compact.
2 - CAN message is delivered to AVR-CAN
3 - Any data value received from addresses 0x3E8, 0x1F4, or 0x5DC between the data values of 0x1 and 0x14 create a pulse width modulated signal successfully on my oscilloscope. The pulse width changes depending on the value of the data part of the message.
The problem I am experiencing now is this.
I can successfully determine what the value of the address is that is being received. A PWM signal is created only when a messege is sent from address 0x3E8 (as is desired). However, once the first message is received on the AVR-CAN, the program doesn't loop back. Transmitting a new message from the PC creates no change in the PWM signal.
On the bright side, when the first message is sent, a PWM signal is only emitted when the CANIDT is of 0x3E8 and when the data is of a value of 0x01 to 0x14 (as is desired.
Where is the best place to read the updated CANIDT value? Do you beleive that my problem is due to this matter, or perhaps a flaw in my programming for my output?
I commented my code a little better to make more clear.
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/sleep.h>
#include <avr/iocan128.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <Math.h>
#define MOB_DIS_CMD ((0 << CONMOB1) | (0 << CONMOB0))
#define MOB_RX_CMD ((1 << CONMOB1) | (0 << CONMOB0))
#define MOB_TX_CMD ((0 << CONMOB1) | (1 << CONMOB0))
#define MOB_IDE_FIELD (1 << IDE)
#define MOB_IDE_11F (0 << IDE)
#define MOB_IDE_29F (1 << IDE)
#define MOB_DLC_FIELD ((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))
#define MOB1_RX_8_BYTES 8
volatile uint8_t Can_status;
//*******************************************************
void PWM_Init (int a,int b)
{
// COM set, fast PWM, 1024 prescaler
TCCR1A = ((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10));
TCCR1B = ((1<<WGM13) | (1<<WGM12) | (1<<CS12) | (0<<CS11) | (1<<CS10));
// Set PWM value
OCR1A = a;
OCR1B = b;
/* Enable timer 1 comp interrupt. */
TIMSK1 = (1<<OCIE1A)|(1<<OCIE1B);
// Reset timer
TCNT1 = 0;
}
void can_init (void) {
CANGCON = (1 << SWRES); // Reset the entire CAN controller.
Can_status = 0; // Default starting value for each CAN initialization.
// Initialization of Message Object
int k;
for (k=0;k<15;k++)
{
CANPAGE = k << 4;
CANCDMOB = 0x00;
CANSTMOB = 0x00;
}
// baud rate set at 125kbaud assuming 16Mhz clock
CANBT1 = 0x0e ;
CANBT2 = 0x0c ;
CANBT3 = 0x37 ;
// CANTCON, CANIE1, and CANGIT were cleared by the SWRES (see the data sheet).
CANGIE = (1 << ENIT) | (1 << ENRX) | (1 << ENERR) | (1 << ENERG);
CANIE2 = (1 << IEMOB1); // MOb1 Interrupt Enabled,
CANGCON = (1 << ENASTB) ; // Enable the CAN.
// Initialization of Message Object One
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Set the ID to 1000 decimal (0x3E8).
CANIDT1 = (uint8_t) (1000 >> 3);
CANIDT2 = (uint8_t) (1000 << 5);
CANIDT3 = 0x00;
CANIDT4 = (0 << RTRTAG); // Set data frame.
// Only allow the single 1000 decimal ID value to Rx.
CANIDM1 = 0b00111000; // Set all 11 ID mask bits to force matching CANIDT ID.
CANIDM2 = 0b01100000;
CANIDM3 = 0x00;
CANIDM4 = (0 << RTRMSK) | (1 << IDEMSK); // Force only Rx data frame 11 bit ID.
CANCDMOB = MOB_RX_CMD | MOB_IDE_11F | MOB1_RX_8_BYTES; //sets MOb for reception; sets dlc to 8
}
//*******************************************************
ISR (CANIT_vect) {
uint8_t save_page; // Pre-interrupt CANPAGE value storage.
save_page = CANPAGE; // Save the pre-interrupt CANPAGE value.
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Get possible RXOK flag and concatenate with all previous MOb error flags (ENERR).
Can_status |= CANSTMOB;
// Clear the CANSTMOB interrupt flags.
CANSTMOB = 0;
// Concatenate all the MOb error flags (ENERR) with the general error flags (ENERG).
Can_status |= (CANGIT & ((1 << SERG) | (1 << CERG) | (1 << FERG) | (1 << AERG)));
// Clear the ENERG interrupt flags. This works differently from the CANSTMOB clear.
CANGIT = ((1 << SERG) | (1 << CERG) | (1 << FERG) | (1 << AERG));
CANPAGE = save_page; // Restore the pre-interrupt CANPAGE value.
}
//*******************************************************
int main(void) {
uint8_t i;
uint8_t result_1; // CANMSG byte == 0x22 compare result.
uint8_t result_2;
uint8_t result_3;
uint8_t result_4;
uint8_t result_5;
uint8_t result_6;
uint8_t result_7;
uint8_t result_8;
long long master_result_1; //these are used to combine data into one 64bit number
long long master_result_2;
long long master_result_3;
long long master_result_4;
long long master_result_5;
long long master_result_6;
long long master_result_7;
long long master_result_8;
long long master_result;
double x;
long part_1; //These are used to combine the CANIDT registers into one 16bit number
long part_2;
long address;
uint8_t dlc; // CANMSG byte total count.
can_init();
sei(); // enable interrupt globally
while (1) {
CANPAGE = (1 << MOBNB0); // Select MOb 1, AINC = 0, INDEX2:0 = 0.
// Check to see if the ISR CANIT finished the MOb 1 Rx.
if (Can_status & (1 << RXOK) ) { // Ignore all MOb 1 Rx results until a RXOK is set.
//********************IF STATEMENT 1********************
Can_status = 0; // Clear the last status to start over with a new Rx.
// Any new ENERG errors will set the Can_status error bits before the new Rx is started.
result_1 = 0; // Initial test value default.
result_2 = 0;
result_3 = 0;
result_4 = 0;
result_5 = 0;
result_6 = 0;
result_7 = 0;
result_8 = 0;
master_result_1 = 0;
master_result_2 = 0;
master_result_3 = 0;
master_result_4 = 0;
master_result_5 = 0;
master_result_6 = 0;
master_result_7 = 0;
master_result_8 = 0;
master_result = 0;
x=0;
part_1 = 0;
part_2 = 0;
address = 0;
// Limit dlc to MOB_MAX_DLC and check for the correct number of Rx bytes.
if ((dlc = MOB_DLC_LIMIT(CANCDMOB & MOB_DLC_FIELD)) == MOB1_RX_8_BYTES) {
//********************IF STATEMENT 2********************
for (i = 0; i < dlc; i++) {
if (i==0){
result_1 = CANMSG;
part_1 = (CANIDT1 << 8); //because the data is successfully collected in this for loop, I assumed it would be the best place to collect the value of the CANIDT registers
part_2 = (CANIDT2);
address = (part_1 + part_2);
}
if (i==1)
result_2 = CANMSG;
if (i==2)
result_3 = CANMSG;
if (i==3)
result_4 = CANMSG;
if (i==4)
result_5 = CANMSG;
if (i==5)
result_6 = CANMSG;
if (i==6)
result_7 = CANMSG;
if (i==7)
result_8 = CANMSG;
}
}
//********************End of IF STATEMENT 2********************
else {
(result_1 = ~0); // ERROR, not enough CANMSG bytes were received.
(result_2 = ~0);
(result_3 = ~0);
(result_4 = ~0);
(result_5 = ~0);
(result_6 = ~0);
(result_7 = ~0);
(result_8 = ~0);
}
master_result_1 = result_1;
master_result_1 = (master_result_1 << 56);
master_result_2 = result_2;
master_result_2 = (master_result_2 << 48);
master_result_3 = result_3;
master_result_3 = (master_result_3 << 40);
master_result_4 = result_4;
master_result_4 = (master_result_4 << 32);
master_result_5 = result_5;
master_result_5 = (master_result_5 << 24);
master_result_6 = result_6;
master_result_6 = (master_result_6 << 16);
master_result_7 = result_7;
master_result_7 = (master_result_7 << 8);
master_result_8 = result_8;
master_result = (master_result_1 + master_result_2 + master_result_3 + master_result_4 + master_result_5 + master_result_6 + master_result_7 + master_result_8);
//master_result is the value of the complete 8 byte data from the message
if (address == (0x3E8 << 5)){// making sure the message is from 0x3E8
if ( (master_result >0x0) && (master_result<=0x14)) { // If all MOB1_RX_8_BYTES were 0x22 values then result_22 == 0.
x = (255-((0.5*master_result)+229.5));
DDRB = 0x40; //set PB6 output (OC1B)
PWM_Init (0xFF,x);
SREG = (1<<SREG_I);
}
else { // If all MOB1_RX_8_BYTES were 0x22 values then result_22 == 0.
DDRB = 0x40; //set PB6 output (OC1B)
PWM_Init (0xFF,0xFF);
SREG = (1<<SREG_I);
// Any data value outside of 0x01 to 0x14 eliminates the PWM signal
}
}//outputs for address 0x3E8 end here
// Restart the MOb 1 Rx (the RXOK disabled MOb 1, so we know it is ready again).
CANCDMOB = MOB_RX_CMD | MOB_IDE_11F | MOB1_RX_8_BYTES;
} // End of MOb 1 Rx ID 1000 decimal RXOK processing.
} // End of while(1) loop - no more executable code past this point.
}
ISR (TIMER1_COMPA_vect) //just to test if interrupt is set
{
;
}
ISR (TIMER1_COMPB_vect) //just to test if interrupt is set
{
;
}
|
|
|
| |
|
|
|
|
|
Posted: Mar 20, 2012 - 05:02 PM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
Well, if I'm sitting next to you and not seeing what is actually happening, then you should fire me .
A simple overview of a Rx MOb life cycle when CANGIE.ENIT is set (allot of details are missing):
1) Select the MOb by writing CANPAGE.
2) Start the MOb by writing CANCDMOB with a Rx command.
3) When CANSTMOB.RXOK is set the MOb is disabled.
4) The CAN IT interrupt is triggered by the RXOK.
5) The ISR code clears the CANCDMOB register and returns from the interrupt.
Now the Rx MOb is completed and disabled. The CAN data may be read from the CAN hardware (the MOb buffer) anytime after the CANSTMOB.RXOK event. Assuming no loss of AVR power, the MOb data is secure inside the CAN hardware until your program writes to it again or until another command is written to the MOb CANCDMOB.
As soon as the RXOK disables the MOb, in 11 bit ID format you have 19 CAN bit times (bit times are determined by the CAN baud rate) to re-enable the MOb. The RXOK rises at the end of the 6th bit of End Of Frame field (see the data sheet Figure 19-1 CAN Standard Frames). If you fail to re-enable the MOb before 19 CAN bit times have passed, you will loose 100% Rx coverage from this Rx MOb. Without 100% Rx coverage you may loose and not receive some CAN messages.
Since your CAN baud is 125 kbps each CAN bit is 8 us per CAN bit time. With a 16 MHz AVR clock of 62.5 ns for each cycle you get 128 AVR clocks per each CAN bit time. This is (19 times 128) 2432 AVR clock cycles for 19 CAN bit times. If doing your PWM or sending slow serial data in main() takes more then 2432 AVR clock cycles before the MOb Rx re-enable you risk loosing CAN messages from the CAN bus.
One way to increase the re-enable time is to create two or more MObs to Rx the exact same CAN message. The lowest numbered MOb gets the first matching CAN message and does a RXOK disable. However, the second MOb is still enabled and it catches the next CAN message before it does a RXOK. This second MOb gives you another full CAN message worth of time (44 CAN bit times minimum + CAN data byte bit times) to re-enable the first MOb. Each duplicate Rx MOb extends the minimum re-enable time by another full CAN frame. Since you seem to always Rx 8 CAN bytes of data that is 44 + 64 (108 CAN bits) which gives you an additional 13,824 AVR clock cycles for each duplicate MOb to re-enable your MObs. In order for you to use duplicate MObs your CAN ISR code will need to be totally rewritten.
From where I am there is no way for me to tell if you will benefit from duplicate MObs or not.
BTW, why do you have ENERR and ENERG enabled? You do not appear to be using the information from the error flags in any way at all. I only did this in the original example code because that program was intended to find out what was going wrong on the CAN bus.
Since you are only using 11 bit identifiers why not just do this:
Code:
uint16_t address;
address = ((uint16_t) CANIDT1 << 3) | ((uint16_t) CANIDT2 >> 5);
and remove the part_1/part_2 variables. The address variable does not need to be a long in your case. BTW, int32_t works for “long” and int64_t should work for “long long” for some of your other variables. See the next post.
Because your CANIDM mask must be wider than the ideal 3 desired CAN IDs, it appears to me you are doing way too much stuff before you filter out unwanted Rx IDs. Shouldn't your priority after this:
Code:
if (Can_status & (1 << RXOK) ) { // Ignore all MOb 1 Rx results until a RXOK is set.
Can_status = 0; // Clear the last status to start over with a new Rx.
be to immediately reject unwanted IDs. You do allot of work before finding out if you even have ID 0x3E8 or not. Have you looked at what happens if you do all this PWM setup and do not even have the correct CAN ID (does this mess anything up)? If you get any ID you did not really want to Rx, all you need to do is restart the Rx MOb. BTW, those large shifts in the “long long” 64 bit variables could be an AVR clock cycle eaters.
That last example code improved the ISR (CANIT_vect) code for better reliability. Since you seem to still be using this code (not for its intended purpose, but for your purposes) you should change to the new ISR code in my last example.
This:
Code:
x = (255-((0.5*master_result)+229.5));
is suspect since you are mixing double and int64_t data types with integer and floating point constants. This calculation may not be working correctly. Get some debug output on your x result and see if it makes any sense or not. Maybe the CAN is working, but your calculation is what fails to change on the next CAN ID Rx? This type of math especially, on an 8 bit AVR could be pushing you over your 2432 AVR clock cycle Rx MOb re-enable limit all by itself. If you run this part of your program under the AVRstudio simulator you may count AVR execution clock cycles and find out how bad it is. The best solution for this type of thing is figuring out how to do all your math in integers (of the required sizes) and not use floating point at all. After all, the PWM hardware registers are all integer controlled, so decimal fractions do not mean anything to this hardware. For a simple partial example; (0.5*master_result) is just a divide by two of an int64_t, which is only a >> 1 (shift right by 1 bit). If your code actually calls in the floating point library to do this, you will waste tons of AVR instruction cycles doing something simple. Do you really need that 1 bit integer fraction left over from a >> 1 shift that a floating point calculation will preserve, or could you afford to loose that fraction with an int64_t >> 1 truncated integer result?
I forgot to mention this:
Code:
if ( (master_result >0x0) && (master_result<=0x14)) { // If all MOB1_RX_8_BYTES were 0x22 values then result_22 == 0.
is mixing a int64_t variable with an integer 0x14 constant. Are you seeing any compiler warnings for this? You may need to typecast the constant to int64_t if the compiler is complaining. At least check it to find out if it is comparing the entire 64 bit variable with a 64 bit 0x14 value. Oops, the comment is wrong now. I think other comments in your code also no longer make sense.
*See the next post for the reason for this edit. |
Last edited by Mike B on Mar 20, 2012 - 06:54 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Mar 20, 2012 - 06:48 PM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
My bad. Without really thinking I assumed you were doing unsigned arthritic.
What I should have said is: “long” is int32_t and “long long” is int64_t. It is actually “unsigned long” is uint32_t and “unsigned long long” is uint64_t. I'm going to change this in the previous post rather than leave wrong info.
If you are expecting unsigned values and declaring signed variables then you will get a nasty bug every time the Most Significant bit of the variable is set.
If you are expecting signed values and declaring unsigned variables then you will get a nasty bug every time the Most Significant bit of the variable is set.
In fact since address was declared as a signed long it was not correct since this is only ever an unsigned value. If your “address = (part_1 + part_2)” code automatically extended the part_1 or part_2 values into a signed negative number since it was targeted at a signed long, your address result would become unusable garbage. Just think of what signed type conversion could do to all those master_result_n values. Yikes!
You need to go back over your variable declarations and make sure you have the correct signed or unsigned variable type. If your address value was getting trashed by sign extension this would be a major bug that killed your code all by itself.
Sorry, I finally woke up and realized I let that slip by. |
|
|
| |
|
|
|
|
|
Posted: Mar 20, 2012 - 10:39 PM |
|

Joined: Feb 23, 2012
Posts: 12
|
|
Well thank you very much for your valued assistance. I finally found the issue that was keeping me from matching ID's.
On page 264 the data sheet goes on to describe that the bits 20:3 on the CANIDT registers are assigned to random values. Because some of these bits are located on the CANIDT2 register, it was keeping my matching if statement from working. Program works successfully so far. Thank you very much for all of your help. |
|
|
| |
|
|
|
|
|
Posted: Mar 21, 2012 - 02:49 AM |
|


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA
|
|
| Thank you for noticing this. I never noticed it in the data sheet partly because 11 bit ID format code like this:
Code:
uint16_t address;
address = ((uint16_t) CANIDT1 << 3) | ((uint16_t) CANIDT2 >> 5);
never picks up any stray reserved bits in the first place. Something like this random bit value should really be included in the errata chapter.
I would still look at the other issues as well, especially the signed vs unsigned stuff. |
|
|
| |
|
|
|
|
|
|
|
|