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)
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));
/* 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;
}
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 {
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);
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;
}
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");
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();
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);
+ }
+}