It takes me several days for debbuging ,but didn't work.
when the para 'timeout' of osMessagePut(id,info,timeout) is not set to 0, then the program crashes with info 'OS_ERROR_MBX_OVF' , which means mailbox overflow. But with timeout setting to 0,everything seems ok.
It really confuses me. Can anyone help me ? Thanks a lot!
The main frame of my program is as follows (it is from mdk example 'CAN_Ex', basically not changed much )
osPoolDef(rlcan_mpool, 80, CAN_msg); osMessageQDef(rlcan_msgq_tx, 20, CAN_msg); /* Thread1, used to send can message */ while(1) { ... /* check if hardware is free for send */ if (CAN_hw_tx_empty (ctrl) == CAN_OK) { CAN_hw_wr (ctrl, msg); /* Send message */ } else { ptrmsg = osPoolAlloc(rlcan_mpool); /* for timeout is not 0, it crashes after ISR getting about 16 messages */ result = osMessagePut(rlcan_msgq_tx, ptrmsg, 10); if (result != osOK) osPoolFree(rlcan_mpool, ptrmsg); } osDelay (500); } /* ISR, interrupt generates after msg sending succeeds */ void CAN0_ORed_Message_buffer_IRQHandler (void) { ... iflag1 = CANc->IFLAG1; //iflag1 will be set if msg sending succeeds while(iflag1) { iflag1 = 0; /* it crashes after getting about 16 messages */ evt = osMessageGet(rlcan_msgq_tx[CTRL0], 0); if (evt.status == osEventMessage) { CAN_hw_wr (CTRL,evt.value.p); /* Send message */ osPoolFree(rlcan_mpool, evt.value.p); } iflag1 = CANc->IFLAG1; //check whether iflag1 is set again } }
The "timeout" arguments specified in the "RTX_CAN.h" and "RTX_CAN.c" for a few functions such as CAN_ERROR CAN_send(); CAN_ERROR CAN_request(); CAN_ERROR CAN_set(); CAN_ERROR CAN_receive() have a wrong data type "uint16_t". They should be "uint32_t". This might be the reason for this issue. Please download the attached example project again via the following link: http://www.keil.com/support/docs/3714.htm This attached example project has just been updated to fix this bug on the 5th of Jun. 15.
Please let me know if this helps. Thx!
Sorry , but it still crashes .
Other info, the MCU is MK64F, and the pc software is Kvaser CanKing.
Perhaps the mailbox is really full.
How often has been a mail retrieved from the mailbox? You can evaluate that by using a counter.
Check also the parameters of the osMail functions. You should always pass the same queue_id to the functions. This seems not the case in your code example that you have provided.
See: www.keil.com/.../group___c_m_s_i_s___r_t_o_s___mail.html
thanks,Reinhard. But I use Message Queue, not mailbox.
Besides, If the queue is still full when time expires, the memory pool will be freed as the following code. And there's just one thread calling the 'osMessagePut' api, and whatever the value of timeout is set (except for '0'),it crashes.
/* for timeout is not 0, it crashes */ result = osMessagePut(rlcan_msgq_tx, ptrmsg, 10); if (result != osOK) { osPoolFree(rlcan_mpool, ptrmsg); }
The only time you can get the error you are describing is when the Post Service Handler Queue gets full. This queue is 16 deep by default. You may change this size, but my guess is the "Real" problem is not the queue depth but some other logic issue. The Post Service Handler Queue fills when you make Mailbox (either osMessage or osMailbox), Semaphore or event calls from an ISR. As long as you stay in an interrupt service routine, this queue will not be emptied. At the point that no more interrupts are pending, this queue is processed.
Sorry, I referred to mail instead of message functions.
Ensure that both functions: osMessageGet and osMessagePut get the same queue_id.
Once this is verified I suggest you trace the calls to both functions (i.e. increment two counters in your application and use the ULINKpro / MDK Logic Analyzer to see how the values progress - or if you prefer a hardware method toggle two different pins and use an oscilloscope).
My guess is that there is something wrong with the CAN peripheral communication.
Thanks! Robert. I find two errors in my program.
One is the fifo queue size being too small in my case. ISR is still running while it reaches the size 16, thus the fifo queue overflow occurs. I set the size to 32 and the first error disappears.
But the other error still exists. The message queue(not the ISR fifo queue) size defined by 'osMessageQDef' is 20, and i'm sure the number of messages put by 'osMessagePut' is exactly 20(osMessagePut is called 20 times,and no osMailPut is called). The strange thing is that 'osMessageGet' returns 'osEventMessage'(showing below ) for 21 times, and the msg contained in evt.value.p is not correct for the last time(the 21st time).
So I changed the 'timout' para of osMessagePut() to '0' again, and osMessageGet() returns 20 times with 'osEventMessage' now.
So I wonder what's happened with 'timout' setting to nonzero when calling osMessagePut()?
void CAN0_ORed_Message_buffer_IRQHandler (void) { ... iflag1 = CANc->IFLAG1; //iflag1 will be set if msg sending succeeds if(iflag1) { iflag1 = 0; evt = osMessageGet(rlcan_msgq_tx[CTRL0], 0); if (evt.status == osEventMessage) { /*it enters here for 21 times, the msg contained in evt.value.p is not correct for the last time */ CAN_hw_wr (CTRL,evt.value.p); /* Send message */ osPoolFree(rlcan_mpool, evt.value.p); } } }
Please refer to this manual to get more details regarding osMessagePut(): www.keil.com/.../group___c_m_s_i_s___r_t_o_s___message.html
Especially this part might be relevant for you: "When the message queue is full, the system retries for a specified time with millisec. While the system retries the thread that is calling this function is put into the state WAITING. The millisec timeout can have the following values:
-> when millisec is 0, the function returns instantly. -> when millisec is set to osWaitForever the function will wait for an infinite time until a message queue slot becomes available. -> all other values specify a time in millisecond for a timeout.
Please Note: The parameter millisec must be 0 for using this function in an ISR."
thanks, Reinhard. the queue id is the same, and the calls to both functions is ok , i'm pretty sure about this, but cannot figure out why osMessageGet is called one more time than osMessagePut as I wrote ahead.
thanks,Chen. I had read the details regarding osMessagePut(). The parameter millisec is indeed 0 for using osMessageGet() in ISR.
And I can see the result of osMessagePut with 'printf', it shows that before entering ISR(where osMessageGet is called), osMessagePut has already returned,as showing below.
I'm really confused now.
/* Thread1, used to send can message */ while(1) { ... /* check if hardware is free for send */ if (CAN_hw_tx_empty (ctrl) == CAN_OK) { CAN_hw_wr (ctrl, msg); /* Send message */ } else { ptrmsg = osPoolAlloc(rlcan_mpool); result = osMessagePut(rlcan_msgq_tx, ptrmsg, 10); if (result != osOK) { osPoolFree(rlcan_mpool, ptrmsg); printf("after osPoolFree"); } } osDelay (500); }
More details, after getting 20 msgs, ie, after osMessageGet() is called for 20 times, the returned value of osMessageGet() is not 'osEventMessage' any more, so it leaves ISR and enters thread1(I didn't call osMessagePut or osMailPut in thread1, neither for other threads ).
Then interrupt occurs, so it enters ISR again , and at this moment, the returned value of osMessageGet() is 'osEventMessage' again! But with timeout setting to 0, everything's ok.
as written in the manual, for both functions osMessagePut and osMessageGet the timeout parameter must be 0 when they are used in ISR.
In your code the timeout for osMessagePut should be 0 not 10.
... result = osMessagePut(rlcan_msgq_tx, ptrmsg, 0); ...
Hi,Chen , osMessagePut is not in ISR, but in thread1 as the comments aside.