some minor bug fixes for HCAN2 chip
authortermitt <termitt>
Fri, 25 Apr 2008 09:24:06 +0000 (09:24 +0000)
committertermitt <termitt>
Fri, 25 Apr 2008 09:24:06 +0000 (09:24 +0000)
lincan/Makefile.omk
lincan/include/hcan2.h
lincan/src/hcan2.c

index d43b19d..f268924 100644 (file)
@@ -1,2 +1,2 @@
-SUBDIRS = src utils
+SUBDIRS = src
 
index 2e5b6ef..22c1458 100644 (file)
@@ -30,6 +30,7 @@ int hcan2_config_irqs(struct canchip_t *chip, short irqs);
 
 int hcan2_clear_objects(struct canchip_t *chip);
 int hcan2_check_tx_stat(struct canchip_t *chip);
+int hcan2_check_MB_tx_stat(struct canchip_t *chip, struct msgobj_t *obj);
 int hcan2_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj);
 int hcan2_filtch_rq(struct canchip_t *chip, struct msgobj_t * obj);
 
index 96b1043..a31490f 100644 (file)
@@ -32,12 +32,15 @@ void hcan2_setup_mbox4read(struct msgobj_t * obj);
 void hcan2_setup_ctrl_regs(struct canmsg_t * msg, uint16_t * ctrl0, uint16_t * ctrl1, uint16_t * ctrl2);
 
 int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg);
-
+void hcan2_notifyRXends(struct msgobj_t * obj, int what);
 /* Enable folowing IRQs
  * HCAN2_IRR_DFRI = Data Frame Received Interrupt Flag
  * HCAN2_IRR_MBEI = Mailbox Empty Interrupt Flag
+ *
+ * and Errors:
+ * Bus Off, Error Passive, Message Overrun/Overwrite
  */
-uint16_t IRQs = ~(HCAN2_IRR_DFRI + HCAN2_IRR_MBEI);
+uint16_t IRQs = ~(HCAN2_IRR_DFRI + HCAN2_IRR_MBEI + HCAN2_IRR_BOI + HCAN2_IRR_EPI + HCAN2_IRR_MOOI);
 /* 1 - mask interrupt, 0 - interrupt not masked */
 
 int hcan2_chip_config(struct canchip_t *chip)
@@ -397,7 +400,6 @@ int hcan2_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct
 int hcan2_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg)
 {
        unsigned obj_bit;
-       int i;
        int b_addr = ((obj->object - 1) / 16) * (-2); 
 
        obj_bit = (1 << ((obj->object - 1) % 16));
@@ -405,17 +407,7 @@ int hcan2_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t
 /*     CANMSG("Sending message [obj: %d]\n", obj->object - 1); */
 
        can_write_reg_w(chip, obj_bit, b_addr + HCAN2_TXPR0);
-                       
-       /* Waits until chip sends message */
-       i = 0;
-       while (hcan2_check_tx_stat(chip) && ((i++) <= MAX_TRANSMIT_WAIT_LOOPS))
-           udelay(200);
 
-       if (i >= MAX_TRANSMIT_WAIT_LOOPS) {
-               CANMSG("Failed while waiting for Transmitt finished\n");
-               return -ENODEV;
-       }
-       
 /*     CANMSG("Message sent [obj: %d]\n", obj->object - 1); */
        return 0;
 }
@@ -432,11 +424,25 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
        uint16_t irq_reg, idx;
        short loop_cnt = MAX_IRQ_WAIT_LOOPS;
        uint32_t rxdf, txdf;
-       struct msgobj_t * obj;
+
+/*
+       HCAN2_IRR_TCMI  - Time Compare Match Register
+       HCAN2_IRR_TOI   - Time Overrun Interrupt
+       HCAN2_IRR_WUBA  - Wake-up on Bus Activity
+       HCAN2_IRR_MOOI  - Message Overrun/Overwrite Interrupt Flag
+       HCAN2_IRR_MBEI  - Messagebox Empty Interrupt Flag
+       HCAN2_IRR_OF    - Overload Frame
+       HCAN2_IRR_BOI   - Bus Off Interrupt Flag
+       HCAN2_IRR_EPI   - Error Passive Interrupt Flag
+       HCAN2_IRR_ROWI  - Receive Overload Warning Interrupt Flag
+       HCAN2_IRR_TOWI  - Transmit Overload Warining Interrupt Flag
+       HCAN2_IRR_RFRI  - Remote Frame Request Interrupt Flag
+       HCAN2_IRR_DFRI  - Data Frame Received Interrupt Flag
+       HCAN2_IRR_RHSI  - Reset/Halt/Sleep Interrupt Flag */
 
        irq_reg = can_read_reg_w(chip, HCAN2_IRR);
        DEBUGMSG("irq: %d, chip base addr: 0x%08x\n", irq, (uint32_t)chip->chip_base_addr);
