Hello,
I'm developing a project with MKL25Z128 and I'm making some tests with LPSCI, using "fsl_lpsci" Processor Expert bean, but I have run into some problems:
I created a simple routine: I receive a character typed on a Windows Terminal like Tera Term, for example, and send back (echo) to the Terminal.
When the rx_buffer full Callback function is enabled, as well as the ISR Handler, I don't receive any data typed from Terminal. I put a breakpoint inside ISR_Handler after SCI Receiver Buffer Full flag checking line, but it doesn't stop there. When Rx_Callback function and ISR Handler are disabled, it works perfectly.
I don't know if I did something wrong. I have spent many hours of attempts strugling on that.
I hope someone has faced the problem as mine and can help me with that.
I attach my simple code for better visualization.
Thanks and best regards,
Marco Coelho
Original Attachment has been moved to: teste_uart_kl25.zip
Hi Marco Coelho,
How about implement callback as below:
void lpsciCom1_RxCallback(uint32_t instance, void * uartState)
{
/* Write your code here ... */
++((lpsci_state_t *)uartState)->txBuff;
--((lpsci_state_t *)uartState)->txSize;
}
Hope that helps,
Have a great day,
Kan
Freescale Technical Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hello, Kan
It is working now. I was suspicious about the "LPSCI_HAL_Getchar" function call in "LPSCI_DRV_IRQHandler". As said in my last message, whenever this function is called, it hangs, untill falls into a "Default_ISR".
I confirmed what I suspected, when I simply commented this function call and inserted the following code in place:
"lpsciState->rxBuff = UART0_D;"
In other words, I included exactly the same line that is inside "LPSCI_HAL_Getchar" function.
So, there may be a kind of strange bug that doesn't allow the correct call and execution of this function.
Your tips were very helpful. I had to add some code, like increasing the "lpsciState->rxSize" after receving the last character. That was a way I found to set "Receive Status" back to "kStatus_LPSCI_RxBusy" and therefore, to avoid sending the last typed character back to Terminal eternally. My test is a echo, so I want the character typed on Terminal to be sent back to PC only once. I don't know if there is a more correct way to do this.
Bellow, you see the modifications I did in the code that I originally attached to this discussion. The changes were in main.c (main loop), Events.c (RxCallBack function) and in fsl_lpsci_driver.c (LPSCI_DRV_IRQHandler function). It was tested on FRDM-KL25Z and I used OpenSDA Virtual COM for communication.
Thanks you very much and best regards,
Marco Coelho
!Hi Marco Coelho,
I am sorry, but I am a little bit confused, the demo I provided yesterday is a echo demo already, I have tested it on FRDM-KL25Z, any data I typed in the terminal has been echoed back, the demo is based on your original project , and what I changed in your project is just adding that callback, nothing else, so I don't understand why you changed main.c in that way, because in my understanding your original project is good, just without a defined rx callback function.
For the issue you mentioned for "LPSCI_HAL_Getchar" function call in "LPSCI_DRV_IRQHandler", actually I could not reproduced it here , maybe you can try my project on your FRDM-KL25Z board to see if the problem is still there.
I attached the video when I tested my demo, please refer to it for more details.
Hope that helps,
Have a great day,
Kan
Freescale Technical Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
i also encounter same issue in other general UART, when i call UART_DRV_InstallTxCallback function, the isr will not stop to call this callback function. it should be a bug in SDK, you can see another thread as below link.
https://community.freescale.com/message/539727?et=watches.email.thread#539727
Hi Ningning,
I just checked the thread you mentioned, and think maybe you have some misunderstanding with the callback function in sdk 1.2, if you refer to Kinetis SDK v.1.2.0 API Reference Manual.pdf, you may find a statement for the kind of InstallTx/RxCallback() function:
so it is not a sdk issue, it is what callback should do when callback function is enabled.
Have a great day,
Kan
Freescale Technical Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Yes, if followed the statement in the RM, users should to add the below two line code to relocate the position of output buffer, that would be OK. but i think it's a little hard for customer, usually we just need to add user's application code before, they needn't to maintain the state structure, and in SDK's most example, after we defined one state structure, users needn't to maintain it, because SDK driver layer will do that.
++uartState->txBuff;
--uartState->txSize;
Hello, Kan
Thanks for clarifying my question. But now another question comes to my mind.
This solution works fine when you run a echo like this. But our application needs to receive a block of data. So, we can't waste time in main loop to save the received data and lose data.
The only way I found to do it temporarily is coming back to my first solution. I tried to call "ReceiveData" inside "RxCallBack" function, instead of call it in my main loop, but it didn't work.
What is the right way to do it by using Processor Expert functions?
Thanks and best regards,
Hi Marco Coelho,
LPSCI_DRV_ReceiveData() is designed to receive data in the application layer, while RxCallback function is called in the ISR, so it is not the correct way to put this api in the callback function, and the LPSCI_DRV_ReceiveData() is a non-blocking function, it returns immediately after being called, so it would waste too much of time, and the user application/main() may use LPSCI_DRV_GetReceiveStatus() to check if the receiving is done, otherwise main() can handle other tasks during the receiving.
An alternative way is to use RTOS like MQX , FreeRTOS and something like that, you may split main() into multiple small tasks , when receiving task is pending, other tasks may have the CPU to do something. The KSDK 1.2 provides OSA layer for such kind of purpose , you may select the RTOS that you are familiar with.
Please kindly let me know if you have any issue.
Have a great day,
Kan
Freescale Technical Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hello, Kan
Thanks for the tips. As I said previously, calling "LPSCI_DRV_ReceiveData()" function in my application layer would take too much time and lose data, since there are the other functions of my application to be executed in main loop also. And I wouldn't choose to use Rx Buffer full interrupt to save data in my application layer loop, instead of inside the ISR. That doesn't make any sense to me!
Isn't there another way to solve this issue? What if the developer feels more comfortable to work in Baremetal mode and is not experienced with MQX or other embedded RTOS?
I just want to save received data inside Rx Buffer full interrupt so that I don't need to check for Rx Buffer State in my application loop and lose a lot of received data.
Thanks and regards,
Marco Coelho
Hi Marco Coelho,
It is easy to save data in the ISR by defining a RxCallback , but the application still have to check the receiving state, otherwise how the application know when to handle the receiving data? do you mean to want to handle the receiving data in the ISR? if so , there is possibility the ISR consumes too much of time to handle the data and pend other interrupts and the mainloop as well.
so in my understanding, if you implement the echo demo in the following way, it would not wait in a endless loop to check the receive status during receiving, the application may handle other tasks while waiting for the data coming in.
/* For example: for(;;) { } */
LPSCI_DRV_ReceiveData(FSL_LPSCICOM1, &rx_data, 1u); // initialize the receiving
for(;;){
if(kStatus_LPSCI_Success == LPSCI_DRV_GetReceiveStatus(FSL_LPSCICOM1, NULL)) // check status, if having data
{
tx_data = rx_data;
LPSCI_DRV_SendData(FSL_LPSCICOM1, &tx_data, 1u);
LPSCI_DRV_ReceiveData(FSL_LPSCICOM1, &rx_data, 1u);
}
else //if no data coming in then do something else
{
tx_data = 0;
}
}
Please kindly help to clarify! I may help to provide an example for your case.
Have a great day,
Kan
Freescale Technical Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Sorry, Kan
Maybe I was not clear enough.
Imagine that you have to receive a block with 64 bytes of data via UART and handle this data in your main application loop. Probably you will need to save it in a matrix of several elements.
What is the best way of doing this using Processor Expert and KSDK?
Thanks and best regards,
Marco Coelho
Hi Marco Coelho,
Thanks for the clarification! I think you may only do the necessary date receive and storing to rx buffer in the callback, but please NOT do many stuff in the callback as it is called in the ISR. and actually when user use the InstallRxCallback, the UART will be setup in the passive mode. No need to call the transferxxx function. The InstallRXcallback enable the receiver and enable the interrupt. All data receive is handled in the user callback and user can decided in the user callback whether to abort the transfer, keeping on receiving data or update the receive buffer. User can provide a flag in the user callback when the need data is received. The main loop can do other stuff and then back to check whether the data is received. If received, do with the data. If not, do with other stuff again.
Hope that helps,
Have a great day,
Kan
Freescale Technical Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hello, Kan
Thanks for clarifying my question. But now another question comes to my mind.
This solution works fine when you run a echo like this. But our application needs to receive a block of data. So, we can't waste time in main loop to save the received data and lose data.
The only way I found to do it temporarily is coming back to my first solution. I tried to call "ReceiveData" inside "RxCallBack" function, instead of call it in my main loop, but it didn't work.
What is the right way to do it by using Processor Expert functions?
Thanks and best regards,
Marco Coelho
Kan,
After debugging the code, I found the exact point where it hangs. The first time I type something on the Terminal, in "LPSCI_DRV_IRQHandler", it calls "LPSCI_HAL_Getchar" function, but it never returns from there, and falls into a Default_ISR, but I don't know why.
/* Handle Rx Data Register Full interrupt */
if((UART0_BRD_C2_RIE(base)) && (UART0_BRD_S1_RDRF(base)))
{
/* Get data and put in receive buffer */
LPSCI_HAL_Getchar(base, lpsciState->rxBuff);
Hi, Kan
I included the code above in RxCallBack function as you recommended, but it didn't take any effect.
Any other tips, hint?
Have you ever tested it on your side? Do you have a simple functional echo example code with RxCallBack function enabled on FRDM-KL25Z? Could you please provide it to me?
Thanks and best regards,
Marco Coelho
Applications Engineer
Siletec Eletronica
!Hi Marco Coelho,
Sorry, I just checked my solution and found some typo issue, it should be as below.
void lpsciCom1_RxCallback(uint32_t instance, void * uartState)
{
/* Write your code here ... */
++((lpsci_state_t *)uartState)->rxBuff;
--((lpsci_state_t *)uartState)->rxSize;
}
The attached project is just what you put in this thread, with the above solution, and I verified it on my FRDM-KL25Z. You may try it on your side.
Hope that helps,
Have a great day,
Kan
Freescale Technical Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi, Kan
Great! Your solution really works! I made some mistakes. I thought "LPSCI_DRV_ReceiveData" function should not be used in Interrupt driven mode and I supposed this could be causing the failure.
I came back to the old code in main loop, by calling "LPSCI_DRV_ReceiveData" function and checking the LPSCI Status. And when this function is called in main loop, I don't have to access ((lpsci_state_t *)uartState)->rxBuff and store it in my rx_data variable inside RxCallBack function anymore.
I also understood it is not necessary to define a "User Parameter" and "Rx buffer", as well. So I disabled them in lpsci bean.
After that, in LPSCI_DRV_ISR_Handler, I commented the line:
// | lpsciState->rxBuff = UART0_D; |
and uncommented the line:
LPSCI_HAL_Getchar(base, lpsciState->rxBuff);
So, its original content is back and no more hanging and no more Default_ISR!
And, now, everything is working perfectly!
Thank you very much for your support, Kan!
Regards,
Marco Coelho
Hi Marco Coelho,
Because after the callback is enabled, it bypasses some part of the LPSCI IRQHandler logic, so if you installed rx callback, you have to handle the rxBuff and rxSzie in the callback function. and your callback function is just an empty function, so the receiving driver could not get any data from the terminal. Please refer to the following for more details.
void lpsciCom1_RxCallback(uint32_t instance, void * uartState)
{
/* Write your code here ... */
}
void LPSCI_DRV_IRQHandler(uint32_t instance)
{
lpsci_state_t * lpsciState = (lpsci_state_t *)g_lpsciStatePtr[instance];
UART0_Type * base = g_lpsciBase[instance];
/* Exit the ISR if no transfer is happening for this instance. */
if ((!lpsciState->isTxBusy) && (!lpsciState->isRxBusy))
{
return;
}
/* Handle Rx Data Register Full interrupt */
if((UART0_BRD_C2_RIE(base)) && (UART0_BRD_S1_RDRF(base)))
{
/* Get data and put in receive buffer */
LPSCI_HAL_Getchar(base, lpsciState->rxBuff);
/* Invoke callback if there is one */
if (lpsciState->rxCallback != NULL)
{
lpsciState->rxCallback(instance, lpsciState);
}
else
{
++lpsciState->rxBuff;
--lpsciState->rxSize;
/* Check and see if this was the last byte received */
if (lpsciState->rxSize == 0)
{
LPSCI_DRV_CompleteReceiveData(instance);
}
}
}
/* Handle Tx Data Register Empty interrupt */
if((UART0_BRD_C2_TIE(base)) && (UART0_BRD_S1_TDRE(base)))
{
/* Check to see if there are any more bytes to send */
if (lpsciState->txSize)
{
/* Transmit data and update tx size/buff. */
LPSCI_HAL_Putchar(base, *(lpsciState->txBuff));
/* Invoke callback if there is one */
if (lpsciState->txCallback != NULL)
{
/* The callback MUST set the txSize to 0 if the
* transmit is ended.*/
lpsciState->txCallback(instance, lpsciState);
}
else
{
++lpsciState->txBuff;
--lpsciState->txSize;
}
/* Check and see if this was the last byte */
if (lpsciState->txSize == 0)
{
/* Complete the transfer and disable the interrupt */
LPSCI_DRV_CompleteSendData(instance);
}
}
}
/* Handle receive overrun interrupt */
if (LPSCI_HAL_GetStatusFlag(base, kLpsciRxOverrun))
{
/* Clear the flag, OR the rxDataRegFull will not be set any more */
LPSCI_HAL_ClearStatusFlag(base, kLpsciRxOverrun);
}
}
Hope that makes sense,
Have a great day,
Kan
Freescale Technical Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Ok, Kan
Following your instructions, I modified my code in loop for in main.c to:
for(;;){
// Wait until we receive a user character
while (kStatus_LPSCI_RxBusy == LPSCI_DRV_GetReceiveStatus(FSL_LPSCICOM1, NULL)) {}
LPSCI_DRV_SendData(FSL_LPSCICOM1, &tx_data, 1u);
while (kStatus_LPSCI_TxBusy == LPSCI_DRV_GetTransmitStatus(FSL_LPSCICOM1, NULL)) {}
}
And left RxCallBack function just like that:
void lpsciCom1_RxCallback(uint32_t instance, void * uartState)
{
/* Write your code here ... */
tx_data = rx_data;
}
But it is not working yet.
Did I forget any detail?
Thanks and regards,
Marco Coelho