2020-07-25 11:54 AM
I tried changing the baud here in main()
static void MX_USART1_UART_Init(void)
huart1.Init.BaudRate = 57600;
and here in mbtask.c:
void ModbusRTUTask()
eMBErrorCode eStatus = eMBInit( MB_RTU, MB_SLAVE_ADDRESS, 3, 57600, MB_PAR_NONE );
As mentioned, this only works to 38400.
Logic analyzer on the RS422 lines shows MODBUS packets from master at 1M fine.
Thank you.
2020-07-27 03:35 AM
What kind of error do you have if you try to further increase the baud rate?
2020-07-31 01:27 AM
I send 2 commands:
(1) Write multiple registers function, start addr 0, qty 3, 6 bytes: [180, 0, 999] for a 999mS 180 degree move
(2) Write coil function
The first command is received OK.
ucRTUBuf in xMBRTUReceiveFSM has the correct 13 byte frame.
EV_FRAME_RECEIVED is posted OK to the event queue which eMBPoll picks up and executes correctly.
The holding registers get the correct values
However the 2nd command frame (coil write function) is not received.
case EV_EXECUTE in eMBPoll never happens.
This behavior always happens running without breakpoints.
If I breakpoint eMBPoll, it mostly happens but not always.
Thanks. Liam
2020-08-17 08:41 AM
Hi Liam,
sorry for the long delay in my answer. I'm trying to reproduce the issue from my side.
Meanwhile, did you check the switching between TX and RX mode of the RS485? If the second command is sent while the RS485 is still in TX mode it is lost and the MODBUS state machine never switch to EV_FRAME_RECEIVED.
A partial frame (i.e. a wrong frame) should trigger the EV_FRAME_RECEIVED status, but it is ignored.
Enrico
2020-08-18 01:18 AM
Hi Liam,
I did some tests.
The communication at 57600 works properly in my setup (QModMaster + FTDI USB-RS485 transceiver)
Attached some screenshots.
The delay between the end of RX frame and the transmission of the acknowledge frame is of about 5 ms, so I think you should wait few ms after the acknowledge is sent before a new frame.
I also did a test at 115.2k, but at this speed the UART communication fails.
2020-08-19 10:39 PM
Hi Enrico. Thank you for looking at this.
I could only get 57600 working by decreasing the EMBPoll period on TIM16.
Default is prescale: 47 and period:999 for 978uS
I changed to prescale: 32 and same period for 666uS
This worked OK. But any faster fails. I concluded this was due to priority vs SYSTICK at 499uS etc.
I will check Rx time as you suggest.
However, we need to talk at substantially higher speed than even 115K to enable a fast stop command.
Other than using PF0 as an edge triggered interrupt, another idea I was considering is using a DMA channel from the UART to solve the lost byte problem described above and altering EMBPoll to work with a queue rather than single instruction.
Liam.
2020-08-19 11:58 PM
Hi Liam
Increasing the eMBPoll frequency should reduce the delays imposed between two consecutive command because the state machine of the MODBUS is executed faster.
However, as you highlighted, the limit is the execution of the others high priority interrupts (basically the FOC algorithm). Maybe there is a way to bypass the state machine making the communication more responsive.
For example, the decoding and execution could be embedded into the end-of-frame timeout manager (TIM14)
BOOL
xMBRTUTimerT35Expired( void )
{
BOOL xNeedPoll = FALSE;
switch ( eRcvState )
{
/* Timer t35 expired. Startup phase is finished. */
case STATE_RX_INIT:
xNeedPoll = xMBPortEventPost( EV_READY );
break;
/* A frame was received and t35 expired. Notify the listener that
* a new frame was received. */
case STATE_RX_RCV:
/* -------------------------------------------------------------- */
/* Instead of notify to the state machine, you could decode and send answer HERE */
/* -------------------------------------------------------------- */
xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
break;
/* An error occured while receiving the frame. */
case STATE_RX_ERROR:
break;
/* Function called in an illegal state. */
default:
assert( ( eRcvState == STATE_RX_INIT ) ||
( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
}
vMBPortTimersDisable( );
eRcvState = STATE_RX_IDLE;
return xNeedPoll;
}
I also think that moving to a DMA approach for the UART should solve the communication speed limit. Just keep attention to not interfere with the DMA management of the FOC.