-/*     DEBUGMSG("IRQ Handler: HCAN2_IRR: 0x%04x\n", irq_reg); */
+       DEBUGMSG("IRQ Handler: HCAN2_IRR: 0x%04x\n", irq_reg); //*/
 
        do {
 
@@ -445,37 +451,86 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
                        return CANCHIP_IRQ_STUCK;
                }
 
+               /* Received message */
                if (irq_reg & HCAN2_IRR_DFRI)
-               {       /* Received message */
+               {
                        rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
                            can_read_reg_w(chip, HCAN2_RXPR0);
 
                        DEBUGMSG("Received message [0x%08x]\n", rxdf);
 
                        while (rxdf) {
-                           /* find the message object */
-                           for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<<idx)); idx++) { }
+                               /* find the message object */
+                               for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<<idx)); idx++) { }
+                               
+                               /* realy i got one? */
+                               if (idx < chip->max_objects) {
+                                       hcan2_irq_read_handler(chip, chip->msgobj[idx]);
+                               
+                                       /* clear RXPR flag for this msgobj */
+                                       can_write_reg_w(chip, (1 << (idx % 16)), HCAN2_RXPR0 - 2*(idx / 16));
+                                       
+                                       rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
+                                       can_read_reg_w(chip, HCAN2_RXPR0);
+                               }
+                       }
+               }
 
-                           /* realy i got one? */
-                           if (idx < chip->max_objects)
-                               hcan2_irq_read_handler(chip, chip->msgobj[idx]);
-                           else
-                               break;
+               /* Error: Bus Off */
+               if (irq_reg & HCAN2_IRR_BOI) {
+                       CANMSG("Error: entering BUS OFF state\nstatus register: 0x%02x irq register: 0x%02x\n",
+                               can_read_reg_w(chip, HCAN2_GSR), irq_reg);
+
+                       /* notify all RX/TX ends */
+                       for (idx = 0; idx < chip->max_objects; idx++) {
+                               /* notify TX */
+                               chip->msgobj[idx]->ret=-1;
+                               if(chip->msgobj[idx]->tx_slot)
+                                       canque_notify_inends(chip->msgobj[idx]->tx_qedge,
+                                               CANQUEUE_NOTIFY_ERROR);
+                               /* notify RX */
+                               hcan2_notifyRXends(chip->msgobj[idx], CANQUEUE_NOTIFY_ERROR);
+                       }
 
-                           /* clear RXPR flag for this msgobj */
-                           can_write_reg_w(chip, (1 << (idx % 16)), HCAN2_RXPR0 - 2*(idx / 16));
+                       /* reset flag - by writing '1' */
+                       can_write_reg_w(chip, HCAN2_IRR_BOI, HCAN2_IRR);
+               }
 
-                           rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
-                               can_read_reg_w(chip, HCAN2_RXPR0);
-                       }
-                           
-                   /* reset HCAN2_IRR_DFRI flag */
-                   can_write_reg_w(chip, irq_reg & ~HCAN2_IRR_DFRI, HCAN2_IRR);
+               /* Warning: Error Passive */
+               if (irq_reg & HCAN2_IRR_EPI) {
+                       uint16_t tecrec;
+                       tecrec = can_read_reg_w(chip, HCAN2_TECREC);
+
+                       CANMSG("Warning: entering ERROR PASSIVE state\nTEC: %d REC: %d\n",
+                               (uint16_t)((tecrec >> 8) & 0x00ff), (uint16_t)(tecrec & 0x00ff));
+                       
+                       /* Show warning only */
+
+                       /* reset flag - by writing '1' */
+                       can_write_reg_w(chip, HCAN2_IRR_EPI, HCAN2_IRR);
                }
 
