fix more race with ch32v203 and setup when queuing zlp.

improve hil test failed output
This commit is contained in:
hathach 2024-08-12 16:39:25 +07:00
parent 7a9ef9e7bd
commit a621c4b6fc
No known key found for this signature in database
GPG Key ID: 26FAB84F615C3C52
3 changed files with 73 additions and 47 deletions

View File

@ -345,12 +345,14 @@ static void handle_ctr_rx(uint32_t ep_id) {
if ((rx_count < xfer->max_packet_size) || (xfer->queued_len >= xfer->total_len)) { if ((rx_count < xfer->max_packet_size) || (xfer->queued_len >= xfer->total_len)) {
// all bytes received or short packet // all bytes received or short packet
dcd_event_xfer_complete(0, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true);
// For ch32v203: reset rx bufsize to mps to prevent race condition to cause PMAOVR (occurs with msc write10) // For ch32v203: reset rx bufsize to mps to prevent race condition to cause PMAOVR (occurs with msc write10)
// also ch32 seems to unconditionally accept ZLP on EP0 OUT, which can incorrectly use queued_len of previous
// transfer. So reset total_len and queued_len to 0.
btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, xfer->max_packet_size); btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, xfer->max_packet_size);
dcd_event_xfer_complete(0, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true);
// ch32 seems to unconditionally accept ZLP on EP0 OUT, which can incorrectly use queued_len of previous
// transfer. So reset total_len and queued_len to 0.
xfer->total_len = xfer->queued_len = 0; xfer->total_len = xfer->queued_len = 0;
} else { } else {
// Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always // Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always
@ -412,11 +414,6 @@ void dcd_int_handler(uint8_t rhport) {
FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF;
} }
if (int_status & USB_ISTR_PMAOVR) {
TU_BREAKPOINT();
FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_PMAOVR;
}
// loop to handle all pending CTR interrupts // loop to handle all pending CTR interrupts
while (FSDEV_REG->ISTR & USB_ISTR_CTR) { while (FSDEV_REG->ISTR & USB_ISTR_CTR) {
// skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt // skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt
@ -459,6 +456,11 @@ void dcd_int_handler(uint8_t rhport) {
handle_ctr_tx(ep_id); handle_ctr_tx(ep_id);
} }
} }
if (int_status & USB_ISTR_PMAOVR) {
TU_BREAKPOINT();
FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_PMAOVR;
}
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -806,6 +808,10 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
ep_write(ep_idx, ep_reg, true); ep_write(ep_idx, ep_reg, true);
} }
//--------------------------------------------------------------------+
// PMA read/write
//--------------------------------------------------------------------+
// Write to packet memory area (PMA) from user memory // Write to packet memory area (PMA) from user memory
// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT // - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
// - Uses unaligned for RAM (since M0 cannot access unaligned address) // - Uses unaligned for RAM (since M0 cannot access unaligned address)

View File

