Hi everybody
I use SAM7x512 and RL-ARM OS. here, OS has 7 tasks and one of them is for CAN receiver. OS_TICK is 1000 and OS_STKSIZE is 1024. and 500000 is my CAN baudrate(my board is just receiver and transmitter is a KVASER PCI CAN Interface).
speed of data transmission is my problem.
when for example transmitter side of CAN bus send a packet per 10ms or more there is know any problem but when I try to increase the speed after some packet (about 200 messages or more) I will get OS_ERR_FIFO_OVF in os_error function. but when I disable the CAN task all other task are working as well.
note: When the system is getting crash and doesn't do any tasks but it's not in os_error function in debug mode with ulink2 sometimes task of CAN in "RTX task and system" -> "stack load" shows "under flow" and after that it calls os_error (in usual states it's about 3% of stack usage)
I tried such works:
1. increase OS_STKSIZE 2. increase OS_FIFOSZ 3. increase CAN_No_ReceiveObjects 4. chaning the OS_TICK
but nothing happened
Does anyone know what I should do?
Hi I've used exactly CAN_SAM7X.c which is in keil examples here is the CAN IRQ ISR:
static void CAN_IRQHandler (void) __irq { U32 ch; CAN_msg *ptrmsg; struct _AT91S_CAN_MB *MailBox; U32 i, int_status, int_ch, int_mask; int_mask = CAN_PTR->CAN_IMR; CAN_PTR->CAN_IDR = 0xFF; /* Disable CAN interrupts */ int_status = CAN_PTR->CAN_SR & int_mask; int_ch = int_status & tx_mailboxes; if (int_ch) { /* Transmission interrupt occured */ tx_mailboxes &= ~int_ch; /* Tx on channel is inactive */ int_mask &= ~int_ch; /* Clear interrupt mask for Tx */ i = 1; for (ch = 1; ch < MAX_OBJ+1; ch++) { /* Find mailbox that caused Tx int */ if (int_ch & i) break; i <<= 1; } MailBox = table_mailbox_addr[ch-1]; /* Mailbox address */ MailBox->CAN_MB_MMR=AT91C_CAN_MOT_DIS;/* Disable mailbox until next write*/ /* If there is a message in the mailbox ready for send, read the message from the mailbox and send it */ if (isr_mbx_receive (MBX_tx_ctrl[CTRL0], (void **)&ptrmsg) != OS_R_OK) { CAN_hw_wr (CTRL, ptrmsg); _free_box(CAN_mpool, ptrmsg); } else { isr_sem_send(wr_sem[CTRL0]); /* Return a token back to semaphore*/ } } int_ch = int_status & rx_mailboxes; if (int_ch) { /* Reception interrupt occured */ i = 1; for (ch = 1; ch < MAX_OBJ+1; ch++) { /* Read all pending received msgs */ if (int_ch & i) { MailBox = table_mailbox_addr[ch-1]; /* Mailbox address */ /* If the mailbox isn't full read the message from the hardware and send it to the message queue */ if (os_mbx_check (MBX_rx_ctrl[CTRL0]) > 0) { ptrmsg = _alloc_box (CAN_mpool); if (ptrmsg) CAN_hw_rd (CTRL, ch, ptrmsg); /* Read received msg */ MailBox->CAN_MB_MCR = AT91C_CAN_MTCR; /* release mailbox */ if (ptrmsg) isr_mbx_send (MBX_rx_ctrl[CTRL0], ptrmsg); } } i <<= 1; } } CAN_PTR->CAN_IER = int_mask; /* Enable CAN interrupt*/ AT91C_BASE_AIC->AIC_ICCR = CAN_INT_CLR; /* Clear interrupt flag*/ AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_AIC->AIC_EOICR; /* End of interrupt*/ }
then to process the data in separated task I made it in this way:
U32 ch; CAN_msg *ptrmsg; struct _AT91S_CAN_MB *MailBox; U32 i, int_status, int_ch, int_mask; void CAN_process(void) { while (1) { os_evt_wait_or (0x0001, 0xffff); // Wait until ISR triggers an event if (int_ch) { /* Transmission interrupt occured */ tx_mailboxes &= ~int_ch; /* Tx on channel is inactive */ int_mask &= ~int_ch; /* Clear interrupt mask for Tx */ i = 1; for (ch = 1; ch < MAX_OBJ+1; ch++) { /* Find mailbox that caused Tx int */ if (int_ch & i) break; i <<= 1; } MailBox = table_mailbox_addr[ch-1]; /* Mailbox address */ MailBox->CAN_MB_MMR=AT91C_CAN_MOT_DIS;/* Disable mailbox until next write*/ /* If there is a message in the mailbox ready for send, read the message from the mailbox and send it */ if (isr_mbx_receive (MBX_tx_ctrl[CTRL0], (void **)&ptrmsg) != OS_R_OK) { CAN_hw_wr (CTRL, ptrmsg); _free_box(CAN_mpool, ptrmsg); } else { isr_sem_send(wr_sem[CTRL0]); /* Return a token back to semaphore*/ } } int_ch = int_status & rx_mailboxes; if (int_ch) { /* Reception interrupt occured */ i = 1; for (ch = 1; ch < MAX_OBJ+1; ch++) { /* Read all pending received msgs */ if (int_ch & i) { MailBox = table_mailbox_addr[ch-1]; /* Mailbox address */ /* If the mailbox isn't full read the message from the hardware and send it to the message queue */ if (os_mbx_check (MBX_rx_ctrl[CTRL0]) > 0) { ptrmsg = _alloc_box (CAN_mpool); if (ptrmsg) CAN_hw_rd (CTRL, ch, ptrmsg); /* Read received msg */ MailBox->CAN_MB_MCR = AT91C_CAN_MTCR; /* release mailbox */ if (ptrmsg) isr_mbx_send (MBX_rx_ctrl[CTRL0], ptrmsg); } } i <<= 1; } } } } static void CAN_IRQHandler (void) __irq { int_mask = CAN_PTR->CAN_IMR; CAN_PTR->CAN_IDR = 0xFF; /* Disable CAN interrupts */ int_status = CAN_PTR->CAN_SR & int_mask; int_ch = int_status & tx_mailboxes; isr_evt_set (0x0001, CAN_process_TID); CAN_PTR->CAN_IER = int_mask; /* Enable CAN interrupt*/ AT91C_BASE_AIC->AIC_ICCR = CAN_INT_CLR; /* Clear interrupt flag*/ AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_AIC->AIC_EOICR; /* End of interrupt*/ }
maybe I should do something else in IRQ ...
and the connection of CAN, here is just for receiving data and I don't have send routine.
note: I tried to fully disable CAN peripheral in Ethernet IRQ. note: when I increased the fifo size of OS, about 1 to 3 minutes I can receive data (1 message per 1ms) and after that program will call os_error with error code=2 (fifo ovf) and sometimes the program will call PAbt_Handler or hardly ever DAbt_Handler. (these two handlers maybe due to fifo ovf but they occur rarely)
another question: when the transmitter side before lunching my device send messages, program will crash on os_sem_init (wr_sem[ctrl0], 1); in CAN_init function. how can I prevent it?
I have question a lot, excuse me
thanks again for your responses
Hi about that part of my code in previous post (with isr_evt_set) when I was debugging I found that the program never pass "os_evt_wait_or (0x0001, 0xffff)" (the program has called isr_evt_set but nothing happened after that)
what's wrong with it?
Hi
after a long while I could found what the problem was.
* Try to speed up general interrupt handling.
as you can see in my sample code (2 messages before) the developer of that code has used mailbox to send a new packet to can_receive fuction and can_receive function use mailbox wait to get a new message through OS mailbox
here I try to omit it and instead, referesh a global variable and flag to be aware in main routine that new message has been received
everything is OK without any OVF on FIFO; dAbt and pAbt
I think because the number of intterupts in Ethernet and CAN are too high the only way to cope such a problem is just speed up my ISR routine as Tamir Michael said.
thanks again
well done
I'm not sure I agree with your analysis. Yes, interrupts should always be as fast as possible. And they should clear out the data and leave the hardware in a stable state. You just may not get your queues full and leave data still in the hardware.
Another issue the ISR makes use of os_mbx_check() instead of isr_mbx_check().