can_rx.c

00001 #include <includes.h>
00002 
00003 CAN_FRAME_DESC   ** can_rx_descriptors;
00004 CAN_FRAME_DESC   ** can_rx_rtr_descriptors;
00005 CAN_RX_CHAN_CFG     can_rx_chan_cfgs[5];
00006 
00007 extern unsigned long can_elapsed_ms;   // CAN module time variable
00008 
00009 // CAN receive frame count global variables:
00010 volatile unsigned short can_rx_frame_count_1 = 0;
00011 volatile unsigned short can_rx_frame_count_2 = 0;
00012 volatile unsigned short can_rx_frame_count_3 = 0;
00013 volatile unsigned short can_rx_frame_count_4 = 0;
00014 
00015 unsigned short can_rx_get_frame_count_1(CAN_FRAME * frame)
00016 {
00017   frame->payload.w.w1 = can_rx_frame_count_1;
00018   can_rx_frame_count_1 = 0;     //Reset frame counter - could lose a count here, but not critical
00019   frame->payload.w.w2 = can_elapsed_ms;
00020   return 0;
00021 }
00022 
00023 unsigned short can_rx_get_frame_count_2(CAN_FRAME * frame)
00024 {
00025   frame->payload.w.w1 = can_rx_frame_count_2;
00026   can_rx_frame_count_2 = 0;     //Reset frame counter - could lose a count here, but not critical
00027   frame->payload.w.w2 = can_elapsed_ms;
00028   return 0;
00029 }
00030 
00031 unsigned short can_rx_get_frame_count_3(CAN_FRAME * frame)
00032 {
00033   frame->payload.w.w1 = can_rx_frame_count_3;
00034   can_rx_frame_count_3 = 0;     //Reset frame counter - could lose a count here, but not critical
00035   frame->payload.w.w2 = can_elapsed_ms;
00036   return 0;
00037 }
00038 
00039 unsigned short can_rx_get_frame_count_4(CAN_FRAME * frame)
00040 {
00041   frame->payload.w.w1 = can_rx_frame_count_4;
00042   can_rx_frame_count_4 = 0;     //Reset frame counter - could lose a count here, but not critical
00043   frame->payload.w.w2 = can_elapsed_ms;
00044   return 0;
00045 }
00046 
00047 void can_rx_set_descriptors(CAN_FRAME_DESC ** rx_descriptors,CAN_FRAME_DESC ** rtr_descriptors){
00048   can_rx_descriptors     = rx_descriptors;
00049   can_rx_rtr_descriptors = rtr_descriptors;
00050 //  can_rx_acceptance_filter_init();  Put acceptance filter config here? And RTR-subscribe? Or keep it separate in software_setup.c?
00051 }
00052 
00053 void can_rx_set_chan_cfg(CAN_CHANNEL chan,volatile unsigned long * base_addr, CAN_RING * rx_ring, CAN_DISPATCH_MODE mode){
00054   CAN_RX_CHAN_CFG * cfg = &can_rx_chan_cfgs[chan];
00055   
00056   cfg->base_addr     = base_addr;
00057   cfg->dispatch_mode = mode;
00058   cfg->ring          = rx_ring; 
00059 }
00060 
00062 // Obtain CAN_IDs and channel numbers from NULL-terminated receive CAN descriptor list
00063 // Put into acceptance filter RAM for LPC21xx MCU and sort.
00064 // Channel numbering used starts at 1 (some ambiguity here in the MCU user manual)
00065 // Each listing should have a unique CAN_ID/CAN controller number combination.
00066 // During initialization, the CAN acceptance filter is put into bypass mode, then into
00067 // operation mode.
00068 void can_rx_acceptance_filter_init(void)
00069 {
00070   unsigned short i, j, high_id;
00071   unsigned long addr, chan, test_value;
00072   CAN_FRAME_DESC  * frame_desc = 0;
00073   volatile unsigned long * afram_ptr = &AFRAM;
00074   
00075   // Set to bypass mode before modifying acceptance filter registers and RAM
00076   AFMR = 
00077       (0 << 0)    // Set acceptance filter to off
00078     | (1 << 1)    // Set acceptance filter to bypass mode
00079     | (0 << 2);   // FullCAN is off
00080     
00081  
00082   // Add CAN_IDs and channel numbers to acceptance filter RAM
00083   // (In whatever order the rx frame descriptors are in)
00084   i = 0;
00085   j = 0;
00086   high_id = 0;
00087   while(1)
00088   {
00089     frame_desc = can_rx_descriptors[i];
00090     
00091     if (frame_desc != NULL)
00092     {
00093       if (!high_id)
00094       {
00095         addr = frame_desc->addr;
00096         chan = frame_desc->chan;
00097         
00098         afram_ptr[j] = (addr << 16) | (chan - 1) << 29; // Add lower-index CAN_ID and channel number
00099         high_id = 1;                                    // Wait for next iteration for higher-value CAN_ID
00100       }
00101       else  //high_id
00102       {
00103         addr = frame_desc->addr;
00104         chan = frame_desc->chan;
00105        
00106         afram_ptr[j] |= (addr | ((chan - 1) << 13));           // Add higher-index CAN_ID and channel number
00107         ++j;                                             // Increment AFRAM address index
00108         if (j >= 0x200)
00109         {
00110           //AFRAM is full. Could add code to give an error if it was also not the last CAN_ID in the list.
00111           break;
00112         }
00113         high_id = 0;                                // Start again with the low id
00114       }
00115       ++i;        // increment the descriptors counter
00116     }
00117     else if ((frame_desc == 0) && (i == 0)) // handle case of empty list 
00118     {
00119       break;
00120     }
00121     else  //End of list
00122     {
00123       if (high_id)
00124       {
00125         afram_ptr[j] |= 0x67FF; // Add dummy higher-value CAN_ID. This is the highest value possible if up to 4 CAN supported
00126         j++;                    // Finish with j pointing to AFRAM location above table.          
00127       }
00128       break;
00129     }    
00130   }
00131   
00132   // Modified bubble sort of the AFRAM entries; they need to be in ascending order, including both channel and id.
00133   // Count up until reaching a pair of values out of order, then switch them and start again from 0.
00134   // Stop when the end of the list is reached with no pairs out of order.
00135   i = 0;
00136   while (1)
00137   {
00138     test_value = 0xFFFF & (afram_ptr[i >> 1] >> ((~i & 1) << 4));
00139     if (((i+1) >> 1) >= j)
00140     {
00141       break;  //sorting done
00142     }
00143     else if (test_value > (0xFFFF & (afram_ptr[(i+1) >> 1] >> ((~(i+1) & 1) << 4))))
00144     {
00145       // Pair is out of order, swap values
00146       if (i & 1)  // i is odd and i+1 is even - swap adjacent 16-bit words of successive 32-bit words
00147       {
00148         afram_ptr[i >> 1] &= 0xFFFF0000;      // Clear bottom 16 bits of lower 32-bit AFRAM word
00149         afram_ptr[i >> 1] |=  afram_ptr[(i+1) >> 1] >> 16;  // Move the upper 16 bits of the upper 32-bit AFRAM word
00150                                                             // down by 16, then move to the lower 32-bit AFRAM word
00151         afram_ptr[(i+1) >> 1] &= 0xFFFF;      // Clear top 16 bits of upper 32-bit AFRAM word
00152         afram_ptr[(i+1) >> 1] |= (test_value << 16);      // Move bottom 16 bits of lower 32-bit AFRAM word to the top 16
00153                                                     // bits of the upper AFRAM word.
00154         
00155       }
00156       else    // i is even and i+1 is odd - swap 16-bit words in same 32-bit word
00157       {
00158         afram_ptr[i >> 1] <<= 16;         // Move low-ID halfword to upper 16 bits
00159         afram_ptr[i >> 1] |= test_value;  // Move the high-ID halfword into the lower 16 bits
00160       } 
00161       i = 0;  // search from start of array again
00162     }
00163     else if (test_value == (0xFFFF & (afram_ptr[(i+1) >> 1] >> (((i+1) & 1) << 4))))
00164     {
00165       //error - no two IDs should be identical. Annoying to clean up this case, however. For later if needed.
00166       ++i;  // give error message and ignore. Some IDs may not work
00167     }
00168     else
00169     {
00170       ++i;  // not out of order yet - increment and check next pair
00171     }
00172   }
00173   
00174   
00175   SFF_sa = 0;    //Set start index of standard individual identifiers in acceptance filter RAM
00176   
00177   SFF_GRP_sa = j << 2; //Set start index of standard group identifiers; also indicates end of preceding section
00178   
00179   EFF_sa = SFF_GRP_sa;     //Set start index of extended individual identifiers; also indicates end of preceding section
00180   
00181   EFF_GRP_sa = SFF_GRP_sa; //Set start index of extended group identifiers; also indicates end of preceding section
00182   
00183   ENDofTable = SFF_GRP_sa; //Address after last active element of acceptance filter. Max is 0x800.
00184     
00185   // Activate acceptance filter, once setup is done
00186   AFMR = 
00187       (0 << 0)    // Set acceptance filter to on
00188     | (0 << 1)    // Set acceptance filter to normal mode
00189     | (0 << 2);   // FullCAN is off
00190     
00191 }
00193 
00195 void can_rx_now(CAN_CHANNEL chan){
00196   CAN_RX_CHAN_CFG        * cfg;
00197   volatile unsigned long * base;
00198   CAN_FRAME                frame;
00199 
00200   cfg   = &can_rx_chan_cfgs[chan];
00201   base  = cfg->base_addr;
00202     
00203   if(base == NULL) {
00204     C1CMR = 1<<2;
00205     C2CMR = 1<<2;
00206     C3CMR = 1<<2;
00207     C4CMR = 1<<2;
00208   } else {
00209     frame.chan            = chan;
00210     frame.addr            = CAN_REG(base,CAN_RID);
00211     frame.dlc             = (CAN_REG(base,CAN_RFS)>>16)&0xF;
00212     frame.rtr             = (CAN_REG(base,CAN_RFS)>>30)&0x1;
00213     frame.payload.w.w1    = CAN_REG(base,CAN_RDA);
00214     frame.payload.w.w2    = CAN_REG(base,CAN_RDB); 
00215     CAN_REG(base,CAN_CMR) = 1<<2; //Release data 
00216 
00217     if (cfg->dispatch_mode == CAN_DISPATCH_MANUAL) {
00218       can_ring_push(cfg->ring,&frame);
00219     } else {//CAN_DISPATCH_AUTO
00220       can_rx_dispatch_frame(&frame);
00221     }
00222   }
00223 }
00224 
00225 void can_rx_dispatch_frame(CAN_FRAME * frame){
00226   CAN_FRAME_DESC  * frame_desc = 0;
00227   CAN_LAYOUT        layout;
00228   int               expected_dlc;
00229   int               i;
00230   CAN_FRAME_DESC ** search_list;
00231   
00232   search_list = (frame->rtr) ? can_rx_rtr_descriptors : can_rx_descriptors;
00233   
00234   if(search_list == NULL) {
00235     return; //Error, list not valid.
00236   }
00237   
00238   i = 0;
00239   while(1){
00240     frame_desc = search_list[i];
00241     if((frame_desc == 0) ||                               //if we have reached the end of the rx descriptor list, or
00242       ((frame_desc->addr&0x7FF) == (frame->addr&0x7FF))) {//if we have found an address match
00243       break;
00244     }
00245     i++;
00246   }
00247 
00248   if(frame_desc == 0) {
00249     //Throw error.  This shouldn't have gotten through the acceptance filter
00250     return;
00251   }
00252   //frame_desc points now to the descriptor for the received frame
00253 
00254   //now, verify that the correct data length field value has been received  
00255   layout = frame_desc->frame_layout;
00256 
00257   if(frame->rtr) {
00258     expected_dlc = 0;
00259   } else {
00260     switch(layout){
00261       case CAN_LAYOUT_D:
00262       case CAN_LAYOUT_FF:
00263       case CAN_LAYOUT_II:
00264       case CAN_LAYOUT_FI:
00265       case CAN_LAYOUT_ISS:
00266         expected_dlc =  8;
00267         break;
00268       default:
00269         //this packet uses an unrecognized layout
00270         expected_dlc = -1;
00271         break;
00272     };
00273   }
00274   if(expected_dlc == -1){
00275     //handle unrecognized frame layout exception
00276     return;
00277   }
00278   if((expected_dlc == 8) &&(frame->dlc < 8) ||
00279      (expected_dlc != frame->dlc)) {
00280     //handle dlc mismatch exception
00281     return;
00282   }
00283 
00284   //dispatch payload contents per frame layout based on frame descriptor
00285   if(frame->rtr == 0){
00286     switch(layout){
00287       case CAN_LAYOUT_D:
00288         ((CAN_RX_SETTER_DOUBLE)frame_desc->ptr1)(frame->payload.d.d1);
00289         break;
00290       case CAN_LAYOUT_FF:
00291         ((CAN_RX_SETTER_FLOAT)frame_desc->ptr1)(frame->payload.f.f1);
00292         ((CAN_RX_SETTER_FLOAT)frame_desc->ptr2)(frame->payload.f.f2);
00293         break;
00294       case CAN_LAYOUT_II:
00295         ((CAN_RX_SETTER_INT)frame_desc->ptr1)(frame->payload.i.i1);
00296         ((CAN_RX_SETTER_INT)frame_desc->ptr2)(frame->payload.i.i2);
00297         break;
00298       case CAN_LAYOUT_FI:
00299         ((CAN_RX_SETTER_FLOAT)frame_desc->ptr1)(frame->payload.f.f1);
00300         ((CAN_RX_SETTER_INT)  frame_desc->ptr2)(frame->payload.i.i2);
00301         break;
00302       case CAN_LAYOUT_ISS:
00303         ((CAN_RX_SETTER_INT  )frame_desc->ptr1)(frame->payload.i.i1);
00304         ((CAN_RX_SETTER_SHORT)frame_desc->ptr2)(frame->payload.s.s3);
00305         ((CAN_RX_SETTER_SHORT)frame_desc->ptr3)(frame->payload.s.s4);   
00306         break;    
00307       default:
00308         //this packet uses an unrecognized layout, throw an error
00309         break;
00310     };
00311   } else {
00312     can_transmit(frame_desc);
00313   }
00314   //YAY!!!
00315   //Now we're done, this frame has been fully dispatched!
00316 }
00317 /*
00318 //Sends out all receive packets as RTR over the CAN bus
00319 void can_subscribe_rtr(void){
00320   int i;
00321   for (i = 0; can_rx_descriptors[i] != 0; i++){
00322     can_subscribe(can_rx_descriptors[i]);
00323   }
00324 }
00325 
00326 //Sends the next CAN descriptor in the list out as rtr
00327 //returns 0 on success, 1 if done sending out all packets
00328 int can_send_next_rtr(void){
00329   static int i = 0;
00330   CAN_FRAME_DESC * next = can_rx_descriptors[i];
00331   if (next != 0){
00332     can_subscribe(next);
00333     i++;
00334     return 0;
00335   } else {
00336     i = 0;
00337     return 1;
00338   }
00339 }
00340 */
Generated on Tue Jun 29 16:36:14 2010 by  doxygen 1.6.3