0

I am using Avnet Azure sphere board with RS485 click board connected. In RS485 Click the GPIO PWM is made high to send RS485 signal from Click board and GPIO PWM is made low to receive RS485 signal. The problem here is for sending the request it takes at least 2 seconds but the connected sensor returns the response within milliseconds before we switch back the GPIO PWM to low for receiving. Hence my UART return event is not firing. Any help would be appreciated.

My send UART message function

static void SendUartMessage(int uartFd, const char* dataToSend, size_t totalBytesToSend, bool ignoreRx)
{
    size_t totalBytesSent = 0;
    //size_t totalBytesToSend = strlen(dataToSend);
    int sendIterations = 0;
    close(r1PinFd);
    r1PinFd = GPIO_OpenAsOutput(MIKROE_PWM, GPIO_OutputMode_PushPull, GPIO_Value_High);
    while (totalBytesSent < totalBytesToSend) {
        sendIterations++;

        // Send as much of the remaining data as possible
        size_t bytesLeftToSend = totalBytesToSend - totalBytesSent;
        const char* remainingMessageToSend = dataToSend + totalBytesSent;
        ssize_t bytesSent = write(uartFd, remainingMessageToSend, bytesLeftToSend);
        if (bytesSent == -1) {
            Log_Debug("ERROR: Could not write to UART: %s (%d).\n", strerror(errno), errno);
            exitCode = ExitCode_SendMessage_Write;
            return;
        }

        totalBytesSent += (size_t)bytesSent;
    }
    int c, d;

    delay_milliseconds(2000);
    close(r1PinFd);
    r1PinFd = GPIO_OpenAsOutput(MIKROE_PWM, GPIO_OutputMode_PushPull, GPIO_Value_Low);

    Log_Debug("Sent %zu bytes over UART in %d calls.\n", totalBytesSent, sendIterations);
}

My RS485 UART return event

static void UartEventHandler(EventLoop* el, int fd, EventLoop_IoEvents events, void* context)
{
    const size_t receiveBufferSize = 256;
    uint8_t receiveBuffer[receiveBufferSize + 1]; // allow extra byte for string termination
    ssize_t bytesRead;

    // Read incoming UART data. It is expected behavior that messages may be received in multiple
    // partial chunks.
    bytesRead = read(uartFd, receiveBuffer, receiveBufferSize);
    if (bytesRead == -1) {
        Log_Debug("ERROR: Could not read UART: %s (%d).\n", strerror(errno), errno);
        exitCode = ExitCode_UartEvent_Read;
        return;
    }

    if (bytesRead > 0) {
        receiveBuffer[bytesRead] = 0;
        Log_Debug("UART received %d bytes: '%s'.\n", bytesRead);
        char  data_hex_str[sizeof(receiveBuffer) / sizeof(receiveBuffer[0])];
        get_hex(receiveBuffer, sizeof(receiveBuffer) / sizeof(receiveBuffer[0]), data_hex_str, sizeof(receiveBuffer) / sizeof(receiveBuffer[0]), 16);
        strcat(returnDataUart, data_hex_str);
        Log_Debug("\s", returnDataUart);
    }

    char* pjsonBuffer = (char*)malloc(JSON_BUFFER_SIZE);
    if (pjsonBuffer == NULL) {
        Log_Debug("ERROR: not enough memory to send telemetry");
    }

    snprintf(pjsonBuffer, JSON_BUFFER_SIZE,
        "{\"gX\":%.2lf, \"gY\":%.2lf, \"gZ\":%.2lf, \"aX\": %.2f, \"aY\": "
        "%.2f, \"aZ\": %.2f, \"pressure\": %.2f, \"light_intensity\": %.2f, "
        "\"altitude\": %.2f, \"temp\": %.2f,  \"rssi\": %d, \"RS485\": %s}",
        acceleration_g.x, acceleration_g.y, acceleration_g.z, angular_rate_dps.x,
        angular_rate_dps.y, angular_rate_dps.z, pressure_kPa, light_sensor, altitude,
        lsm6dso_temperature, network_data.rssi, returnDataUart);

    Log_Debug("\n[Info] Sending telemetry: %s\n", pjsonBuffer);
    SendTelemetry(pjsonBuffer, true);
    free(pjsonBuffer);
}

1 Answers1

0

RS485 is half duplex so only one device can transmit at a time. It is therefore imperative that you turn off the transmitter as soon as you finish sending data. Ideally you should do this in hardware. In you case, it looks like you have a delay_milliseconds(2000); before you turn off the transmitter. This result in a collision and any data transmitted will be lost.

doron
  • 27,972
  • 12
  • 65
  • 103
  • If I did not give the delay, the send data is not successful. Is there anyway we can delay the response from the sensor? – Vaduganathan May 25 '21 at 04:30
  • it is imperative that you turn off the transmitter immediately after sending. If your write is working via DMA, you will need to tie the turning off the transmitter into an interrupt called when the DMA transfer is completed. A common pattern is the use the UART RTS line for switching the transmitter. – doron May 25 '21 at 12:31
  • The DMA completion interrupt is not the proper event for toggling the transceiver; the UART hardware still needs more time to shift out the last character frame. Reliable/accurate control in software can only be achieved by the UART device driver. BTW this "answer" seems more like a comment than a specific solution. – sawdust May 27 '21 at 21:45
  • The problem was with the delay method which I created for millisecond wait. It was rounding off to zero when I give a value below 1000. Everything works fine. – Vaduganathan May 31 '21 at 11:58