sparkfun / Arduino_Apollo3

Arduino core to support the Apollo3 microcontroller from Ambiq Micro
83 stars 37 forks source link

Custom Serial Pins for serial 1 have receiving issue! #496

Closed bimalpaneru closed 8 months ago

bimalpaneru commented 8 months ago

Following up on this issue, , I have been trying to use Pin AUD_BCLK for Tx and AUD_LRCLK for Rx for a RS485 module.

Been having the issue during the receiving. Nothing is being received on the Rx line whereas TX seems perfectly fine. I do not even know what might be causing this, think this is the closest thread to my problem.

I have 10k pullup on the Rx line in saying that with or without pullup nth changes.

I am using a micromod variant of artemis at 19200 SERIAL_8E1

Would really appreciate any suggestions on potential solution to this.

paulvha commented 8 months ago

hi, The old issue was solved and closed. I am trying to understand the setup. Which micromod board are you using? (ATP, main board, double main board) I assume the micromod Artemis processor How do you connect (which pin on the board ?) Can you share the sketch you use ? Which version of the Artemis library? regards, Paul

bimalpaneru commented 8 months ago

Hi Paul, Here are the details for my setup. Do let me know if you need more information. Running it on Ubuntu 22.04 Using MicroMod Artemis image These are the project configuration
Artremis core is v2.2.1 but I have seen similar issue with v2.2.2 as well Platform [env:SparkFun_Artemis_Module] platform = apollo3blue board = SparkFun_MicroMod_Artemis_Processor framework = arduino platform_packages=framework-arduinoapollo3@2.2.1

running it on platformio core 6.1.13. Testing with this sketch to read from the custom serial port 1

#include <Arduino.h>

/****************For Artemis***********************/
const PinName RS485_DI_PIN = AUD_BCLK;
const uint8_t RS485_DE_PIN = G2;
const uint8_t RS485_RE_PIN = G3;
const PinName RS485_RO_PIN = AUD_LRCLK;
const uint8_t DOWNSTREAM_POWER_ENABLE_PIN = AUD_IN;

const uint8_t RS485_MUX_S0_PIN = SDIO_DATA1;
const uint8_t RS485_MUX_S1_PIN = SDIO_DATA2;
const uint8_t RS485_MUX_ENABLE_PIN = SDIO_DATA3;

UART rs485_serial(AUD_BCLK, AUD_LRCLK);

void delay_ms() {
    // delay(10);
    // delayMicroseconds(1);
    // delayMicroseconds(572);
}

void pre_send() {
    digitalWrite(RS485_RE_PIN, HIGH);
    digitalWrite(RS485_DE_PIN, HIGH);
}
void post_send() {
    digitalWrite(RS485_RE_PIN, LOW);
    digitalWrite(RS485_DE_PIN, LOW);
}

void setup() {
    pinMode(RS485_RE_PIN, OUTPUT);
    pinMode(RS485_DE_PIN, OUTPUT);

    pinMode(RS485_MUX_ENABLE_PIN, OUTPUT);
    pinMode(RS485_MUX_S0_PIN, OUTPUT);
    pinMode(RS485_MUX_S1_PIN, OUTPUT);

    pinMode(DOWNSTREAM_POWER_ENABLE_PIN, OUTPUT);

    //  //Enable mux and select channel 3

    digitalWrite(RS485_MUX_ENABLE_PIN, LOW);
    digitalWrite(RS485_MUX_S0_PIN, 1);
    digitalWrite(RS485_MUX_S1_PIN, 1);

    //  //enable power

    digitalWrite(DOWNSTREAM_POWER_ENABLE_PIN, HIGH);

    Serial.begin(115200);
    rs485_serial.begin(19200, SERIAL_8E1);
    post_send();
}

void loop() {
    if (Serial1.available()) {
        Serial.write((char)Serial1.read());
    }
///////////////sample send/////////////////
    // pre_send();
    // rs485_serial.print("hello\n");
    // post_send();
    // delay(1000);
}