@ -285,8 +285,9 @@ TU_ATTR_ALWAYS_INLINE static inline void btable_set_rx_bufsize(uint32_t ep_id, u
/* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10); uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10);
if (bl_nb == 0) { if (bl_nb == 0) {
// zlp but 0 is invalid value, set num_block to 1 (2 bytes) // zlp but 0 is invalid value, set blsize to 1 (32 bytes)
bl_nb = 1 << 10; // Note: lower value can cause PMAOVR on setup with ch32v203
bl_nb = 1 << 15;
} }
#ifdef FSDEV_BUS_32BIT #ifdef FSDEV_BUS_32BIT

View File

@ -36,7 +36,7 @@ import glob
import platform import platform
from multiprocessing import Pool from multiprocessing import Pool
ENUM_TIMEOUT = 30 ENUM_TIMEOUT = 20
# get usb serial by id # get usb serial by id
@ -110,7 +110,8 @@ def run_cmd(cmd):
#print(cmd) #print(cmd)
r = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) r = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if r.returncode != 0: if r.returncode != 0:
title = 'command error' title = f'COMMAND FAILED: {cmd}'
print()
if os.getenv('CI'): if os.getenv('CI'):
print(f"::group::{title}") print(f"::group::{title}")
print(r.stdout.decode("utf-8")) print(r.stdout.decode("utf-8"))
@ -198,14 +199,15 @@ def flash_esptool(board, firmware):
# ------------------------------------------------------------- # -------------------------------------------------------------
# Tests # Tests
# ------------------------------------------------------------- # -------------------------------------------------------------
def test_board_test(id): def test_board_test(board):
# Dummy test # Dummy test
pass pass
def test_cdc_dual_ports(id): def test_cdc_dual_ports(board):
port1 = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 0) uid = board['uid']
port2 = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 2) port1 = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0)
port2 = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 2)
ser1 = open_serial_dev(port1) ser1 = open_serial_dev(port1)
ser2 = open_serial_dev(port2) ser2 = open_serial_dev(port2)
@ -224,9 +226,10 @@ def test_cdc_dual_ports(id):
assert ser2.read(100) == str2.upper(), 'Port2 wrong data' assert ser2.read(100) == str2.upper(), 'Port2 wrong data'
def test_cdc_msc(id): def test_cdc_msc(board):
uid = board['uid']
# Echo test # Echo test
port = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 0) port = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0)
ser = open_serial_dev(port) ser = open_serial_dev(port)
str = b"test_str" str = b"test_str"
@ -235,7 +238,7 @@ def test_cdc_msc(id):
assert ser.read(100) == str, 'CDC wrong data' assert ser.read(100) == str, 'CDC wrong data'
# Block test # Block test
data = read_disk_file(id, 'README.TXT') data = read_disk_file(uid, 'README.TXT')
readme = \ readme = \
b"This is tinyusb's MassStorage Class demo.\r\n\r\n\ b"This is tinyusb's MassStorage Class demo.\r\n\r\n\
If you find any bugs or get any questions, feel free to file an\r\n\ If you find any bugs or get any questions, feel free to file an\r\n\
@ -244,26 +247,28 @@ issue at github.com/hathach/tinyusb"
assert data == readme, 'MSC wrong data' assert data == readme, 'MSC wrong data'
def test_cdc_msc_freertos(id): def test_cdc_msc_freertos(board):
test_cdc_msc(id) test_cdc_msc(board)
def test_dfu(id): def test_dfu(board):
uid = board['uid']
# Wait device enum # Wait device enum
timeout = ENUM_TIMEOUT timeout = ENUM_TIMEOUT
while timeout: while timeout:
ret = subprocess.run(f'dfu-util -l', ret = subprocess.run(f'dfu-util -l',
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout = ret.stdout.decode() stdout = ret.stdout.decode()
if f'serial="{id}"' in stdout and 'Found DFU: [cafe:4000]' in stdout: if f'serial="{uid}"' in stdout and 'Found DFU: [cafe:4000]' in stdout:
break break
time.sleep(1) time.sleep(1)
timeout = timeout - 1 timeout = timeout - 1
assert timeout, 'Device not available' assert timeout, 'Device not available'
f_dfu0 = f'dfu0_{id}' f_dfu0 = f'dfu0_{uid}'
f_dfu1 = f'dfu1_{id}' f_dfu1 = f'dfu1_{uid}'
# Test upload # Test upload
try: try:
@ -272,10 +277,10 @@ def test_dfu(id):
except OSError: except OSError:
pass pass
ret = run_cmd(f'dfu-util -S {id} -a 0 -U {f_dfu0}') ret = run_cmd(f'dfu-util -S {uid} -a 0 -U {f_dfu0}')
assert ret.returncode == 0, 'Upload failed' assert ret.returncode == 0, 'Upload failed'
ret = run_cmd(f'dfu-util -S {id} -a 1 -U {f_dfu1}') ret = run_cmd(f'dfu-util -S {uid} -a 1 -U {f_dfu1}')
assert ret.returncode == 0, 'Upload failed' assert ret.returncode == 0, 'Upload failed'
with open(f_dfu0) as f: with open(f_dfu0) as f:
@ -288,14 +293,16 @@ def test_dfu(id):
os.remove(f_dfu1) os.remove(f_dfu1)
def test_dfu_runtime(id): def test_dfu_runtime(board):
uid = board['uid']
# Wait device enum # Wait device enum
timeout = ENUM_TIMEOUT timeout = ENUM_TIMEOUT
while timeout: while timeout:
ret = subprocess.run(f'dfu-util -l', ret = subprocess.run(f'dfu-util -l',
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout = ret.stdout.decode() stdout = ret.stdout.decode()
if f'serial="{id}"' in stdout and 'Found Runtime: [cafe:4000]' in stdout: if f'serial="{uid}"' in stdout and 'Found Runtime: [cafe:4000]' in stdout:
break break
time.sleep(1) time.sleep(1)
timeout = timeout - 1 timeout = timeout - 1
@ -303,10 +310,11 @@ def test_dfu_runtime(id):
assert timeout, 'Device not available' assert timeout, 'Device not available'
def test_hid_boot_interface(id): def test_hid_boot_interface(board):
kbd = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'event-kbd') uid = board['uid']
mouse1 = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'if01-event-mouse') kbd = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'event-kbd')
mouse2 = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'if01-mouse') mouse1 = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'if01-event-mouse')
mouse2 = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'if01-mouse')
# Wait device enum # Wait device enum
timeout = ENUM_TIMEOUT timeout = ENUM_TIMEOUT
while timeout: while timeout:
@ -338,22 +346,23 @@ all_tests = [
] ]
def test_board(item): def test_board(board):
name = item['name'] name = board['name']
flasher = item['flasher'].lower() flasher = board['flasher'].lower()
# default to all tests # default to all tests
if 'tests' in item: if 'tests' in board:
test_list = item['tests'] + ['board_test'] test_list = board['tests'] + ['board_test']
else: else:
test_list = list(all_tests) test_list = list(all_tests)
# remove skip_tests # remove skip_tests
if 'tests_skip' in item: if 'tests_skip' in board:
for skip in item['tests_skip']: for skip in board['tests_skip']:
if skip in test_list: if skip in test_list:
test_list.remove(skip) test_list.remove(skip)
err_count = 0
for test in test_list: for test in test_list:
fw_dir = f'cmake-build/cmake-build-{name}/device/{test}' fw_dir = f'cmake-build/cmake-build-{name}/device/{test}'
if not os.path.exists(fw_dir): if not os.path.exists(fw_dir):
@ -367,19 +376,26 @@ def test_board(item):
# flash firmware. It may fail randomly, retry a few times # flash firmware. It may fail randomly, retry a few times
for i in range(3): for i in range(3):
ret = globals()[f'flash_{flasher}'](item, fw_name) ret = globals()[f'flash_{flasher}'](board, fw_name)
if ret.returncode == 0: if ret.returncode == 0:
break break
else: else:
print(f'Flashing failed, retry {i+1}') print(f'Flashing failed, retry {i+1}')
time.sleep(1) time.sleep(1)
assert ret.returncode == 0, 'Flash failed\n' + ret.stdout.decode() if ret.returncode == 0:
try:
# run test ret = globals()[f'test_{test}'](board)
globals()[f'test_{test}'](item['uid']) print('OK')
print('OK') except AssertionError as e:
err_count += 1
print('Failed')
print(f' {e}')
else:
err_count += 1
print('Flash failed')
return err_count
def main(): def main():
""" """
@ -404,8 +420,11 @@ def main():
else: else:
config_boards = [e for e in config['boards'] if e['name'] in boards] config_boards = [e for e in config['boards'] if e['name'] in boards]
err_count_list = 0
with Pool(processes=os.cpu_count()) as pool: with Pool(processes=os.cpu_count()) as pool:
pool.map(test_board, config_boards) err_count_list = pool.map(test_board, config_boards)
sys.exit(sum(err_count_list))
if __name__ == '__main__': if __name__ == '__main__':