this post was submitted on 04 Nov 2025
18 points (100.0% liked)

Ask Electronics

3881 readers
2 users here now

For questions about component-level electronic circuits, tools and equipment.

Rules

1: Be nice.

2: Be on-topic (eg: Electronic, not electrical).

3: No commercial stuff, buying, selling or valuations.

4: Be safe.


founded 2 years ago
MODERATORS
 

So I am working on an Arduino project and have trouble communicating over UART.

I have a SIM7600G-H 4G Module from Waveshare and hooked it up to an Arduino Nano ESP32. The connections are as follows:

SIM7600<->Nano ESP32

TXD<->RX0

RXD<->TX0

VIN<->VUSB

GND<->GND

CTS<->D3

RTS<->D12

It mostly works, I can send AT commands and receive responds. However sometimes I only receive parts and chunks are missing or being send to the next command. I strongly suspect RSPs ("unsolicited result code") to be the reason behind it. As documented in the manual RSPs are being send without an implicit action and happens for example if the module receives a call or SMS.

I have read about hardware flow control which seems to theoretically solve the problem of those module talking over each other and have connected the CTS and RTS pins to generic digital pins. According the manual the SIM Module it has hardware flow control enabled as an default.

On the Arduino side of things I have added these lines in hopes of enabling it, however I do not see a change, they do not return any error but I still see data missing. I have also tried swapping CTS and RTS just for fun, but without any luck.

Serial0.setPins(-1,-1,12,3);
Serial0.setHwFlowCtrlMode(UART_HW_FLOWCTRL_CTS_RTS);

Here are the logs which shows some responds being cut off.

20:57:47.991 -> Send AT command: AT
20:57:47.991 -> Response: AT
20:57:47.991 -> OK
20:57:47.991 -> 
20:57:47.992 -> Send AT command: AT+CPIN=1234
20:57:47.992 -> Response: AT+CPIN=1234      <- This responds ending is cut off
20:57:47.992 -> Send AT command: AT+CSQ
20:57:48.025 -> Response:                    <- This responds start is cut off
20:57:48.025 -> OK
20:57:48.025 -> 
20:57:48.025 -> Send AT command: AT+CREG=1
20:57:48.059 -> Response: AT+CREG=1
20:57:48.059 -> OK
20:57:48.059 -> 

And this is my function to send those commands.

char* SIMClass::send(const char* command) {
  // Clear buffer
  while (Serial0.available() > 0) Serial0.read();
  Serial.print("Send AT command: ");
  Serial.println(command);

  unsigned long timeout = millis() + 10000;
  char* response = (char*)malloc(1024 * sizeof(char));
  uint16_t index = 0;

  Serial0.print(command);
  Serial0.print("\r");


  while (Serial0.available() == 0) {
    if (millis() > timeout) {
      response[index] = '\0';
      return response;
    }
  }

  while (Serial0.available() > 0) {
    response[index++] = Serial0.read();
    timeout = millis() + 1000;
  }
  response[index] = '\0';
  Serial.print("Response: ");
  Serial.println(response);
  return response;
}

After enabling hardware flow control unsing Serial0.setHwFlowCtrlMode(UART_HW_FLOWCTRL_CTS_RTS) I expected Serial0.print(message) to wait until the SIM module is not busy and vice versa. Am I wrong in that assumption? Am I missing something else or is it maybe recommend to implement the hardware flow yourself?

top 13 comments
sorted by: hot top controversial new old
[–] bitfucker@programming.dev 7 points 5 days ago* (last edited 5 days ago) (2 children)

