in reply to Re^4: Win32::SerialPort, buffer overflow
in thread Win32::SerialPort, buffer overflow

There are also flow-control lines on the serial connection, so the device can indicate when it is ready to read or not.

Not all RS232 devices implement hardware flow control. Some don't implement anything but the bare minimum (GND, RxD, TxD).

Just last week, I've wired a new, major brand UPS to a small server. That UPS lacks USB for some unknown reason, but supports RS232. Of course, it does not use the usual PC pinout. That would be far too easy. And the official adapter cable just shorts the two main handshake pairs on the PC side (RTS to CTS and DCD to DTR). Only RxD, TxD and GND are connected to the UPS.

That server, by the way, has one RS232 with a PC pinout on a DB9 connector, and a second serial port on an internal pinheader with CMOS 3.3V levels lacking the handshake lines. They are present at the UART, but not connected to the pinheader.

From my experiance with modern ARM-based microcontrollers, RS232 works fine in home and office environments, even without handshake lines, and even at relatively high baud rates (115200 bit/s). The old 8-bit AVRs (and probably also the 8-bit PICs) can be problematic without handshake lines, they just can't get the data out of the UART receive buffer fast enough. If you connect a USB UART (e.g. FTDI FT232) close to the microcontroller board instead of using a long RS232 cable, ARM-based microcontrollers can even work at much higher speeds without handshake, up to the limits of the USB UART.

In an industrial environment, I would use something with differential signals instead (RS485, RS422, CAN), or a current loop (e.g. 4-20 mA), because those systems are almost immune to noise.

Do you have a breakout-box showing you those signals on LEDs?

At 38400 Bit/s, a data byte encodes to at least 10 bits (start, 8x data, stop), so you end up with up to 3840 Bytes/s. That's almost 4 bytes per ms, or 4 kHz. You won't be able to see an LED flashing at that speed, if one of the two devices sets or clears a handshake signal for a few bytes. That's just a limit of your wetware. You can hear a 4 kHz signal, but visually, you are limited to about 25 Hz.

At 300 Bit/s = 30 Bytes/s, you could clearly see the LEDs flickering. At 38400 Bit/s or more, you can just hope that the handshake lines change their level very often, so they effectively drive the LEDs with a PWM signal and make them change their apparant brightness.

If you want to see short signal changes, with a duty cycle close to 0 % or close to 100 %, you need an oscilloscope. At RS232 speeds, any cheap one with at least 2 Megasamples per second / 1 MHz bandwith will do. (Note that some people sell cheap junk kits that can't even measure outside the audio range.)

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
  • Comment on Re^5: Win32::SerialPort, buffer overflow

Replies are listed 'Best First'.
Re^6: Win32::SerialPort, buffer overflow
by jmClifford (Beadle) on Nov 18, 2024 at 05:51 UTC

    Hi.

    Thanks to NERDVANA and soonix and afoken. With respect to access to the RS232 serial, the module I am accessing is an OBD2 automotive module with a USB to serial chip embedded within a plastic sealed module. The handskaking on the serial port is switched off ("none" as indicated with the serial initialisation). Also, the initialisation also seems to suggest a buffering of 256 bytes in both directions.

    I have tried changing the size of the write (shorted and longer) but the issue still follows how the data is written to the sub Serial_TrxRcv($parameter). I have a "yucky" work around where I avoid taking the $ccmd (command) directly from the hash, but copy to a $newcmd variable in a very specific way. This is in the following code presentation.

    sub ProcessPIDs { # print "Inside ProcessPIDs \n"; # Process the input arguments my ( $nickname, $ref_nicknametocommand ) = @_; my %InSubNickNameToCommand = %{$ref_nicknametocommand}; # De-ref +rence the reference to an hash my $ccmd; $ccmd = $InSubNickNameToCommand{ $nickname }; # need E +RROR checking here !!!!!! my $newcmd ; if ($ccmd eq '0101') { $newcmd = '0101'; } elsif ($ccmd eq '0103') { $newcmd = '0103'; } elsif ($ccmd eq '0104') { $newcmd = '0104'; } elsif ($ccmd eq '0105') { $newcmd = '0105'; } elsif ($ccmd eq '0106') { $newcmd = '0106'; } elsif ($ccmd eq '0107') { $newcmd = '0107'; } elsif ($ccmd eq '010c') { $newcmd = '010c'; } elsif ($ccmd eq '010d') { $newcmd = '010d'; } elsif ($ccmd eq '010e') { $newcmd = '010e'; } elsif ($ccmd eq '010f') { $newcmd = '010f'; } elsif ($ccmd eq '0110') { $newcmd = '0110'; } elsif ($ccmd eq '0111') { $newcmd = '0111'; } elsif ($ccmd eq '0113') { $newcmd = '0113'; } elsif ($ccmd eq '0114') { $newcmd = '0114'; } elsif ($ccmd eq '0115') { $newcmd = '0115'; } elsif ($ccmd eq '011c') { $newcmd = '011c'; } elsif ($ccmd eq '0121') { $newcmd = '0121'; } elsif ($ccmd eq '012e') { $newcmd = '012e'; } elsif ($ccmd eq '012f') { $newcmd = '012f'; } elsif ($ccmd eq '013c') { $newcmd = '013c'; } elsif ($ccmd eq '0142') { $newcmd = '0142'; } elsif ($ccmd eq '0143') { $newcmd = '0143'; } elsif ($ccmd eq '0144') { $newcmd = '0144'; } elsif ($ccmd eq '0145') { $newcmd = '0145'; } elsif ($ccmd eq '0149') { $newcmd = '0149'; } elsif ($ccmd eq '014a') { $newcmd = '014a'; } elsif ($ccmd eq '014c') { $newcmd = '014c'; } else { print "Warning; failed to match $ccmd\n"; die "AMEN !\n"; } # my $newcmd = $ccmd; # this does not work print "\$ccmd; $ccmd ".length($ccmd). " \$newcmd; $newcmd ".length +($newcmd)."\n"; my $response = Serial_TrxRcv($newcmd); my $result; .... etc ...

    As indicated in the code above, I could not just copy with "my $newcmd = $ccmd" but had to involve an if statement. In this circumstance the $newcmd can be passed to the sub without the buffer error occurring.

    If the $newcmd is copied from a constant in the program then it works.

    It's hard to known if the issue is from a very fine timing problem with the serial port treatment or related to how perl reads from a simple scaler embedded with a hash. Please consider issues ?

    Regards JC....

      That... is a truly strange workaround you have there. I can't imagine how that is different from '=', nor do I expect it to change execution speed much. Is there any chance that the difference is the 'die' that stops you from sending any other codes?

      The most relevant "gotcha" compared to what you're doing here would be if something inside Serial_TrxRcv tried checking whether you gave it a number or a string, in which case $ccmd could have picked up a "dualvar" nature (both a number and a string) which gets removed by assigning a string constant (in certain perl versions). But, you already showed us the code of Serial_TrxRcv and the first thing in there concatenates it with "\r" which will always treat it as a string.