Peripheral RS485
- This topic has 9 replies, 3 voices, and was last updated 5 years, 11 months ago by John Greene.
-
AuthorPosts
-
November 14, 2018 at 8:56 am #26763John GreeneParticipant
We are trying to implement RS485 on a custom peripheral board. We have code written for Mdot that was running fine before the most recent update to libmdot-mbed5 which, in turn, needs mbed-os-5.7.7. Something apparently changed with Mbed’s “Serial” function at some point between mbed-os-5.4.7 and mbed-os-5.7.7 (and, more specifically, in mbed-os-5.5.4) and it no longer works as we have it implemented.
Below is a post I put up on the Mbed forum (https://os.mbed.com/questions/83077/Different-interrupt-behavior-starting-wi/) as well as the only response to it posted thus far. We have tried using “RawSerial” instead of “Serial” per the suggestion in the response without any luck. It is unclear as to whether the RawSerial vs Serial is really even the issue.
Has anyone had any luck running RS485 from an Mdot on mbed-os-5.7.7? Any ideas what else we might try/do?
Different interrupt behavior starting with mbed-os-5.5.4
We had code developed in mbed-os-5.4.7 that works fine for our MTS_MDOT_F411RE target. When we updated to mbed-os-5.7.7, our transmit interrupt routine appears to be causing our program to hang. I say this because as soon as the program executes the below line (let’s call it “Line A” for reference), no lines following it will ever execute.
USART1_DATA.pSerialPort->attach(&INT_USART1_TX_Handler, Serial::TxIrq);
Some additional related findings through using printf to gauge the program’s progression:
The Rx equivalent line does not exhibit this issue.
Emptying the contents of INT_USART1_TX_Handler does not resolve this issue.
Calling _ _disable_irq() before “Line A” resolves the hang, and calling _ _enable_irq() later in the code causes the hang to emerge.
Through process of elimination and scoping out a pin, we’ve seen that up to mbed-os-5.5.3 will properly generate waveforms (which occur after all the initializations). Using the same setup, mbed-os-5.5.4 does not generate these waveforms, and neither do several other versions we tested up to 5.7.7 inclusive.Is there a known change implemented in mbed-os-5.5.4 that could result in this sort of issue with interrupts for F411RE? Is there a known workaround or solution for this situation?
I can try to provide additional information if needed. Any thoughts or feedback would be greatly appreciated, thank you.
Comment on this question
1 AnswerGraham S.
5 days, 14 hours ago.
Are you using the plain mbed provided Serial class? I’ve been hunting similar ISR issues with Serial. If you open the source you can see that every member function is protected by a mutex. Mutexes of course should not be called from ISR context. Even functions one would assume are safe like putc(), getc() use mutexes. On older versions of mbed I had used functions like readable() and getc() in ISR without crashing things. But on new mbed builds this crashes for me with mutex lock errors. There are some suggestions on the forums about handling class Serial in ISR but I have not seen one that did not end up calling illegal mutex inside ISR because all Serial methods have mutexes. As far as I can tell as soon as you get into an ISR routine with Serial you are beat as you can’t even legally clear the interrupt flag that got you there.The solution I found was to use the RawSerial class instead of regular Serial – this is in standard mbed library as well. It has the basics like putc(), getc() and a printf() that are supposed to resolve this issue and allow sending and receiving in ISR context. It may be as simple as changing your object from type Serial to type RawSerial. RawSerial has resolved the random mutex issues for me.
For regular Serial class (I haven’t tried this) but for printing you could spin up a dedicated Thread with a mailbox input. Should allow other parts of the program to run at normal speed while sending does it’s thing.
November 14, 2018 at 9:47 am #26786Ryan KlaassenBlockedThis is the only change I could find on interrupts from 5.5.3 to 5.5.4.
https://github.com/ARMmbed/mbed-os/pull/4676 . What is &INT_USART1_TX_Handler doing?November 14, 2018 at 12:52 pm #26795John GreeneParticipantIt is the serial interrupt function in the USART initialization:
/********************************************************************************************
; Function: USART1_IntInit
; Description: Initializes USART1
; Inputs: ULONG – baud rate
; UBYTE – control word (parity, stop, word length)
; UBYTE – fifo control word
; Returns: SUCCESS – SUCCESS
***********************************************************************************************/
ERRCODE USART1_IntInit(UCB* ucb)
{
ERRCODE ec = SUCCESS;
/* Initialize SOFTWARE FIFO */
USART1_DATA.rxHead = USART1_DATA.rxTail =0;
USART1_DATA.txHead = USART1_DATA.txTail =0;
USART1_DATA.errors=0;
USART1_DATA.overflows=0;
USART1_DATA.rxCnt=0;
USART1_DATA.txCnt=0;
USART1_DATA.transferState = USART1_TRANSFER_COMPLETE;
USART1_DATA.transferComplete = ucb->transferComplete;
USART1_DATA.rxSignal = ucb->rxSignal = NULL;
USART1_DATA.rxSignalParameter = ucb->rxSignalParameter = NULL;
USART1_DATA.txSignal = ucb->txSignal = NULL;
USART1_DATA.txSignalParameter = ucb->txSignalParameter = NULL;
//
ucb->getRxCounter = USART1_GetRxCounter;
ucb->getTxCounter = USART1_GetTxCounter;
ucb->setData = USART1_SetData;
ucb->getData = USART1_GetData;
ucb->setFiFoData = USART1_SetFiFoData;
ucb->getFiFoData = USART1_GetFiFoData;
ucb->isTxFiFoAvailable = USART1_IsTxFiFoAvailable;
ucb->getErrors = USART1_GetErrors;
ucb->getOverflows = USART1_GetOverflows;
ucb->getRxCnt = USART1_GetRxCnt;
ucb->getTxCnt = USART1_GetTxCnt;
//
/* Initialize UART interface */
switch(ucb->iface) {
case SERIALAPI_USART1_INTERFACE:
break;
default:
ec = SERIALAPI_INTERFACE_ERROR;
break;
}
if (ec) goto func_end;
//
switch(ucb->word_length) {
case SERIALAPI_WORLD_LENGTH_8:
break;
default:
ec = SERIALAPI_WORD_LENGTH_ERROR;
break;
}
if (ec) goto func_end;
//
switch(ucb->stop) {
case SERIALAPI_STOP_1:
break;
default:
ec = SERIALAPI_STOP_ERROR;
break;
}
if (ec) goto func_end;
//
switch(ucb->parity) {
case SERIALAPI_PARITY_NO:
break;
default:
ec = SERIALAPI_PARITY_ERROR;
break;
}
USART1_DATA.pSerialPort = &USART1_PORT;
USART1_DATA.pSerialPort->baud(ucb->baudRate);
// Setup a serial interrupt function to receive data
USART1_DATA.pSerialPort->attach(&INT_USART1_RX_Handler, Serial::RxIrq);
// Setup a serial interrupt function to transmit data
USART1_DATA.pSerialPort->attach(&INT_USART1_TX_Handler, Serial::TxIrq);
func_end:
return ec;
}November 14, 2018 at 1:22 pm #26796Ryan KlaassenBlockedI apologize, I meant what is the INT_USART1_TX_Handler code?
November 14, 2018 at 4:00 pm #26797John GreeneParticipantDefinition:
******************************************************************************************** ; Function: INT_USART1_TX_Handler ; Description: USART1 TX interrupt service routine ; Inputs: Nothing ; Returns: Nothing **********************************************************************************************/ void INT_USART1_TX_Handler (void) { while(USART1_DATA.pSerialPort->writeable()) { /* Process TX SOFTWARE FIFO */ if(USART1_DATA.txTail != USART1_DATA.txHead) { USART1_DATA.pSerialPort->putc(USART1_DATA.txBuffer[USART1_DATA.txTail++]); if(USART1_DATA.txTail >= USART1_TX_SOFT_FIFO_LENGTH) USART1_DATA.txTail =0; USART1_DATA.txCnt++; } else { USART1_DATA.transferState = USART1_TRANSFER_COMPLETE; if(USART1_DATA.transferComplete) USART1_DATA.transferComplete(); break; } } }
- This reply was modified 6 years ago by John Greene.
November 14, 2018 at 4:11 pm #26799Jason ReissKeymasterhttps://os.mbed.com/teams/MultiTech/code/MTS-Serial
Below is the ISR handler we use in our custom serial driver on the AT command port.
void MTSSerial::handleWrite() { while(txBuffer.size() != 0) { if (_serial->writeable()) { char byte; if(txBuffer.read(byte) == 1) { _serial->attach(NULL, Serial::RxIrq); _serial->putc(byte); _serial->attach(this, &MTSSerial::handleRead, Serial::RxIrq); } } else { return; } } }
November 14, 2018 at 5:04 pm #26800Ryan KlaassenBlockedI don’t see anything in the code that stands out as the issue.
https://github.com/ARMmbed/mbed-os/pull/4734/files It may have something to do with this pr. In 5.5.4 they eliminated some clears specifically this call __HAL_UART_CLEAR_IT(huart, UART_CLEAR_TCF); on uart_irqNovember 27, 2018 at 2:00 pm #26890John GreeneParticipantThanks for the feedback, Ryan and Jason. Unfortunately, we are still spinning our wheels on this problem. I am wondering if we might ought to shelve trying to implement the RS485 driver we have and see if we can implement MTSSerial instead. Are you aware of anyone who has used MTSSerial in ways outside of the specific AT command intended use case? And, if not, do you foresee us bumping into any problems using it? (FYI – we are using this RS485 transceiver http://www.ti.com/lit/ds/symlink/sn65hvd1781.pdf)
November 30, 2018 at 8:43 am #26904Jason ReissKeymasterMTSSerial is used on mDot/xDot as well as our cellular modules. It is a wrapper of RawSerial that adds buffers.
MTSSerial does not support RS485. I am not certain it will meet your requirements.
There are projects such as modserial and RS485 available on mbed that may be of interest.
https://os.mbed.com/users/Allar/code/RS485/docs/tip/classRS485.html
https://os.mbed.com/cookbook/MODSERIALDecember 4, 2018 at 1:20 pm #26925John GreeneParticipantUnderstood, Jason. Thanks for the feedback/guidance.
-
AuthorPosts
- You must be logged in to reply to this topic.