Search code examples
uartmodbusatmelsamd21

Why samd21 is reading modbus own response as a master request?


I'm adding slave MODBUS RTU communication over RS-485 (by chip ADM2587EBRWZ) into a SAMD21 existing program. Only Read holding register and Write single register commands implemented as I don't need more.

To test it I use a PLC by Microcom as master. I let it run for some hours but the logs shows some -3333 values (Microcom use -3333 to show an error has occurred with that register read). Checking the plc terminal I noticed that if the answer message ends in "00 00 CRC_lo 00" the next request is an error. If Debugged on Atmelstudio, the ATSAMD21 reads that same answer and detect it as a request, giving a Illegal data address response to the PLC.

After answering I do a usart_reset on the port and clean the message array, any idea of what can it be?

2 notes: I quite new to C programming and English is not my first language.

Edit: added more code, if need anything else I can post it. This part is on main loop:

while(ReceivedCommand_MODBUS() ==false)
{
    UartReadJob_MODBUS();
}                       
AnalyzeReceiveCommand_MODBUS();

First function is:

bool ReceivedCommand_MODBUS()
{   
    uint16_t CRC=0;
    CRC = CRC16(CommandReadBuffer_MODBUS,6);
    if ((CommandReadBuffer_MODBUS[CommandReadLength-1] == ((CRC & 0xFF00)>>8)) && (CommandReadBuffer_MODBUS[CommandReadLength-2]) == (CRC & 0x00FF) )
{
    return true;
}

if ((CommandReadLength - 1 )>= RS485_COMMAND_LENGTH)
{
    CommandReadLength = 0;  
    memset(CommandReadBuffer_MODBUS, 0, sizeof(CommandReadBuffer_MODBUS));
}
return false;
}

And last one:

void AnalyzeReceiveCommand_MODBUS()
{
    uint32_t receiveLength = 0;
    uint8_t receiveCommand[COMMAND_READ_BUFFER_LENGTH_MODBUS];
    memset(receiveCommand, 0, COMMAND_READ_BUFFER_LENGTH_MODBUS);   
    ReadCommand_MODBUS(receiveCommand, &receiveLength);
    uint16_t CRC = 0;
    
    //Modbus request is read and response generated here

    SendMaster_MODBUS(messageData,MessageSize);                         
    delay_ms(10);    //delays are for breakpoints
    UartReset(&UART1);
    for (char i=0;i<=MessageSize+1;i++)
    {
        UartReceiveBuffer_MODBUS[i]=0;
        UartSendBuffer_MODBUS[i]=0; 
        messageData[i]=0;
    }
    void ResetBuffer_MODBUS ();
    delay_ms(10);
}

ReadCommand_MODBUS fucntion:

void ReadCommand_MODBUS(uint8_t* command, uint32_t* length)
{
    *length = CommandReadLength;
    memcpy(command, CommandReadBuffer_MODBUS, CommandReadLength);
    CommandReadLength = 0;
    memset(CommandReadBuffer_MODBUS, 0, sizeof(CommandReadBuffer_MODBUS));
}

Solution

  • Now it seems to work, calling this after sending the response message:

    void ResetBuffer_MODBUS ()
    {
        memset(CommandReadBuffer_MODBUS, 0, sizeof(CommandReadBuffer_MODBUS));
    }
    

    No error so far, will leave it running for a while, but before it would have failed a couple by now.