CommunityGD32Cores / ArduinoCore-GD32

Arduino core for GD32 devices, community developed, based on original GigaDevice's core
Other
89 stars 33 forks source link

Issue with using UART1 on GD32F130C8 #76

Open imeshsps opened 2 years ago

imeshsps commented 2 years ago

I was trying to run the following code to test two serial ports and I was having this issue.

void setup() { Serial.begin(9600); Serial1.begin(9600); } void loop() { Serial.println("looping S1"); Serial1.println("looping S2"); delay(1000); }

The issue I'm having is I'm getting the output for both serial print lines on the first serial output.

debug screen

Then I tried to run SPL example with changed parameters to check whether it is a issue with my PCB but after I made same changes, I was able to use UART1.

uart1 settings

Then I tried to use only Serial1 with the following code and on the debug mode I noticed the following.

void setup() { Serial1.begin(9600); } void loop() { Serial1.println("looping S2"); delay(1000); }

2nd serial port

It seems like it is still passing the same parameters for 1st serial port. Please can you help me to fix this ? Any help is really appreciated.

Thanks.

maxgerhardt commented 2 years ago
  1. We have a misdesign of the Serial buffers where they use the exact same buffer. This was already fixed in a fork, but I haven't imported the fix yet, so independent hardware serial's don't yet work. I'll have a look.
  2. I think though in this case though Serial is a macro for Serial1 and hence you access the same object? See

https://github.com/CommunityGD32Cores/ArduinoCore-GD32/blob/a22a2e3aca8ce338f1ca8e2170fd70c53399120e/cores/arduino/HardwareSerial.h#L145-L147

So that's clear why it's outputting the same stuff.

It seems like it is still passing the same parameters for 1st serial port

If you want to change the default parameters for the hardware serial, you would have to change them in your variant, e.g.

https://github.com/CommunityGD32Cores/ArduinoCore-GD32/blob/a22a2e3aca8ce338f1ca8e2170fd70c53399120e/variants/GD32F130C6_GENERIC/variant.h#L110-L116

We don't yet have a good system of multiple hardware serials, but work on it.

To be clear, what you want is Serial1 on PA2 + PA3 (using USART0) and a Serial2 on some other pins using the USART1 peripheral? (And Serial will always be a macro to the default serial, either the first hardware serial or USB serial.)

imeshsps commented 2 years ago

Thanks for quick reply.

To be clear, what you want is Serial1 on PA2 + PA3 (using USART0) and a Serial2 on some other pins using the USART1 peripheral? (And Serial will always be a macro to the default serial, either the first hardware serial or USB serial.)

Yes. to use two hardware serials on different pins.

I think though in this case though Serial is a macro for Serial1 and hence you access the same object. See

It should be. But I tried using Serial2, it says it is not defined.

If you want to change the default parameters for the hardware serial, you would have to change them in your variant.

I'll give this a try. Thanks for your support. Hope to see them working soon.

maxgerhardt commented 2 years ago

We can keep the issue open until it is properly resolved in code.

maxgerhardt commented 2 years ago

PR #77 in conjunction with https://github.com/CommunityGD32Cores/platform-gd32/commit/52cb1be23bcff41a2b9da6adf3ce9bbdd9b3bf15 have exposed all hardware serial ports of the board as Serial1, Serial2, et cetera. (Serial is macro for Serial1 if no USB is enabled, your chip doesn't have that implemented yet).

I've also added an official PlatformIO example at https://github.com/CommunityGD32Cores/gd32-pio-projects/tree/main/gd32-arduino-serials and personally tested it on a GD32F303CC board.

Can you test this on your F130C8? If you need help with configuring your serial port pins, let me know. By default, you have Serial1 (=Serial) on TX=PA9, RX=PA10, and Serial2 on TX=PA2, RX=PA3, as per here, with these other pins being usable. I hope the README I wrote in the linked projects explains it well.

To update your Arduino core version, please open a CLI and execute

pio pkg update -g -p "https://github.com/CommunityGD32Cores/platform-gd32.git"

in it.

Alternatively, delete C:\Users\<user>\.platformio\packages\framework-arduinogd32 and build the project again.

imeshsps commented 2 years ago

Thank you, I'm out for today and I'll test it tomorrow and let you know.

I really appreciate the time and effort you are putting into this.

imeshsps commented 2 years ago

Hey @maxgerhardt ,

I was able to test it today and it was working with my GD32F130C8.

Screenshot 2022-08-14 102725

After that, I wanted to connect the Neo6M GPS receiver and I noticed this. When I was writing to Serial1 with the FTDI module it was showing on the serial monitor. But when I connect the GPS module, it was not showing anything. Later I found that when connecting it for a very short period of time and disconnecting it, it was showing GPS data. But when I keep it connected, it freezes after a few seconds. I needed to restart the chip to get the serial working back.

Screenshot 2022-08-14 104812

It seemed to me that this was due to the long timeout period and after I reduced the timeout, it was working fine. And by adding the same "trick" to software serial as the following code, I was able to get TinyGPSPlus running.

SoftwareSerial ss(PB11, PB10); ss.begin(9600); ss.setTimeout(250);

Screenshot 2022-08-14 112836

Thank you very much and I really appreciate the time and effort you are putting into this.

