From: termitt Date: Fri, 25 Apr 2008 09:24:06 +0000 (+0000) Subject: some minor bug fixes for HCAN2 chip X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/7440c5c6ece06cdf6ea19270047cca22b324d73a some minor bug fixes for HCAN2 chip --- diff --git a/lincan/Makefile.omk b/lincan/Makefile.omk index d43b19d..f268924 100644 --- a/lincan/Makefile.omk +++ b/lincan/Makefile.omk @@ -1,2 +1,2 @@ -SUBDIRS = src utils +SUBDIRS = src diff --git a/lincan/include/hcan2.h b/lincan/include/hcan2.h index 2e5b6ef..22c1458 100644 --- a/lincan/include/hcan2.h +++ b/lincan/include/hcan2.h @@ -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); diff --git a/lincan/src/hcan2.c b/lincan/src/hcan2.c index 96b1043..a31490f 100644 --- a/lincan/src/hcan2.c +++ b/lincan/src/hcan2.c @@ -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<max_objects) && !(rxdf & (1<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<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); + } +}