-               if (irq_reg & (HCAN2_IRR_MBEI))
+               /* Message Overrun/Overwritten */
+               if (irq_reg & HCAN2_IRR_MOOI) { 
+                       /* put get Unread Message Status Register */
+                       rxdf =  (can_read_reg_w(chip, HCAN2_UMSR1) << 16) + can_read_reg_w(chip, HCAN2_UMSR0);
+
+                       /* find the message object */
+                       for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<<idx)); idx++) { }
+                       
+                       CANMSG("Error: MESSAGE OVERRUN/OVERWRITTEN [MB: %d]\n",idx);
+                       
+                       /* notify only injured RXqueue-end */
+                       if (idx < chip->max_objects) 
+                               hcan2_notifyRXends(chip->msgobj[idx], CANQUEUE_NOTIFY_ERROR);
+
+                       /* reset flag */
+                       can_write_reg_w(chip, (1 << (idx % 16)), HCAN2_UMSR0 - 2 * (idx / 16));
+               }
+
+               /* Mailbox empty - after message was sent */
+               if (irq_reg & HCAN2_IRR_MBEI)
                {
-                   /* Mailbox empty - after message was sent */
                    txdf = (can_read_reg_w(chip, HCAN2_TXACK1) << 16) +
                        can_read_reg_w(chip, HCAN2_TXACK0);
 
@@ -489,21 +544,16 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
                        can_write_reg_w(chip, 0xffff, HCAN2_ABACK1);
                        return CANCHIP_IRQ_HANDLED;
                    } 
-                   
-                   obj = chip->msgobj[idx];
 
                    /* Clear TXACK flag */                  
                    can_write_reg_w(chip, 1 << (idx % 16), HCAN2_TXACK0 - 2 * (idx / 16));
 
                    /* sends message */     
-                   hcan2_wakeup_tx(chip, obj);
+                   hcan2_wakeup_tx(chip, chip->msgobj[idx]);
                }
 
-               irq_reg=can_read_reg_w(chip, HCAN2_IRR);
-       } while(irq_reg & (HCAN2_IRR_MBEI | HCAN2_IRR_DFRI));
-
-       /* reset ALL tinterrupt flags */
-       can_write_reg_w(chip, irq_reg, HCAN2_IRR);
+               irq_reg = can_read_reg_w(chip, HCAN2_IRR);
+       } while(irq_reg & ~IRQs);
 
        return CANCHIP_IRQ_HANDLED;
 }
@@ -549,6 +599,19 @@ int hcan2_check_tx_stat(struct canchip_t *chip)
                return 1;
 }
 
+/* Note: this checks TX status of concrete messagebox */
+int hcan2_check_MB_tx_stat(struct canchip_t *chip, struct msgobj_t *obj)
+{
+       /* Transmition is complete return 0 - no error */
+       
+       /* MB1-MB15 are in CANTXPR0 and MB16-MB31 are in CANTXPR1
+          CANTXPR0 = CANTXPR1 + 0x0002
+          MB0 - receive only */
+
+       char id = obj->object - 1;
+       return (can_read_reg_w(chip, HCAN2_TXPR0 - 2 * (id / 16)) & (1 << (id & 0x00ff)));
+}
+
 int hcan2_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
 {
        DEBUGMSG("WakeUP TX\n");
@@ -559,14 +622,18 @@ int hcan2_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
        can_preempt_disable();
        
        can_msgobj_set_fl(obj,TX_REQUEST);
-       while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+       if(!can_msgobj_test_and_set_fl(obj,TX_LOCK) &&
+               !hcan2_check_MB_tx_stat(chip, obj))
+       {       /* enable transmition only if MB is empty */
                can_msgobj_clear_fl(obj,TX_REQUEST);
 
                hcan2_irq_write_handler(chip, obj);
        
                can_msgobj_clear_fl(obj,TX_LOCK);
-               if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
        }
+       else
+               can_msgobj_clear_fl(obj,TX_REQUEST);
+
 
        can_preempt_enable();
 
@@ -989,3 +1056,10 @@ int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg)
 
        return ((ctrl0 ^ c0) || (ctrl2 ^ c2));
 }
+
+void hcan2_notifyRXends(struct msgobj_t * obj, int what){
+       struct canque_edge_t * edge;
+       canque_for_each_inedge(obj->qends, edge){
+               canque_notify_outends(edge, what);
+       }
+}