~~I assume you mean RXD to TX0. As for sporadic packets like that, I'd honestly check for the signal integrity. Maybe somehow the data line is picking up noise high enough to cause disturbance. It could be caused by a lot of things, but the most likely culprit are the connector/cable. Any connection going into/out of pcb should be checked. Or check your timing. Make sure the baud and other config (start, data, stop, parity) are matched. Small drift in baudrate is usually tolerable. UART is designed for async communication after all, meaning that any device may send anytime so CTS and RTS isn't usually needed provided that it is a hardware UART (not bit banging). You can check out Ben Eater video about it. In short, the TX is usually held high, the RX then can detect a falling edge which is a signal that a packet is starting. The UART hardware then processes the signal according to the config that you give it and is usually able to do a DMA transfer.~~

Edit: Ahh, after reading the code I suspect that your code processes the data faster than the module can send the full reply. The first loop that you are waiting for the first data to arrive, you immediately process everything in the buffer until it is empty, not knowing that maybe the module has not yet finished transmitting. CTS and RTS would not help since they are used to signal if both devices would like to (or probably could) send / receive data. Not signalling end of data transfer

Edit 2, the solution: Either parse the received packet until the expected end, or wait until timeout before returning.

[–] bvoigtlaender@feddit.org 3 points 4 days ago (1 children)

Thank you so much. That might actually be it. I didn't had the time to fully implement that yesterday but will be today. I did however put in a sleep() after waiting for the buffer and reading it to validate your thesis, which results in complete data!! ^^

Arduino even has an function for that readBytesUntil. However in my short testings yesterday in seemed to always stop on new lines, even if I set the char for it to stop on to something really silly. Reading it and implementing that stop on my own worked better. I wanna do it the "official" way though, it would then even respect an timeout set by setTimeout

I will probably end up having CTS and RTS anyway cause I couldn’t make sure that the module starts to talk all of the sudden.

I hate that the answer to my problems are always the most stupid ones. I kinda wish it would have been signal integrity, but I would probably regret that real fast too. :)

[–] bitfucker@programming.dev 3 points 3 days ago

Yeah, CTS and RTS is useful for the module since you may overflow the module buffer (instead of the module overflowing your UART buffer). With proper HW flow control, hopefully your device UART respects the signal and pauses the tx until it is clear again without you having to code the pause yourselves. It can happen when the GSM bandwidth is lower than the UART bandwidth.

The module suddenly talking should also be handled by your device UART gracefully. When your rx buffer is full for whatever reason (not reading it for a long time?), the module won't be sending anymore data until you read your rx buffer. Theoretically, no data should be lost that way.

[–] ChrysanthemumIndica@discuss.tchncs.de 5 points 5 days ago (2 children)

I'd like to concur about reading the receive buffer faster than it is filled!

Hopefully there is some end of line character that can be parsed for, but if not, a timeout should be fine like you said.

Curious what baud rate is being used.

[–] bvoigtlaender@feddit.org 2 points 4 days ago

The Serial on the ESP is set to 115200 as is the default of the module but can be overridden using commands. I should probably double check that. :) However I would assume that having a different baud rate would result in more errors than I am currently experiencing.

[–] bitfucker@programming.dev 5 points 5 days ago (1 children)

Since the posts are about SIM7600, and the example shows, it's probably AT Command. So always newline delimited (either \r or \r\n)

That's fair, and sort of what I assumed, but I don't quite have the experience to say for a fact, so much appreciated!

Ironically I've only done modem stuff when I was very young and also somehow most of last year. But also maybe I get a little paranoid when it comes to talking to devices, and maybe I'm extrapolating my current i2c woes too far 😅

[–] j4k3@lemmy.world 6 points 5 days ago (1 children)

You need a little $5 FX2 board based logic analyser and the FOSS software PulseView to see the data.

You should check that baud rate is matched. In particular, you may need to look at the clock rates of the chip and how its PLL is divided. Back in the day, you actually had to pick the correct crystal frequency to match things like a desired baud rate. Now, most hardware is more tolerant of differences. When you are dealing with more simple hardware, it still matters.

[–] bvoigtlaender@feddit.org 3 points 5 days ago (2 children)