maxgerhardt commented 2 years ago

When I was writing to Serial1 with the FTDI module it was showing on the serial monitor. But when I connect the GPS module, it was not showing anything. Later I found that when connecting it for a very short period of time and disconnecting it, it was showing GPS data. But when I keep it connected, it freezes after a few seconds. I needed to restart the chip to get the serial working back.

Seems like the RX buffer got full and there's an error in handling that somewhere -- it should never crash, at most discard the bytes that weren't fitting anymore at the front or back in the ringbuffer.

I'll try and reproduce this by sending lots of data to the chip and see how long it survives.

Candas1 commented 1 year ago

Hi,

I use the same code with a GD32F103 and a GD32F130, but the GD32F130 RX stops working after a few seconds. I have working SPL code for the GD32F130 so it could probably help resolve the issue.

maxgerhardt commented 1 year ago

How can I reproduce the issue? Would a simple loopback like

#include <Arduino.h>

void setup() {
    Serial.begin(115200);
}

void loop() {
    if(Serial.available() > 0) {
        char buf[SERIAL_RX_BUFFER_SIZE + 1];
        size_t numRead = Serial.readBytes(buf, sizeof(buf));
        buf[numRead] = '\0';
        Serial.print("Received: ");
        Serial.println(buf);
    }
}

suffice?

Candas1 commented 1 year ago

Hi,

Sorry for the delayed reply. I created a simple project with only this code today, the only change I did is using Serial2 instead of Serial. A hoverboard mainboard is sending binary data every 10ms. It stops receiving after some time on the GD32F130, but works on STM32F103.

Please let me know if there is anything else I can do to help. I tried to compare with some working SPL examples I know of, but it seems those use DMA.

maxgerhardt commented 1 year ago

Do you have an estimate of how many bytes get sent every 10ms? What is the approximate timespan after which it stops receiving?

Candas1 commented 1 year ago

18 bytes I will measure this when I am back home this evening.

Candas1 commented 1 year ago

Sorry for not providing feedback earlier. It fails after a minute or so, but I will experiment more and come back when I find the root cause and if I am sure it's due to arduino-gd32

maxgerhardt commented 1 year ago

I have a setup right now with a GD32F130C8 and a USB-to-serial adapter connected to it's Serial (PA9, PA10). I'm using this sketch

#include <Arduino.h>
#define LED PC13

void setup(void) {
    pinMode(LED, OUTPUT);
    Serial.begin(115200);
}

void loop(void) {
    Serial.println("Test");
    digitalWrite(LED, HIGH);
    if(Serial.available() > 0) {
        char buf[SERIAL_RX_BUFFER_SIZE + 1];
        size_t numRead = Serial.readBytes(buf, min(Serial.available(), sizeof(buf)));
        buf[numRead] = '\0';
        Serial.print("Received: ");
        Serial.println(buf);
    }
    delay(100);
    digitalWrite(LED, LOW);
    delay(100);
}

and I'm using hterm to do infinite-loop sending of data with 100ms time in between. So far, no crashes for 290 seconds.

grafik

maxgerhardt commented 1 year ago

Now I've played around with it quite a lot and written a custom python script to pump data faster into the chip than what hterm can do.

I indeed observed some weird behavior. It seems that after resets, the board can receive garbage data when the uart signals are already pumping at full speed during reset and initialization phase. Additionally I had a case where it would stop receiving data at all.

I've pushed https://github.com/CommunityGD32Cores/ArduinoCore-GD32/commit/32030ad620c7c0d3312ad5ec3740d46f1319d2ff and corrected some mistakes in the UART code. Specifically it resets the error flags (frame error, overrun error, parity error, noise error) properly per datasheet instructions (by clearing interrupt flags, not just reading the RDATA register). Since then I didn't have the situation of "stops receiving at all" anymore.

There still is the issue of receiving a bunch of garbaga data after reset for a few iterations (about 3 in my case) that I have not yet solved and are also running out if ideas... It may be due to the properties of UART itself.

grafik

(I am only ever sending 'A' so no P or other weird characters should ever ocurr...)

However, this commit may already be enough to resolve your issues. Can you retest your firmware?

And btw, updating is done with the PlatformIO Core CLI and

pio pkg update -g -p gd32
maxgerhardt commented 1 year ago

This reset issue is really weird. I've debugged it further and the hardware flags at the time of the RX interrupt are all fine: None of the error flags set, valid reception, and the UART0->RDATA register really contains 0x05 or 0x50 although 'A' (0x41) is only being sent. There are no bits set by the hardware to indicate that the RX data is bad. I think with some timing offset, when the MCU boots up / enables the UART in the middle of a UART transmission it may interepret the data transmission of 0x41 in the middle as a start bit, starts sampling in the middle of data, by chance gets a valid stop bit and returns that data. The HW can't tell the difference because time-shifted it may look like.

In any case, you may not be suffering from that reset issue when all microcontrollers in that system are turned on at the same time and when one sends, the other is ready to receive properly.

Candas1 commented 1 year ago

Sorry I was abroad and just came back. I tested my firmware again after your fixes and it ran without RX problems for 30 minutes so the issue is fixed for me. About the garbage you receive, can it be just transmission errors? In my firmware we use a Start frame and a XOR checksum to reject bad frames.