diff --git a/.gitignore b/.gitignore index a73b741..126e432 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /UKSSTMS320F28335.CS_/ /Bin/UKSSTMS320F28335_*.bin /Bin/LoggerFix/ +/Bin/LoggerEepromFix/ +/Bin/*.pending diff --git a/Doc/UMP_LOGGER.md b/Doc/UMP_LOGGER.md index e11f7bc..9a9283a 100644 --- a/Doc/UMP_LOGGER.md +++ b/Doc/UMP_LOGGER.md @@ -215,3 +215,27 @@ TI. Отдельно выполнена синтаксическая прове Для сборки v3 нужен templates/main начиная с коммита c0ee7c4 (поддержка CAN-чтения 42/84 слов и порт TMS320F28335). + +## Пересечение образа 34a95bc5 с параметрами EEPROM + +Образ `UKSSTMS320F28335_34a95bc5.bin` имеет размер 32518 байт. +`Save_params` записывает 129 слов с адреса `0x3FFF-(128+1)`; +драйвер EEPROM умножает адрес на 2. Параметры начинаются с байта 32508. +Последние 10 байт BIN пересекаются с параметрами: два последних адреса +таблицы переходов `ump_log_read` (регистры 0x100E/0x100F) и завершающее +нулевое слово загрузочной таблицы. Сохранение параметров повреждает эту +часть образа для последующей загрузки. Это установленный дефект образа; +причину таймаута на конкретной плате нужно подтвердить повторной проверкой. + +В исправлении временный снимок RS перенесён со стека в статический буфер: +обработчики RS вызываются последовательно из main, а перед возвратом +снимок полностью кодируется в собственный буфер UART. CAN имеет свой буфер. +Сборка `build_logger.ps1` использует параметры CCS Debug (-O1, speed=3) +и создаёт отдельный `Bin/LoggerEepromFix/UKSSTMS320F28335_logger_eeprom_fix.bin`. +Проверенный размер — 32494 байта, запас до параметров — 14 байт. + +Оба сценария сборки вызывают `check_firmware.ps1` до публикации BIN. +Проверяются размер, формат SCI8, полнота блоков и конец загрузочной таблицы. +При превышении границы остаётся только файл `.pending`; готовый BIN +не публикуется. Проверка: `python tests/ump_logger/test_firmware_image.py`. +После перепрошивки требуется проверка на плате; проверка на ПК её не заменяет. diff --git a/Source/Internal/message.c b/Source/Internal/message.c index a2947ff..8abaef2 100644 --- a/Source/Internal/message.c +++ b/Source/Internal/message.c @@ -200,7 +200,9 @@ static void modbus_exception(RS_DATA *rs_arr, unsigned int function, unsigned in static int receive_ump(RS_DATA *rs_arr) { unsigned int address, value, saved, length, count, error; - uint16_t words[UMP_MAX_WORDS]; + /* Main-loop only; encoded into the UART buffer before the next request. + * Keep the 124-word snapshot off the shared interrupt stack. */ + static uint16_t words[UMP_MAX_WORDS]; address = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3]; if (address < UMP_BASE) return 0; value = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5]; diff --git a/build_bin.bat b/build_bin.bat index 7bac309..ecbed48 100644 --- a/build_bin.bat +++ b/build_bin.bat @@ -10,7 +10,11 @@ if not defined GIT_COMMIT ( ) pushd "%SRC_ROOT%Bin" || exit /b 1 -hex2000.exe UKSSTMS320F28335.out -boot -sci8 -map UKSSTMS320F28335.map -o UKSSTMS320F28335_%GIT_COMMIT%.bin -b +hex2000.exe UKSSTMS320F28335.out -boot -sci8 -map UKSSTMS320F28335.map -o UKSSTMS320F28335_%GIT_COMMIT%.bin.pending -b set "BUILD_RESULT=%errorlevel%" +if not "%BUILD_RESULT%"=="0" goto finish +powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%SRC_ROOT%check_firmware.ps1" -Path "UKSSTMS320F28335_%GIT_COMMIT%.bin.pending" -PublishPath "UKSSTMS320F28335_%GIT_COMMIT%.bin" +set "BUILD_RESULT=%errorlevel%" +:finish popd exit /b %BUILD_RESULT% diff --git a/build_logger.ps1 b/build_logger.ps1 index bc34efa..73d5bd7 100644 --- a/build_logger.ps1 +++ b/build_logger.ps1 @@ -1,6 +1,7 @@ param( [string]$TemplatesRoot = "$PSScriptRoot/../newProject/SETGUI/third_party/templates", - [string]$CompilerRoot = 'C:/ti/ccs1230/ccs/tools/compiler/ti-cgt-c2000_22.6.0.LTS' + [string]$CompilerRoot = 'C:/ti/ccs1230/ccs/tools/compiler/ti-cgt-c2000_22.6.0.LTS', + [string]$OutputDirectory = "$PSScriptRoot/Bin/LoggerEepromFix" ) $ErrorActionPreference = 'Stop' $protocol = Join-Path (Resolve-Path -LiteralPath $TemplatesRoot).Path 'c/set-protocol' @@ -9,15 +10,16 @@ foreach ($required in @('src/ump_protocol.c', 'ports/tms320f28335/ump_tms28335.c throw "Missing $required in $protocol. Use templates with the UMP v3 port." } } -$output = Join-Path $PSScriptRoot 'Bin/LoggerFix' +$output = $OutputDirectory $objects = Join-Path $output 'obj' New-Item -ItemType Directory -Force -Path $objects | Out-Null $includes = @('Source/Internal/Include', 'Source/External/v120/DSP2833x_headers/include', 'Source/External/v120/DSP2833x_common/include') | ForEach-Object { "--include_path=$PSScriptRoot/$_" } $includes += @("--include_path=$CompilerRoot/include", "--include_path=$protocol", "--include_path=$protocol/ports/tms320f28335") -$flags = @('-v28', '-ml', '-mt', '--float_support=fpu32', '-O3', '--define=LARGE_MODEL', - '--abi=coffabi', '--disable_dp_load_opt', '--opt_for_speed=0', '--gen_func_subsections=on') +# Match the CCS Debug configuration used for 34a95bc5. +$flags = @('-v28', '-ml', '-mt', '--float_support=fpu32', '-O1', '--define=LARGE_MODEL', + '--define=_DEBUG', '--symdebug:dwarf', '--abi=coffabi', '--opt_for_speed=3') $external = @('DSP2833x_ADC_cal.asm', 'DSP2833x_Adc.c', 'DSP2833x_CpuTimers.c', 'DSP2833x_PieCtrl.c', 'DSP2833x_SWPrioritizedDefaultIsr.c', 'DSP2833x_SWPrioritizedPieVect.c', 'DSP2833x_SysCtrl.c', 'DSP2833x_Xintf.c', 'DSP2833x_usDelay.asm') @@ -30,13 +32,14 @@ foreach ($source in $sources) { if ($LASTEXITCODE -ne 0) { throw "Compilation failed: $source" } $objectFiles += Join-Path $objects ([IO.Path]::GetFileNameWithoutExtension($source) + '.obj') } -$name = 'UKSSTMS320F28335_logger_fix' +$name = 'UKSSTMS320F28335_logger_eeprom_fix' & "$CompilerRoot/bin/cl2000.exe" @flags -z "--map_file=$output/$name.map" --stack_size=0x3f0 --warn_sections ` "--search_path=$CompilerRoot/lib" --reread_libs --entry_point=_c_int00 --rom_model ` "--output_file=$output/$name.out" @objectFiles "$PSScriptRoot/F28335.cmd" ` "$PSScriptRoot/Source/External/v120/DSP2833x_headers/cmd/DSP2833x_Headers_nonBIOS.cmd" ` "$PSScriptRoot/Libraries/rts2800_fpu32.lib" if ($LASTEXITCODE -ne 0) { throw 'Link failed' } -& "$CompilerRoot/bin/hex2000.exe" "$output/$name.out" -boot -sci8 -map "$output/${name}_hex.map" -o "$output/$name.bin" -b +& "$CompilerRoot/bin/hex2000.exe" "$output/$name.out" -boot -sci8 -map "$output/${name}_hex.map" -o "$output/$name.bin.pending" -b if ($LASTEXITCODE -ne 0) { throw 'Binary conversion failed' } +& "$PSScriptRoot/check_firmware.ps1" -Path "$output/$name.bin.pending" -PublishPath "$output/$name.bin" Write-Output "Firmware: $output/$name.bin" diff --git a/check_firmware.ps1 b/check_firmware.ps1 new file mode 100644 index 0000000..335c8be --- /dev/null +++ b/check_firmware.ps1 @@ -0,0 +1,36 @@ +param( + [Parameter(Mandatory=$true)][string]$Path, + [string]$PublishPath +) +$ErrorActionPreference = 'Stop' +# Load_params/Save_params use word address 0x3FFF-(ANSWER_LEN+1). +# Seeprom_write converts that address to wire bytes (WORD_LEN=2). +$header = Get-Content -Raw -LiteralPath "$PSScriptRoot/Source/Internal/Include/message.h" +if ($header -notmatch '(?m)^#define\s+ANSWER_LEN\s+(0x[0-9a-fA-F]+|[0-9]+)') { + throw 'Cannot determine the EEPROM parameter reservation from ANSWER_LEN' +} +$registerCount = if ($Matches[1].StartsWith('0x')) { + [Convert]::ToInt32($Matches[1].Substring(2), 16) +} else { [int]$Matches[1] } +$limit = (0x3FFF - ($registerCount + 1)) * 2 +$bytes = [IO.File]::ReadAllBytes((Resolve-Path -LiteralPath $Path).Path) +if ($bytes.Length -gt $limit) { + throw "Firmware size $($bytes.Length) exceeds EEPROM firmware area $limit bytes; overlaps saved parameters by $($bytes.Length - $limit) bytes." +} +if ($bytes.Length -lt 30 -or [BitConverter]::ToUInt16($bytes, 0) -ne 0x08AA) { + throw 'Expected a C2000 SCI8 boot image' +} +$offset = 22 +$blocks = 0 +while ($true) { + if ($offset + 2 -gt $bytes.Length) { throw 'Missing boot table terminator' } + $words = [BitConverter]::ToUInt16($bytes, $offset) + $offset += 2 + if (!$words) { break } + $offset += 4 + 2 * $words + if ($offset -gt $bytes.Length) { throw 'Truncated boot table block' } + $blocks++ +} +if (!$blocks -or $offset -ne $bytes.Length) { throw 'Invalid boot table length' } +if ($PublishPath) { Move-Item -LiteralPath $Path -Destination $PublishPath -Force } +Write-Output "Verified SCI8 image: $($bytes.Length) bytes, $blocks blocks, $($limit - $bytes.Length) bytes before saved parameters." diff --git a/tests/ump_logger/test_firmware_image.py b/tests/ump_logger/test_firmware_image.py new file mode 100644 index 0000000..d05fec0 --- /dev/null +++ b/tests/ump_logger/test_firmware_image.py @@ -0,0 +1,55 @@ +"""Exercise the release gate without TI tools or hardware.""" +from pathlib import Path +import shutil +import struct +import subprocess +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[2] +LIMIT = (0x3FFF - (128 + 1)) * 2 + + +def image(size): + header = struct.pack('