I will definitely get an logic analyzer, looks like it will come in handy more times than one. Thanks for the recommendation.

Even though I expect it too be too quickly really debug it (?!). Ill try to get some more info about what the CTS of the module actually says when sending stuff.

I was hoping that the error was a bit more high level than that though most of the data is actually being received fine. I have edited the post and have attached a log showing the problem.

[–] j4k3@lemmy.world 3 points 5 days ago* (last edited 5 days ago) (1 children)

So one of the tricks I learned from reverse engineering the 3 layer PCB of the Nintendo Game & Watch anniversary Mario handheld, is that the engineer(s) that designed the board routed ground traces between every single line. Every button, and every signal had a ground trace around it with very few exceptions. I was given some low quality xrays of the board after I had already retraced the entire thing using continuity and vias. I then pieced together the internal routing using the xrays.

My point is that all signals on a board include a magnetic component. Electrons actually flow backwards from ground because all electrons have a negative charge. We think of conventional current flow from positive to negative, but that is technically incorrect. There is a magnetic field that is created by that flow, and the size of issues this field creates are primary determined by any additional distance traveled between the signal and ground.

Additionally, you may have brown out conditions periodically impacting one peripheral. Something like a UART module seems like a small thing, but back in the 1980s, that was an entire chip on a board of a microprocessor. It has a ring buffer and several registers. It may be causing issues when these are loaded up with high values. Try increasing the capacitance on your power rails to see if that solves the problem.

I do not know the output configuration. If it is an open collector, where pull up resistors are used, you need to select the best resistor value to get sharp edges. You may need to check that the logic low value is within the required range of values. You could put a Schmitt triggered buffer in between the devices to see if sharp edges improve performance like with a 74(x)2G17 for a modern 2 gate surface mounted option or with a more old school 74(x)241. The (x) is the series, which you select for architecture and speed. For almost everything, you will be using CMOS 74 series, and in most instances, 74HC will be fast enough. Generally speaking, 74LS is only compatible with old bjt stuff, 74HCT is for converting between LS and HC type stuff, and most LS and HC stuff will not work together. The static HC stuff is MUCH lower power and what most chips use. You just need to be sure to match the power to your devices. This page will help you find logic stuff for this type of issue: https://en.wikipedia.org/wiki/List_of_7400-series_integrated_circuits. It is totally overkill, but tossing in a buffer with sharp Schmitt triggered edges is a quick hack to see if your issue is potentially related to RLC or grounding.

For the FX2 chip. They come in 2 varieties. Don't get the one in the little enclosure with just 8 lines. There is another cheap board that is bare and has all of the chip pins broken out and labeled in the solder mask. This one works with up to 16 channels. It can be super handy to see all the extra signal lines or create extra trigger signals.

The actual developer of Pulse View has a tutorial here: https://www.youtube.com/watch?v=dobU-b0_L1I

[–] jet@hackertalks.com 2 points 13 hours ago (1 children)

What was the benefit of surrounding every trace with ground? Reduced crosstalk?

[–] j4k3@lemmy.world 2 points 12 hours ago

Yeah, fast edges on the buttons. I think the whole design was originally intended to be 2 sided. The third layer has almost a complete ground plane, and the other two have sufficient infill and stitching to be a typical 2 sided design. Stuff would have needed to be moved around some to make room for the button contacts, but there was more than enough space.

From what I recall of the guys doing the software hack, I think the STM32 H7 microcontroller was emulating the original 6502 based ROM. So maybe they were optimising the hardware as much as possible to avoid the typical timing issues present in emulation in challenging parts of the game.

The coolest part of the hardware design is actually that little DC switch mode converter and battery manager. It is crazy efficient. Like, a full charge on the lithium cell will be at around half charged still after a couple of years, and while playing, it lasts abnormally long for such a device. It is not a particularly large cell either.

[–] j4k3@lemmy.world 2 points 5 days ago

This is the one you want with 16 channels