Skip to content

Commit

Permalink
send.py tries to avoid board reset for Linux/MacOS, receive process e…
Browse files Browse the repository at this point in the history
…xplained in README
  • Loading branch information
envenomator committed Jan 29, 2024
1 parent 6db935c commit 6fc149d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 19 deletions.
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,36 @@ The utility requires at least MOS version 1.02. Transfering data over the ESP US

hexload <uart1 [baudrate] | vdp> [filename]

This utility provides two options for transfering data:
Start the hexload receiver client on the Agon first, using a serial connectivity option as described below and *then* transfer Intel hex content from your PC to the serial interface. As Intel hex content doesn't provide a feedback mechanism to the sender, nor is there an option for hardware handshaking to control the flow between sender and hexload receiver, the receiver needs to be running *before* any transfer is started. If you do start the sender first, and the hexload receiver client later, it may just pick up what is left in the transmit buffer, transfering some content, but certainly not everything. In that case, just retry the process using the correct startup order.


The serial connectivity options are:
1. The UART1 serial port can be used at the external GPIO serial pins PC0/TxD1, PC1/RxD1 and GND. Connect to external serial interfaces (3.3v), like for example a USB-Serial FTDI adapter
![Multiple transfers using different baudrates and addresses](https://github.com/envenomator/agon-hexload/blob/master/media/uarttransfer.png?raw=true)

2. The ESP USB port that powers the Agon can be used, using the serial-over-USB interface it provides, without requiring a separate interface. This requires a VDP version of at least 1.04.
2. The ESP USB port that powers the Agon can be used, using the serial-over-USB interface it provides, without requiring a separate interface. This requires a VDP version of at least 1.04. As the serial settings are hardcoded in the VDP, there is no option to set the baudrate in the hexload client.
![A single transfer over the VDP serial](https://github.com/envenomator/agon-hexload/blob/master/media/vdptransfer.png?raw=true)

### Baudrate
The uart1 option has a selectable baudrate. If no baudrate is given, the default of 384000 is selected. The vdp option uses 115200 by default. The actual baudrate used is echoed to the user at startup.
The uart1 option has a selectable baudrate. If no baudrate is given, the default of 384000 is selected. The vdp option uses a hardcoded 115200 by default and isn't selectable in the hexload client. The actual baudrate used is echoed to the user at startup.

**Please be aware** that **achievable** baudrates in **your** setup may be much lower than this. Some users report baud rates well below 115200. The **achievable** baudrate without errors during transmission in your setup, will depend on factors like quality of your FTDI adapter, which IC is on it, which driver is loaded into the operating system for it to function, your operating system itself, but also which USB interface you are plugging it into.

Upon first use, it appears prudent to set an initially LOW baudrate value, potentially as low as 57600, or even 9600, to verify transmission. And only after this initial verification ramp up the speed an next attempts to see where you end up with your specific setup.

### Dump to file
The transfered data is dumped to a file when a filename is appended as last option.
The transfered data is dumped to a file when a filename is appended as last option. This is an add-on option; the data is always stored to memory at the location given in the Intel Hex file (or default address).

### Difference in feedback during transmission
During reception of Intel Hex files on the UART1, no feedback is given to the user before transmission is terminated by a 01 record. There is not enough CPU available to handle output while also processing the input at high speed.
Using the VDP does allow for feedback to the user during transmission. The VDP informs the user of every address record sent.

### Sending files
Intel Hex files must be sent in textformat, over one of the serial interfaces. I have provided an example send.py python script to automate this process, converting binary files to hex files on the fly before transfer. Edit your serial port and speed in the script as needed and provide the Intel Hex file as argument.
Intel Hex files must be sent in ascii format, over one of the serial interfaces. I have provided an example send.py python script to automate this process, converting binary files to hex files on the fly before transfer. The script tries to autodetect your serial port. If autodetection doesn't work, provide serial port and speed as argument to the script, or edit the relevant default settings in the script.

send.py filename <port> <baudrate>

In some cases using the VDP, the first time the ESP serial is used after a reboot, it can trigger the boot-mode from the ESP. Just press reset and try again, or set the ESP boot jumper to disabled.
Due to the way the VDP/serial interface is wired up (to bootstrap the ESP32 for programming), the board usually resets when the serial interface opens/closes. This means that a waiting hexload client is suddenly gone when a transfer is started. To avoid this, the script tries to set the DTR/CTS signals explicitly before starting the transfer. Boards with the CH340 FTDI chip may reset just the first time after power-up and not later on. Your mileage may vary; just press the reset button and try again, in the correct order.

### UART1 pinout
- Tx: GPIO pin PC0 - connect to your adapter serial Rx
Expand Down
60 changes: 47 additions & 13 deletions send.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
## Title: send.py
## Author: Jeroen Venema
## Created: 25/10/2022
## Last update: 11/09/2023

## Last update: 29/01/2024
##
## Edited by Steve Lovejoy for linux DTR issue.
##
## syntax
## send.py FILENAME <PORT> <BAUDRATE>
##
Expand All @@ -12,11 +14,12 @@
## 10/09/2023 Script converts binary file to Intel Hex during transmission.
## Using defaults as constants.
## 11/09/2023 Wait time variable introduced for handling PC serial drivers with low buffer memory
## 29/01/2024 OS-specific serial settings to prevent board reset upon opening of serial port

DEFAULT_START_ADDRESS = 0x40000
DEFAULT_SERIAL_PORT = 'COM11'
DEFAULT_SERIAL_PORT = 'COM11'
DEFAULT_BAUDRATE = 115200
DEFAULT_LINE_WAITTIME = 0 ## A value of +/- 0.003 Helps PC serial drivers with low buffer memory
DEFAULT_LINE_WAITTIME = 0.003 ## A value of +/- 0.003 Helps PC serial drivers with low buffer memory

def errorexit(message):
print(message)
Expand All @@ -27,9 +30,18 @@ def errorexit(message):

import sys
import time
import os
import os.path
import tempfile
import serial.tools.list_ports

if(os.name == 'posix'): # termios only exists on Linux
DEFAULT_SERIAL_PORT = '/dev/ttyUSB0'
try:
import termios
except ModuleNotFoundError:
errorexit('Please install the \'termios\' module with pip')

try:
import serial
except ModuleNotFoundError:
Expand All @@ -40,18 +52,16 @@ def errorexit(message):
errorexit('Please install the \'intelhex\' module with pip')



if len(sys.argv) == 1 or len(sys.argv) >4:
sys.exit('Usage: send.py FILENAME <PORT> <BAUDRATE>')

if not os.path.isfile(sys.argv[1]):
sys.exit(f'Error: file \'{sys.argv[1]}\' not found')

if len(sys.argv) == 2:
#serialport = DEFAULT_SERIAL_PORT
serialports = serial.tools.list_ports.comports()
if len(serialports) > 1:
sys.exit("Multiple COM ports - cannot automatically select");
sys.exit("Multiple serial ports present - cannot automatically select");
serialport = str(serialports[0]).split(" ")[0]
if len(sys.argv) >= 3:
serialport = sys.argv[2]
Expand All @@ -67,7 +77,7 @@ def errorexit(message):
print(f'Sending \'{sys.argv[1]}\' ', end="")
if nativehexfile: print('as native hex file')
else:
print('in Intel Hex format')
print('as binary data, in Intel Hex format')
print(f'Using start address 0x{DEFAULT_START_ADDRESS:x}')
print(f'Using serial port {serialport}')
print(f'Using Baudrate {baudrate}')
Expand All @@ -83,15 +93,39 @@ def errorexit(message):
ihex.write_hex_file(file)
file.seek(0)

resetPort = False

if(os.name == 'posix'):
if resetPort == False:
# to be able to suppress DTR, we need this
f = open(serialport)
attrs = termios.tcgetattr(f)
attrs[2] = attrs[2] & ~termios.HUPCL
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
f.close()
else:
f = open(serialport)
attrs = termios.tcgetattr(f)
attrs[2] = attrs[2] | termios.HUPCL
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
f.close()

ser = serial.Serial()
ser.baudrate = baudrate
ser.port = serialport
ser.setDTR(False)
ser.setRTS(False)
ser.timeout = 2

# OS-specific serial dtr/rts settings
if(os.name == 'nt'):
ser.setDTR(False)
ser.setRTS(False)
if(os.name == 'posix'):
ser.rtscts = False # not setting to false prevents communication
ser.dsrdtr = resetPort # determines if Agon resets or not

try:
ser.open()
print('Opening serial port...')
time.sleep(1)
print('Sending data...')

if nativehexfile:
Expand All @@ -103,9 +137,9 @@ def errorexit(message):
ser.write(str(line).encode('ascii'))
time.sleep(DEFAULT_LINE_WAITTIME)

#time.sleep(1)
print('Done')
ser.close()
except serial.SerialException:
errorexit('Error: serial port unavailable')

file.close()
file.close()

0 comments on commit 6fc149d

Please sign in to comment.