Here is a sample schematic of the pins being used.

image

bimalpaneru commented 8 months ago

The idea is to read from a MODBUS RTU. But I havent been able to register any Rx on the MCU

paulvha commented 8 months ago

An Artemis processor has 2 UART's. On the Micromod processor default UART0 is assigned to Serial and UART1 to Serial1. Serial1 is by default connected for transmission to TX1 and received to RX1.

In the sketch you re-assign UART1 to become rs485_serial and the pins: UART rs485_serial(AUD_BCLK, AUD_LRCLK); However in the sketch, you try to READ from Serial1, but that is NOT connected anymore to UART1. Instead, you should READ from rs485_serial, in the same way as you WRITE to rs485_serial !

Attached is the changed sketch I have used and it works.

regards, Paul rs485test.zip

bimalpaneru commented 8 months ago

Hi Paul, Sorry for using Serial1 in the previous post. It should have been rs485_serial, got mixed up in multiple test line. I have tried the test you have recreated but that does not seem to work, in my case. However, commenting Line 8: of packages/framework-arduinoapollo3@2.2.1/variants/SFE_ARTEMIS_MM_PB UART Serial1(TX1, RX1, RTS1, CTS1); and redefining the UART object with custom pins in the main.cpp seems to have worked.

paulvha commented 8 months ago

weird.. must have something to do with platformio. I use Arduino IDE and it works there. Can you close this issue ?

bimalpaneru commented 8 months ago

Just a quick follow up, will there be an implementation of Serial.flush() in future? Can you please suggest an alternative for TX buffer flush? TIA

paulvha commented 8 months ago

Don't expect so. The issue is related to MBED-OS not having a flush() call and how it interacts.

MBED-OS is in between the sketch/user level and the Sparkfun Apollo3/Artemis processor driver. With a print or write from the sketch /user level the complete buffer is sent to MBED-OS unbuffered driver. From there, character by character, it is sent to the Apollo3 processor driver until the buffer has been sent completely. MBED-OS will return with the size of the buffer transferred once the Sparkfun Apollo3 processor driver routine returns as the character has been placed in the Apollo3 chip TX-FIFO.

There is no way to flush/clear pending characters in the buffer in MBED-OS once it has been written. AND, although the Apollo3 chip has a TX-FIFO-EMPTY flag, there is NO function-call to check that.

regards, Paul

bimalpaneru commented 8 months ago

Thank you for this detailed response @paulvha really appreciate you help on this,

I had a impression that this method, in am_hal_uart.c could be a savior, but guess not?

//*****************************************************************************
//
// Wait for all of the traffic in the TX pipeline to be sent.
//
//*****************************************************************************
uint32_t
am_hal_uart_tx_flush(void *pHandle)
{
    am_hal_uart_state_t *pState = (am_hal_uart_state_t *) pHandle;
    uint32_t ui32Module = pState->ui32Module;

    //
    // If we have a TX queue, we should wait for it to empty.
    //
    if (pState->bEnableTxQueue)
    {
        while (am_hal_queue_data_left(&(pState->sTxQueue)))
        {
            ONE_BYTE_DELAY(pState);
        }
    }

    //
    // Wait for the TX busy bit to go low.
    //
    while ( UARTn(ui32Module)->FR_b.BUSY )
    {
        ONE_BYTE_DELAY(pState);
    }

    return AM_HAL_STATUS_SUCCESS;
} // am_hal_uart_tx_flush()
paulvha commented 8 months ago

That is indeed part of the Sparkfun Apollo3 / Artemis driver. This was implemented from the AMBIQ driver in the V1.x Sparkfun library but is not used in the V2.x due to MBED-OS in between.

Just one more remark the Sparkfun Artemis driver does not use TXQueue implementation (buffers are 0) so it writes directly to the FIFO in the Apollo3 chip. Hence the FR_b.BUSY flag check is only relevant.