Compare commits
22 Commits
ccs12
...
pm35-uart-
| Author | SHA1 | Date | |
|---|---|---|---|
| 04a9d989fb | |||
| fa20ed085b | |||
| 13e5bfe373 | |||
| 3ebfdca0a0 | |||
| fabd1bdf99 | |||
| 1e911e5250 | |||
| f741741cf8 | |||
| 378e06a281 | |||
| 5d9818291b | |||
| c6c9128238 | |||
| 419d6b17dc | |||
| e3d43ef279 | |||
| 34a95bc553 | |||
| 1ce42a1877 | |||
| 316dd52f99 | |||
| 2a9f42331c | |||
| ee7dce4615 | |||
| a3633d8ede | |||
| df719229b7 | |||
| 799e6ba46d | |||
| 341f194b4d | |||
| ed9680a36e |
6
.editorconfig
Normal file
6
.editorconfig
Normal file
@@ -0,0 +1,6 @@
|
||||
# Общая кодировка редактируемых файлов проекта.
|
||||
root = true
|
||||
|
||||
# Русские комментарии сохраняются без BOM в UTF-8.
|
||||
[*]
|
||||
charset = utf-8
|
||||
59
.gitignore
vendored
59
.gitignore
vendored
@@ -1,5 +1,60 @@
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Debug/
|
||||
/Release/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/UKSSTMS320F28335.CS_/
|
||||
/Doc/build/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/UKSSTMS320F28335_*.bin
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/LoggerFix/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/LoggerEepromFix/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/Rs232FifoTest/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/Rs232NoFifoTest/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/UartFifoTest/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/*.pending
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/UKSSTMS320F28335/Generated/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/FirmwareIdentity/
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/*.bin.manifest.json
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/Bin/*.bin.sha256
|
||||
# Кэш Python восстанавливается автоматически и не относится к исходникам прошивки.
|
||||
**/__pycache__/
|
||||
# Загруженные локальные инструменты документации не нужны для хранения изменений проекта.
|
||||
/Doc/.tools/
|
||||
# HTML-документация и диагностические журналы Doxygen создаются из исходных документов.
|
||||
/Doc/build/
|
||||
# Объекты компиляции восстанавливаются скриптами сборки и зависят от локальных инструментов TI.
|
||||
/Bin/**/obj/
|
||||
# Паспорт и заголовок конкретной сборки генерируются перед компиляцией из версии и состояния Git.
|
||||
/Bin/**/generated/
|
||||
# Исполняемые образы TI в экспериментальных каталогах являются результатом компиляции.
|
||||
/Bin/**/*.out
|
||||
# Карты новых сборок воспроизводятся линкером; ранее отслеживаемые карты остаются в Git.
|
||||
/Bin/**/*.map
|
||||
# HEX новых сборок дублирует локальные OUT/BIN; уже отслеживаемые образы сохраняются в истории.
|
||||
/Bin/**/*.hex
|
||||
# Листинги TI создаются из OUT для проверки порядка машинных инструкций EEPROM.
|
||||
/Bin/**/*disassembly*.txt
|
||||
# Кандидат SCI8 предназначен для проверки перед выпуском окончательного образа.
|
||||
/Bin/**/*.candidate
|
||||
# Локальные загрузочные образы пересоздаются из исходников и скриптов соответствующей сборки.
|
||||
/Bin/**/*.bin
|
||||
# Манифест конкретного образа содержит время и состояние локальной сборки.
|
||||
/Bin/**/*.bin.manifest.json
|
||||
# Контрольная сумма создаётся вместе с локальным загрузочным образом.
|
||||
/Bin/**/*.bin.sha256
|
||||
# Журналы компиляции и диагностики зависят от локального запуска инструментов.
|
||||
/Bin/**/*.log
|
||||
# Копии паспорта в каталогах с отметкой времени дублируют генерируемые метаданные сборки.
|
||||
/Bin/**/firmware_identity.json
|
||||
# Снимки интерфейса, использованные для проверки состава каналов, являются локальными артефактами.
|
||||
/Bin/**/logger_channels.png
|
||||
# Снимки предпросмотра защиты используются только при визуальной проверке интерфейса.
|
||||
/Bin/**/gui_preview.png
|
||||
|
||||
1
Bin/.gitignore
vendored
1
Bin/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
# Исключает из Git артефакты по шаблону ниже.
|
||||
/UKSSTMS320F28335.out
|
||||
|
||||
3
Bin/CCS12/.gitignore
vendored
3
Bin/CCS12/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
# CCS 12 output files
|
||||
*
|
||||
!.gitignore
|
||||
41
Bin/EepromPublishFix/rebuild.py
Normal file
41
Bin/EepromPublishFix/rebuild.py
Normal file
File diff suppressed because one or more lines are too long
BIN
Bin/GAS_M95M02/UKSSTMS320F28335_GAS_M95M02.bin
Normal file
BIN
Bin/GAS_M95M02/UKSSTMS320F28335_GAS_M95M02.bin
Normal file
Binary file not shown.
41
Bin/GAS_M95M02/UKSSTMS320F28335_GAS_M95M02.bin.manifest.json
Normal file
41
Bin/GAS_M95M02/UKSSTMS320F28335_GAS_M95M02.bin.manifest.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"product": "Balsam-167-PM35",
|
||||
"target": "TMS320F28335",
|
||||
"version": [
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"build_id": "c6c9128+",
|
||||
"built_at_utc": "2026-10-09T13:10:25+00:00",
|
||||
"source": {
|
||||
"commit": "c6c91282387adc789a7ebbc6f7e763d02b549789",
|
||||
"dirty": true
|
||||
},
|
||||
"templates": {
|
||||
"commit": "86ece3ea907cc92db73390eaae7551dd01b54e2c",
|
||||
"dirty": true
|
||||
},
|
||||
"identity_contract": 1,
|
||||
"identity_register_count": 12,
|
||||
"eeprom": "M95M02",
|
||||
"eeprom_bytes": 262144,
|
||||
"firmware_limit_bytes": 261884,
|
||||
"gas": {
|
||||
"enabled": true,
|
||||
"version": 1,
|
||||
"profile": 167,
|
||||
"info_words": 8,
|
||||
"register_count": 128,
|
||||
"transports": [
|
||||
"modbus_rtu",
|
||||
"ump_service_can"
|
||||
],
|
||||
"info_base": 24320,
|
||||
"register_base": 20480
|
||||
},
|
||||
"file": "UKSSTMS320F28335_GAS_M95M02.bin",
|
||||
"size_bytes": 33174,
|
||||
"sha256": "a1c186e5f114ea2f77ac5f18a60424c79f53b1e3a49e0343ac9bd96979f0347e"
|
||||
}
|
||||
1
Bin/GAS_M95M02/UKSSTMS320F28335_GAS_M95M02.bin.sha256
Normal file
1
Bin/GAS_M95M02/UKSSTMS320F28335_GAS_M95M02.bin.sha256
Normal file
@@ -0,0 +1 @@
|
||||
a1c186e5f114ea2f77ac5f18a60424c79f53b1e3a49e0343ac9bd96979f0347e UKSSTMS320F28335_GAS_M95M02.bin
|
||||
16
Bin/GAS_M95M02/profile-comparison.json
Normal file
16
Bin/GAS_M95M02/profile-comparison.json
Normal file
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"after_bytes": 32472,
|
||||
"profile": 0,
|
||||
"gas_added_bytes": 0,
|
||||
"binary_identical": true,
|
||||
"before_bytes": 32472
|
||||
},
|
||||
{
|
||||
"after_bytes": 33174,
|
||||
"profile": 1,
|
||||
"gas_added_bytes": 410,
|
||||
"binary_identical": false,
|
||||
"before_bytes": 32764
|
||||
}
|
||||
]
|
||||
358
Bin/IndicatorTimingCompare/A_delay_before_clock_fall/kanal.c
Normal file
358
Bin/IndicatorTimingCompare/A_delay_before_clock_fall/kanal.c
Normal file
@@ -0,0 +1,358 @@
|
||||
/* Последовательный вывод данных канала индикации. Русские пояснения сохранены в UTF-8. */
|
||||
/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */
|
||||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||||
/* Подключает "DSP2833x_SWPrioritizedIsrLevels.h": поставляемое TI описание SWPrioritizedIsrLevels для семейства C2833x. */
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
/* Подключает "filter_bat2.h": накопительный фильтр измерительных каналов. */
|
||||
#include "filter_bat2.h"
|
||||
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
|
||||
#include "measure.h"
|
||||
|
||||
/* Подключает "RS485.h": приём и передача SCI-A/SCI-B, упаковка команд и FIFO первого порта. */
|
||||
#include "RS485.h"
|
||||
/* Подключает "message.h": обработка Modbus, заводские параметры и сохранение настроек. */
|
||||
#include "message.h"
|
||||
/* Подключает "kanal.h": последовательный вывод данных канала индикации. */
|
||||
#include "kanal.h"
|
||||
/* Подключает "pulto.h": обмен и индикация пульта. */
|
||||
#include "pulto.h"
|
||||
/* Подключает "package.h": адреса устройств, типы плат и псевдонимы технологических регистров. */
|
||||
#include "package.h"
|
||||
/* Подключает "tools.h": настройка внешней памяти и служебные задержки. */
|
||||
#include "tools.h"
|
||||
|
||||
/* Подключает "peripher.h": перемычки режима платы, дискретные входы и выходы. */
|
||||
#include "peripher.h"
|
||||
|
||||
/* Объявляет digits — данные digits. Начальное значение задаётся справа от знака равенства. */
|
||||
int digits[16] = {63,6,91,79,102,109,125,7,127,111,64,0,0,0,121,0};
|
||||
/* Объявляет readr — данные readr. Начальное значение задаётся справа от знака равенства. */
|
||||
int readr[5] = {0x08,0x0C,0x10,0x00,0x04};
|
||||
|
||||
/* Ограничивает настройки таймингов компилятором TI C2000; модель на ПК не использует эти директивы. */
|
||||
#if defined(__TI_COMPILER_VERSION__)
|
||||
/* Сохраняет отдельный вызов переключения CLOCK: встраивание при -O3 сокращало удержание DATA после фронта. */
|
||||
#pragma FUNC_CANNOT_INLINE(DCLK)
|
||||
/* Возвращает генерацию DCLK как в образе от 06.10.2026: уровень 1 и приоритет скорости 3 сохраняют прежнюю последовательность инструкций GPIO. */
|
||||
#pragma FUNCTION_OPTIONS(DCLK, "--opt_level=1 --opt_for_speed=3")
|
||||
/* Сохраняет отдельный вызов переключения DATA, чтобы длительность импульсов не зависела от встраивания в передатчик. */
|
||||
#pragma FUNC_CANNOT_INLINE(DOUT)
|
||||
/* Возвращает генерацию DOUT с прежними параметрами -O1 и --opt_for_speed=3; значения взяты из старой конфигурации CCS. */
|
||||
#pragma FUNCTION_OPTIONS(DOUT, "--opt_level=1 --opt_for_speed=3")
|
||||
/* Не позволяет встроить разделитель пакетов в цикл передачи и изменить интервалы между переключениями линий. */
|
||||
#pragma FUNC_CANNOT_INLINE(RESET)
|
||||
/* Сохраняет прежнюю последовательность вызовов GPIO и задержек разделителя, используя настройки старого образа. */
|
||||
#pragma FUNCTION_OPTIONS(RESET, "--opt_level=1 --opt_for_speed=3")
|
||||
/* Сохраняет отдельный вызов передачи бита; протокол использует порядок и интервалы фронтов CLOCK и DATA. */
|
||||
#pragma FUNC_CANNOT_INLINE(SENDBIT)
|
||||
/* Возвращает передаче бита настройки старого образа -O1 и --opt_for_speed=3, оставляя остальной проект на -O3. */
|
||||
#pragma FUNCTION_OPTIONS(SENDBIT, "--opt_level=1 --opt_for_speed=3")
|
||||
/* Завершает блок настроек TI, не изменяя формат пакетов и существующие счётчики задержек. */
|
||||
#endif
|
||||
|
||||
/* Начинает функцию DCLK; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void DCLK(int x)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if(x) GpioDataRegs.GPASET.bit.GPIO6=1; последующий оператор выполняется только при истинном условии. */
|
||||
if(x) GpioDataRegs.GPASET.bit.GPIO6=1;
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else GpioDataRegs.GPACLEAR.bit.GPIO6=1;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Начинает функцию DOUT; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void DOUT(int x)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if(x) GpioDataRegs.GPASET.bit.GPIO8=1; последующий оператор выполняется только при истинном условии. */
|
||||
if(x) GpioDataRegs.GPASET.bit.GPIO8=1;
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else GpioDataRegs.GPACLEAR.bit.GPIO8=1;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Условие компиляции CLKMULT==1: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==1
|
||||
/* Задаёт POWS0 = 0L; данные POWS0. */
|
||||
#define POWS0 0L
|
||||
/* Задаёт POWS1 = 10L; данные POWS1. */
|
||||
#define POWS1 10L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Условие компиляции CLKMULT==2: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==2
|
||||
/* Задаёт POWS0 = 0L; данные POWS0. */
|
||||
#define POWS0 0L
|
||||
/* Задаёт POWS1 = 30L; данные POWS1. */
|
||||
#define POWS1 30L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Условие компиляции CLKMULT==3: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==3
|
||||
/* Задаёт POWS0 = 1L; данные POWS0. */
|
||||
#define POWS0 1L
|
||||
/* Задаёт POWS1 = 50L; данные POWS1. */
|
||||
#define POWS1 50L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Условие компиляции CLKMULT==4: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==4
|
||||
/* Задаёт POWS0 = 2L; данные POWS0. */
|
||||
#define POWS0 2L
|
||||
/* Задаёт POWS1 = 60L; данные POWS1. */
|
||||
#define POWS1 60L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Условие компиляции CLKMULT==5: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==5
|
||||
/* Задаёт POWS0 = 4L; данные POWS0. */
|
||||
#define POWS0 4L
|
||||
/* Задаёт POWS1 = 80L; данные POWS1. */
|
||||
#define POWS1 80L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
|
||||
/* Начинает функцию RESET; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void RESET()
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Вызывает DCLK с аргументами (0) в текущей последовательности операций. */
|
||||
DCLK(0);
|
||||
/* Условие компиляции POWS1>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS1>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS1) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS1);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Вызывает DOUT с аргументами (1) в текущей последовательности операций. */
|
||||
DOUT(1);
|
||||
/* Условие компиляции POWS1>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS1>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS1) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS1);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Вызывает DOUT с аргументами (0) в текущей последовательности операций. */
|
||||
DOUT(0);
|
||||
/* Условие компиляции POWS1>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS1>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS1) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS1);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Начинает функцию SENDBIT; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void SENDBIT(int x)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Выставляет передаваемый бит DATA до подъёма CLOCK, сохраняя его на протяжении высокого уровня такта. */
|
||||
DOUT(x); DCLK(1);
|
||||
/* Условие компиляции POWS0>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS0>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS0) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS0);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Вариант A: задержка перед спадом CLOCK продлевает высокий уровень при действительном DATA; POWS0+1 — прежний счётчик циклов TI, не микросекунды. */
|
||||
DSP28x_usDelay(POWS0+1);
|
||||
/* Опускает CLOCK при ещё действительном DATA, чтобы сохранить передаваемый бит на отрицательном фронте такта. */
|
||||
DCLK(0);
|
||||
/* Сбрасывает DATA после спада CLOCK; в варианте A дополнительной задержки между спадом и сбросом нет. */
|
||||
DOUT(0);
|
||||
/* Условие компиляции POWS1>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS1>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS1) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS1);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Начинает функцию kanal_Send; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void kanal_Send(int adr, long dat, int dot)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Объявляет Word — слово; data — данные; aliq_part — данные aliq_part; dg — данные dg. */
|
||||
long Word,data,aliq_part,dg[4];
|
||||
/* Объявляет i — данные i; j — данные j; bit — представление регистра отдельными битовыми полями; byt — данные byt; addr — данные addr. Начальное значение задаётся справа от знака равенства. */
|
||||
int i,j,bit,byt,addr,sgn=0,punkt=0,aliq_len=0,full_len, isdot=0;
|
||||
|
||||
/* Проверяет if(adr>1); последующий оператор выполняется только при истинном условии. */
|
||||
if(adr>1) // Лампочки
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает Word значением dat; слово. */
|
||||
Word =dat;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else
|
||||
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if(dat<0) sgn=1; последующий оператор выполняется только при истинном условии. */
|
||||
if(dat<0) sgn=1;
|
||||
/* Записывает data значением labs(dat); данные. */
|
||||
data = labs(dat);
|
||||
|
||||
/* Проверяет if(dot>=0 и dot<4) isdot = 1; последующий оператор выполняется только при истинном условии. */
|
||||
if(dot>=0 && dot<4) isdot = 1;
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else dot=0;
|
||||
|
||||
/* Записывает aliq_part значением data; данные aliq_part. */
|
||||
aliq_part = data;
|
||||
/* Цикл for(i=0;i<dot;i++) aliq_part/=10;; задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=0;i<dot;i++) aliq_part/=10;
|
||||
|
||||
/* Записывает dat значением aliq_part; данные dat. */
|
||||
dat = aliq_part;
|
||||
/* Повторяет или ожидает, пока выполняется while(dat>0). */
|
||||
while(dat>0)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Делит dat значением 10; данные dat. */
|
||||
aliq_len++; dat/=10;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Записывает dat значением data; данные dat. */
|
||||
dat = data;
|
||||
|
||||
/* Записывает full_len значением aliq_len+sgn; данные full_len. */
|
||||
full_len = aliq_len+sgn;
|
||||
/* Проверяет if(full_len==0) full_len=1; последующий оператор выполняется только при истинном условии. */
|
||||
if(full_len==0) full_len=1;
|
||||
/* Увеличивает full_len значением dot; данные full_len. */
|
||||
full_len += dot;
|
||||
|
||||
/* Цикл for(i=0; i<(full_len-4);i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=0; i<(full_len-4);i++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Начинает цикл с проверкой условия после тела: первый проход выполняется всегда. */
|
||||
dot--; dat/=10;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
/* Проверяет if(dot<0) dot=0; последующий оператор выполняется только при истинном условии. */
|
||||
if(dot<0) dot=0;
|
||||
/* Записывает punkt значением 1<<dot; данные punkt. */
|
||||
punkt = 1<<dot;
|
||||
/* Проверяет if(punkt==1) punkt=0; последующий оператор выполняется только при истинном условии. */
|
||||
if(punkt==1) punkt=0;
|
||||
|
||||
/* Записывает dg[3] значением (dat)/1000; данные dg. */
|
||||
dg[3] = (dat)/1000;
|
||||
/* Записывает dg[2] значением (dat%1000)/100; данные dg. */
|
||||
dg[2] = (dat%1000)/100;
|
||||
/* Записывает dg[1] значением (dat%100)/10; данные dg. */
|
||||
dg[1] = (dat%100)/10;
|
||||
/* Записывает dg[0] значением (dat%10); данные dg. */
|
||||
dg[0] = (dat%10);
|
||||
|
||||
/* Проверяет if(dg[0]+dg[1]+dg[2]+dg[3]==0); последующий оператор выполняется только при истинном условии. */
|
||||
if(dg[0]+dg[1]+dg[2]+dg[3]==0)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает punkt значением 0; dot=0; sgn=0; данные punkt. */
|
||||
punkt=0; dot=0; sgn=0;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Проверяет if(isdot); последующий оператор выполняется только при истинном условии. */
|
||||
if(isdot)
|
||||
/* Цикл for(i=3;i>0;i--); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=3;i>0;i--)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if((dg[i]==0) и (i!=dot)); последующий оператор выполняется только при истинном условии. */
|
||||
if((dg[i]==0)&&(i!=dot))
|
||||
/* Записывает dg[i] значением 0xF; данные dg. */
|
||||
dg[i]=0xF; // Это значит пусто
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else break;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Проверяет if(sgn); последующий оператор выполняется только при истинном условии. */
|
||||
if(sgn)
|
||||
/* Цикл for(i=1;i<4;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=1;i<4;i++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if( (dg[i]==0xF) или (i==3)); последующий оператор выполняется только при истинном условии. */
|
||||
if( (dg[i]==0xF)||(i==3))
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает dg[i] значением 0xA; данные dg. */
|
||||
dg[i]=0xA; // Это значит минус
|
||||
/* Прерывает ближайший цикл или ветвь switch и продолжает после него. */
|
||||
break;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
} }
|
||||
|
||||
/* Цикл for(i=0;i<4;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=0;i<4;i++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает dg[i] значением digits[dg[i]]; данные dg. */
|
||||
dg[i] = digits[dg[i]];
|
||||
/* Проверяет if((punkt>>i)&1) dg[i]+= 128; последующий оператор выполняется только при истинном условии. */
|
||||
if((punkt>>i)&1) dg[i]+= 128;
|
||||
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Записывает Word значением ((dg[0] ) & 0x000000FF) | ((dg[1]<<8 ) & 0x0000FF00) |; слово. */
|
||||
Word = ((dg[0] ) & 0x000000FF) | ((dg[1]<<8 ) & 0x0000FF00) |
|
||||
/* Продолжает список аргументов, полей или выражение ((dg[2]<<16) & 0x00FF0000) | ((dg[3]<<24) & 0xFF000000);; порядок элементов сохраняется. */
|
||||
((dg[2]<<16) & 0x00FF0000) | ((dg[3]<<24) & 0xFF000000);
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Записывает addr значением readr[adr]; данные addr. */
|
||||
addr = readr[adr];
|
||||
|
||||
/* Цикл for (i=0;i<4;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for (i=0;i<4;i++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if(addr>0x10) break; последующий оператор выполняется только при истинном условии. */
|
||||
if(addr>0x10) break;
|
||||
|
||||
/* Цикл for (j=0;j<8;j++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for (j=0;j<8;j++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает bit значением Word & 1; Word >>= 1; представление регистра отдельными битовыми полями. */
|
||||
bit = Word & 1; Word >>= 1;
|
||||
/* Вызывает SENDBIT с аргументами (bit) в текущей последовательности операций. */
|
||||
SENDBIT(bit);
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Записывает byt значением addr; данные byt. */
|
||||
byt = addr;
|
||||
/* Цикл for (j=0;j<6;j++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for (j=0;j<6;j++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает bit значением byt & 1; byt >>= 1; представление регистра отдельными битовыми полями. */
|
||||
bit = byt & 1; byt >>= 1;
|
||||
/* Вызывает SENDBIT с аргументами (bit) в текущей последовательности операций. */
|
||||
SENDBIT(bit);
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
/* Изменяет счётчик в выражении addr++; на один для следующего шага. */
|
||||
addr++;
|
||||
|
||||
/* Вызывает RESET с аргументами () в текущей последовательности операций. */
|
||||
RESET();
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
358
Bin/IndicatorTimingCompare/B_delay_after_clock_fall/kanal.c
Normal file
358
Bin/IndicatorTimingCompare/B_delay_after_clock_fall/kanal.c
Normal file
@@ -0,0 +1,358 @@
|
||||
/* Последовательный вывод данных канала индикации. Русские пояснения сохранены в UTF-8. */
|
||||
/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */
|
||||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||||
/* Подключает "DSP2833x_SWPrioritizedIsrLevels.h": поставляемое TI описание SWPrioritizedIsrLevels для семейства C2833x. */
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
/* Подключает "filter_bat2.h": накопительный фильтр измерительных каналов. */
|
||||
#include "filter_bat2.h"
|
||||
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
|
||||
#include "measure.h"
|
||||
|
||||
/* Подключает "RS485.h": приём и передача SCI-A/SCI-B, упаковка команд и FIFO первого порта. */
|
||||
#include "RS485.h"
|
||||
/* Подключает "message.h": обработка Modbus, заводские параметры и сохранение настроек. */
|
||||
#include "message.h"
|
||||
/* Подключает "kanal.h": последовательный вывод данных канала индикации. */
|
||||
#include "kanal.h"
|
||||
/* Подключает "pulto.h": обмен и индикация пульта. */
|
||||
#include "pulto.h"
|
||||
/* Подключает "package.h": адреса устройств, типы плат и псевдонимы технологических регистров. */
|
||||
#include "package.h"
|
||||
/* Подключает "tools.h": настройка внешней памяти и служебные задержки. */
|
||||
#include "tools.h"
|
||||
|
||||
/* Подключает "peripher.h": перемычки режима платы, дискретные входы и выходы. */
|
||||
#include "peripher.h"
|
||||
|
||||
/* Объявляет digits — данные digits. Начальное значение задаётся справа от знака равенства. */
|
||||
int digits[16] = {63,6,91,79,102,109,125,7,127,111,64,0,0,0,121,0};
|
||||
/* Объявляет readr — данные readr. Начальное значение задаётся справа от знака равенства. */
|
||||
int readr[5] = {0x08,0x0C,0x10,0x00,0x04};
|
||||
|
||||
/* Ограничивает настройки таймингов компилятором TI C2000; модель на ПК не использует эти директивы. */
|
||||
#if defined(__TI_COMPILER_VERSION__)
|
||||
/* Сохраняет отдельный вызов переключения CLOCK: встраивание при -O3 сокращало удержание DATA после фронта. */
|
||||
#pragma FUNC_CANNOT_INLINE(DCLK)
|
||||
/* Возвращает генерацию DCLK как в образе от 06.10.2026: уровень 1 и приоритет скорости 3 сохраняют прежнюю последовательность инструкций GPIO. */
|
||||
#pragma FUNCTION_OPTIONS(DCLK, "--opt_level=1 --opt_for_speed=3")
|
||||
/* Сохраняет отдельный вызов переключения DATA, чтобы длительность импульсов не зависела от встраивания в передатчик. */
|
||||
#pragma FUNC_CANNOT_INLINE(DOUT)
|
||||
/* Возвращает генерацию DOUT с прежними параметрами -O1 и --opt_for_speed=3; значения взяты из старой конфигурации CCS. */
|
||||
#pragma FUNCTION_OPTIONS(DOUT, "--opt_level=1 --opt_for_speed=3")
|
||||
/* Не позволяет встроить разделитель пакетов в цикл передачи и изменить интервалы между переключениями линий. */
|
||||
#pragma FUNC_CANNOT_INLINE(RESET)
|
||||
/* Сохраняет прежнюю последовательность вызовов GPIO и задержек разделителя, используя настройки старого образа. */
|
||||
#pragma FUNCTION_OPTIONS(RESET, "--opt_level=1 --opt_for_speed=3")
|
||||
/* Сохраняет отдельный вызов передачи бита; протокол использует порядок и интервалы фронтов CLOCK и DATA. */
|
||||
#pragma FUNC_CANNOT_INLINE(SENDBIT)
|
||||
/* Возвращает передаче бита настройки старого образа -O1 и --opt_for_speed=3, оставляя остальной проект на -O3. */
|
||||
#pragma FUNCTION_OPTIONS(SENDBIT, "--opt_level=1 --opt_for_speed=3")
|
||||
/* Завершает блок настроек TI, не изменяя формат пакетов и существующие счётчики задержек. */
|
||||
#endif
|
||||
|
||||
/* Начинает функцию DCLK; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void DCLK(int x)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if(x) GpioDataRegs.GPASET.bit.GPIO6=1; последующий оператор выполняется только при истинном условии. */
|
||||
if(x) GpioDataRegs.GPASET.bit.GPIO6=1;
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else GpioDataRegs.GPACLEAR.bit.GPIO6=1;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Начинает функцию DOUT; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void DOUT(int x)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if(x) GpioDataRegs.GPASET.bit.GPIO8=1; последующий оператор выполняется только при истинном условии. */
|
||||
if(x) GpioDataRegs.GPASET.bit.GPIO8=1;
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else GpioDataRegs.GPACLEAR.bit.GPIO8=1;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Условие компиляции CLKMULT==1: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==1
|
||||
/* Задаёт POWS0 = 0L; данные POWS0. */
|
||||
#define POWS0 0L
|
||||
/* Задаёт POWS1 = 10L; данные POWS1. */
|
||||
#define POWS1 10L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Условие компиляции CLKMULT==2: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==2
|
||||
/* Задаёт POWS0 = 0L; данные POWS0. */
|
||||
#define POWS0 0L
|
||||
/* Задаёт POWS1 = 30L; данные POWS1. */
|
||||
#define POWS1 30L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Условие компиляции CLKMULT==3: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==3
|
||||
/* Задаёт POWS0 = 1L; данные POWS0. */
|
||||
#define POWS0 1L
|
||||
/* Задаёт POWS1 = 50L; данные POWS1. */
|
||||
#define POWS1 50L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Условие компиляции CLKMULT==4: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==4
|
||||
/* Задаёт POWS0 = 2L; данные POWS0. */
|
||||
#define POWS0 2L
|
||||
/* Задаёт POWS1 = 60L; данные POWS1. */
|
||||
#define POWS1 60L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Условие компиляции CLKMULT==5: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if CLKMULT==5
|
||||
/* Задаёт POWS0 = 4L; данные POWS0. */
|
||||
#define POWS0 4L
|
||||
/* Задаёт POWS1 = 80L; данные POWS1. */
|
||||
#define POWS1 80L
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
|
||||
/* Начинает функцию RESET; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void RESET()
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Вызывает DCLK с аргументами (0) в текущей последовательности операций. */
|
||||
DCLK(0);
|
||||
/* Условие компиляции POWS1>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS1>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS1) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS1);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Вызывает DOUT с аргументами (1) в текущей последовательности операций. */
|
||||
DOUT(1);
|
||||
/* Условие компиляции POWS1>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS1>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS1) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS1);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Вызывает DOUT с аргументами (0) в текущей последовательности операций. */
|
||||
DOUT(0);
|
||||
/* Условие компиляции POWS1>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS1>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS1) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS1);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Начинает функцию SENDBIT; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void SENDBIT(int x)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Выставляет передаваемый бит DATA до подъёма CLOCK, сохраняя его на протяжении высокого уровня такта. */
|
||||
DOUT(x); DCLK(1);
|
||||
/* Условие компиляции POWS0>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS0>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS0) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS0);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Опускает CLOCK при ещё действительном DATA, чтобы сохранить передаваемый бит на отрицательном фронте такта. */
|
||||
DCLK(0);
|
||||
/* Вариант B: задержка между DCLK(0) и DOUT(0) удерживает DATA после спада CLOCK; POWS0+1 — прежний счётчик циклов TI, не микросекунды. */
|
||||
DSP28x_usDelay(POWS0+1);
|
||||
/* Сбрасывает DATA после завершения паузы удержания, возвращая линию к нулю перед следующим битом. */
|
||||
DOUT(0);
|
||||
/* Условие компиляции POWS1>0: выбранный блок включается в текущий вариант прошивки. */
|
||||
#if POWS1>0
|
||||
/* Вызывает DSP28x_usDelay с аргументами (POWS1) в текущей последовательности операций. */
|
||||
DSP28x_usDelay(POWS1);
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Начинает функцию kanal_Send; назначение модуля — последовательный вывод данных канала индикации. */
|
||||
void kanal_Send(int adr, long dat, int dot)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Объявляет Word — слово; data — данные; aliq_part — данные aliq_part; dg — данные dg. */
|
||||
long Word,data,aliq_part,dg[4];
|
||||
/* Объявляет i — данные i; j — данные j; bit — представление регистра отдельными битовыми полями; byt — данные byt; addr — данные addr. Начальное значение задаётся справа от знака равенства. */
|
||||
int i,j,bit,byt,addr,sgn=0,punkt=0,aliq_len=0,full_len, isdot=0;
|
||||
|
||||
/* Проверяет if(adr>1); последующий оператор выполняется только при истинном условии. */
|
||||
if(adr>1) // Лампочки
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает Word значением dat; слово. */
|
||||
Word =dat;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else
|
||||
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if(dat<0) sgn=1; последующий оператор выполняется только при истинном условии. */
|
||||
if(dat<0) sgn=1;
|
||||
/* Записывает data значением labs(dat); данные. */
|
||||
data = labs(dat);
|
||||
|
||||
/* Проверяет if(dot>=0 и dot<4) isdot = 1; последующий оператор выполняется только при истинном условии. */
|
||||
if(dot>=0 && dot<4) isdot = 1;
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else dot=0;
|
||||
|
||||
/* Записывает aliq_part значением data; данные aliq_part. */
|
||||
aliq_part = data;
|
||||
/* Цикл for(i=0;i<dot;i++) aliq_part/=10;; задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=0;i<dot;i++) aliq_part/=10;
|
||||
|
||||
/* Записывает dat значением aliq_part; данные dat. */
|
||||
dat = aliq_part;
|
||||
/* Повторяет или ожидает, пока выполняется while(dat>0). */
|
||||
while(dat>0)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Делит dat значением 10; данные dat. */
|
||||
aliq_len++; dat/=10;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Записывает dat значением data; данные dat. */
|
||||
dat = data;
|
||||
|
||||
/* Записывает full_len значением aliq_len+sgn; данные full_len. */
|
||||
full_len = aliq_len+sgn;
|
||||
/* Проверяет if(full_len==0) full_len=1; последующий оператор выполняется только при истинном условии. */
|
||||
if(full_len==0) full_len=1;
|
||||
/* Увеличивает full_len значением dot; данные full_len. */
|
||||
full_len += dot;
|
||||
|
||||
/* Цикл for(i=0; i<(full_len-4);i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=0; i<(full_len-4);i++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Начинает цикл с проверкой условия после тела: первый проход выполняется всегда. */
|
||||
dot--; dat/=10;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
/* Проверяет if(dot<0) dot=0; последующий оператор выполняется только при истинном условии. */
|
||||
if(dot<0) dot=0;
|
||||
/* Записывает punkt значением 1<<dot; данные punkt. */
|
||||
punkt = 1<<dot;
|
||||
/* Проверяет if(punkt==1) punkt=0; последующий оператор выполняется только при истинном условии. */
|
||||
if(punkt==1) punkt=0;
|
||||
|
||||
/* Записывает dg[3] значением (dat)/1000; данные dg. */
|
||||
dg[3] = (dat)/1000;
|
||||
/* Записывает dg[2] значением (dat%1000)/100; данные dg. */
|
||||
dg[2] = (dat%1000)/100;
|
||||
/* Записывает dg[1] значением (dat%100)/10; данные dg. */
|
||||
dg[1] = (dat%100)/10;
|
||||
/* Записывает dg[0] значением (dat%10); данные dg. */
|
||||
dg[0] = (dat%10);
|
||||
|
||||
/* Проверяет if(dg[0]+dg[1]+dg[2]+dg[3]==0); последующий оператор выполняется только при истинном условии. */
|
||||
if(dg[0]+dg[1]+dg[2]+dg[3]==0)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает punkt значением 0; dot=0; sgn=0; данные punkt. */
|
||||
punkt=0; dot=0; sgn=0;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Проверяет if(isdot); последующий оператор выполняется только при истинном условии. */
|
||||
if(isdot)
|
||||
/* Цикл for(i=3;i>0;i--); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=3;i>0;i--)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if((dg[i]==0) и (i!=dot)); последующий оператор выполняется только при истинном условии. */
|
||||
if((dg[i]==0)&&(i!=dot))
|
||||
/* Записывает dg[i] значением 0xF; данные dg. */
|
||||
dg[i]=0xF; // Это значит пусто
|
||||
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
||||
else break;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Проверяет if(sgn); последующий оператор выполняется только при истинном условии. */
|
||||
if(sgn)
|
||||
/* Цикл for(i=1;i<4;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=1;i<4;i++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if( (dg[i]==0xF) или (i==3)); последующий оператор выполняется только при истинном условии. */
|
||||
if( (dg[i]==0xF)||(i==3))
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает dg[i] значением 0xA; данные dg. */
|
||||
dg[i]=0xA; // Это значит минус
|
||||
/* Прерывает ближайший цикл или ветвь switch и продолжает после него. */
|
||||
break;
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
} }
|
||||
|
||||
/* Цикл for(i=0;i<4;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for(i=0;i<4;i++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает dg[i] значением digits[dg[i]]; данные dg. */
|
||||
dg[i] = digits[dg[i]];
|
||||
/* Проверяет if((punkt>>i)&1) dg[i]+= 128; последующий оператор выполняется только при истинном условии. */
|
||||
if((punkt>>i)&1) dg[i]+= 128;
|
||||
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Записывает Word значением ((dg[0] ) & 0x000000FF) | ((dg[1]<<8 ) & 0x0000FF00) |; слово. */
|
||||
Word = ((dg[0] ) & 0x000000FF) | ((dg[1]<<8 ) & 0x0000FF00) |
|
||||
/* Продолжает список аргументов, полей или выражение ((dg[2]<<16) & 0x00FF0000) | ((dg[3]<<24) & 0xFF000000);; порядок элементов сохраняется. */
|
||||
((dg[2]<<16) & 0x00FF0000) | ((dg[3]<<24) & 0xFF000000);
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Записывает addr значением readr[adr]; данные addr. */
|
||||
addr = readr[adr];
|
||||
|
||||
/* Цикл for (i=0;i<4;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for (i=0;i<4;i++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Проверяет if(addr>0x10) break; последующий оператор выполняется только при истинном условии. */
|
||||
if(addr>0x10) break;
|
||||
|
||||
/* Цикл for (j=0;j<8;j++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for (j=0;j<8;j++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает bit значением Word & 1; Word >>= 1; представление регистра отдельными битовыми полями. */
|
||||
bit = Word & 1; Word >>= 1;
|
||||
/* Вызывает SENDBIT с аргументами (bit) в текущей последовательности операций. */
|
||||
SENDBIT(bit);
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Записывает byt значением addr; данные byt. */
|
||||
byt = addr;
|
||||
/* Цикл for (j=0;j<6;j++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
||||
for (j=0;j<6;j++)
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
/* Записывает bit значением byt & 1; byt >>= 1; представление регистра отдельными битовыми полями. */
|
||||
bit = byt & 1; byt >>= 1;
|
||||
/* Вызывает SENDBIT с аргументами (bit) в текущей последовательности операций. */
|
||||
SENDBIT(bit);
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
/* Изменяет счётчик в выражении addr++; на один для следующего шага. */
|
||||
addr++;
|
||||
|
||||
/* Вызывает RESET с аргументами () в текущей последовательности операций. */
|
||||
RESET();
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
37
Bin/IndicatorTimingCompare/README.txt
Normal file
37
Bin/IndicatorTimingCompare/README.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
Бальзам-167: два проверочных варианта задержки индикации
|
||||
Дата сборки: 12.10.2026.
|
||||
|
||||
A_delay_before_clock_fall
|
||||
BIN: UKSSTMS320F28335_A_delay_before_clock_fall_fa20ed0+.bin
|
||||
Дополнительная задержка стоит ПЕРЕД спадом CLOCK.
|
||||
Последовательность: DSP28x_usDelay(POWS0+1); DCLK(0); DOUT(0).
|
||||
Назначение: продлить высокий уровень CLOCK при действительном DATA.
|
||||
Размер: 32246 байт. Запас до области параметров AT25256B: 262 байта.
|
||||
SHA-256: C28337E35996AED330E22BC014EF9D15D06C9A1F5CFCCCE27EAD75FB1AC565F9
|
||||
|
||||
B_delay_after_clock_fall
|
||||
BIN: UKSSTMS320F28335_B_delay_after_clock_fall_fa20ed0+.bin
|
||||
Дополнительная задержка стоит ПОСЛЕ спада CLOCK, МЕЖДУ DCLK(0) и DOUT(0).
|
||||
Последовательность: DCLK(0); DSP28x_usDelay(POWS0+1); DOUT(0).
|
||||
Назначение: удержать DATA после спада CLOCK перед сбросом линии данных.
|
||||
Размер: 32248 байт. Запас до области параметров AT25256B: 260 байт.
|
||||
SHA-256: 1ABA3835FFA39649E9922E107B6DBAAA2605F7C4ED80631D583973EFC2DEC215
|
||||
|
||||
В каждом варианте только одна дополнительная задержка POWS0+1.
|
||||
В обоих вариантах DATA сохраняется до спада CLOCK и сбрасывается после него.
|
||||
Общие условные задержки POWS0 и POWS1 и разделитель RESET сохранены.
|
||||
При CLKMULT=2 значения POWS0+1=1 и POWS1=30 являются аргументами
|
||||
цикловой функции TI DSP28x_usDelay, а не длительностями в микросекундах.
|
||||
|
||||
Оба варианта полностью собраны TI C2000 22.6.0.LTS из текущего проекта.
|
||||
Базовый коммит: fa20ed085bdca15fec47c79b72f50525653e103d; сборки помечены dirty.
|
||||
Для каждого варианта при компиляции подставлен отдельный kanal.c,
|
||||
сохранённый рядом с его BIN. Основной Source/Internal/kanal.c при подготовке
|
||||
этой пары не изменялся. Общие параметры компиляции и прочие модули одинаковы;
|
||||
паспорта также содержат собственное время сборки каждого варианта.
|
||||
|
||||
Проверено: полный цикл компиляции и линковки, структура SCI8 и предел EEPROM,
|
||||
соответствие итогового BIN кандидату hex2000, расположение задержек в машинном
|
||||
коде SENDBIT, передача 0 и 1 на обоих фронтах в модели логических уровней,
|
||||
одинаковый код DCLK/DOUT между вариантами и прежний код разделителя RESET.
|
||||
Физические длительности сигналов и отсутствие строба требуют проверки на плате.
|
||||
41
Bin/StartupWait3s/rebuild.py
Normal file
41
Bin/StartupWait3s/rebuild.py
Normal file
File diff suppressed because one or more lines are too long
48
Bin/TestLampFix/README.txt
Normal file
48
Bin/TestLampFix/README.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
Бальзам-167: проверочная прошивка с исправлением TESTLAMP
|
||||
Сборка: 13.10.2026, 11:00:35 (Москва, UTC+3).
|
||||
|
||||
Готовый образ:
|
||||
UKSSTMS320F28335_testlamp_fix_fa20ed0+.bin
|
||||
Размер: 32272 байта. Запас до параметров AT25256B: 236 байт.
|
||||
SHA-256: bfe4c3c9b55bb5022f38f254929f893e5eaab57ef3d3fa31771a6b6f97f877a4
|
||||
Паспорт: UKSSTMS320F28335_testlamp_fix_fa20ed0+.bin.manifest.json
|
||||
Архив этой сборки: fa20ed08+_2026-10-13_11-00-35_UTC+3.
|
||||
|
||||
Исправления:
|
||||
1. В get_Buttons для dsk_EPLT накопительный фильтр получает предыдущее
|
||||
значение bTestLamp вместо постоянного нуля. Раньше даже один низкий
|
||||
отсчёт GPIO26 при удержании кнопки сразу отключал тест, а следующий
|
||||
высокий отсчёт мог снова его включить. Это переключало пакеты ламп
|
||||
и семисегментных индикаторов между рабочим и тестовым режимами.
|
||||
Порог 1000 по-прежнему измеряется опросами главного цикла.
|
||||
2. cpu_timer1_isr_PULT ограничивает IER маской MINT13 и исключает собственный
|
||||
Timer1 (INT13). Прежнее IER |= MINT13 включало дополнительные источники
|
||||
вместо ограничения приоритетов и могло разрешить повторный вход Timer1.
|
||||
Вложенная передача больше не может перемешать DATA/CLK, счётчик каналов
|
||||
и фазу яркости. В машинном коде перед EINT проверено AND IER, #0x0139.
|
||||
|
||||
Штатная тестовая последовательность what_is сохранена: цифры меняются
|
||||
и тестовая маска ламп переключается каждые 500 тактов Timer1 (0,5 секунды).
|
||||
Это исправление относится к частому нерегулярному мерцанию поверх теста.
|
||||
Порядок уровней и задержек SENDBIT/RESET взят из текущего kanal.c проекта;
|
||||
для этой сборки он не изменялся. В образ вошли уже имевшиеся правки
|
||||
ecan.c, measure.c и kanal.c.
|
||||
|
||||
Проверено:
|
||||
- настоящие get_Buttons, er_anal, what_is и обработчик пульта в хостовой
|
||||
модели при O3; короткие провалы входа при удержании TESTLAMP;
|
||||
- тестовые пакеты ламп и цифр при уже включённой рабочей лампе;
|
||||
- отсутствие повторного входа ISR, отпускание и удалённая команда теста;
|
||||
- сохранение обычного PWM: шесть включённых тактов из десяти;
|
||||
- возвращение каждой старой ошибки отдельно вызывает провал теста;
|
||||
- полная компиляция и линковка TI C2000 22.6.0.LTS, O3, COFF, FPU32;
|
||||
- SCI8, четыре RAM-блока, границы AT25256B и совпадение BIN с кандидатом;
|
||||
- UTF-8 и русские пояснения к изменённому и добавленному коду.
|
||||
|
||||
Повторная проверка: python tests/testlamp/run_test.py
|
||||
Повторная сборка: python Bin/TestLampFix/rebuild.py
|
||||
|
||||
На физической плате эта прошивка пока не проверена. Для проверки повторить
|
||||
сценарий пользователя: включённые рабочие лампы, нажатие и удержание TESTLAMP,
|
||||
затем отпускание. Штатные изменения теста раз в 0,5 секунды сохраняются;
|
||||
быстрых переключений между тестовыми и рабочими показаниями быть не должно.
|
||||
54
Bin/TestLampFix/rebuild.py
Normal file
54
Bin/TestLampFix/rebuild.py
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
TMS320C2000 Hex Converter v5.2.7
|
||||
********************************************************************************
|
||||
|
||||
INPUT FILE NAME: <D:\project12\Balsam_167\bin\UKSSTMS320F28335.out>
|
||||
INPUT FILE NAME: <UKSSTMS320F28335.out>
|
||||
OUTPUT FORMAT: Binary
|
||||
|
||||
PHYSICAL MEMORY PARAMETERS
|
||||
@@ -12,21 +12,20 @@ PHYSICAL MEMORY PARAMETERS
|
||||
|
||||
BOOT LOADER PARAMETERS
|
||||
Table Type: SERIAL PORT (SCI 8 bit Mode)
|
||||
Entry Point: 0x0000b8fa
|
||||
Entry Point: 0x0000a8d1
|
||||
|
||||
|
||||
OUTPUT TRANSLATION MAP
|
||||
--------------------------------------------------------------------------------
|
||||
00000000..003fffff Page=0 Memory Width=8 ROM Width=8
|
||||
--------------------------------------------------------------------------------
|
||||
OUTPUT FILES: D:\project12\Balsam_167\bin\UKSSTMS320F28335.bin [b0..b7]
|
||||
OUTPUT FILES: UKSSTMS320F28335_c6c91282.bin.pending [b0..b7]
|
||||
|
||||
CONTENTS: 00000000..00007d15 BOOT TABLE
|
||||
.cinit : dest=0000ba94 size=0000027f width=00000002
|
||||
.text : dest=00008000 size=00003a94 width=00000002
|
||||
ramfuncs : dest=0000c15d size=00000023 width=00000002
|
||||
.econst : dest=0000c000 size=00000112 width=00000002
|
||||
.switch : dest=0000c112 size=00000028 width=00000002
|
||||
CONTENTS: 00000000..00007ffb BOOT TABLE
|
||||
.cinit : dest=0000c000 size=00000273 width=00000002
|
||||
.text : dest=00008000 size=00003bfc width=00000002
|
||||
.econst : dest=0000c274 size=0000012b width=00000002
|
||||
.switch : dest=0000c3a0 size=0000004c width=00000002
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
00000000..003fffff Page=1 Memory Width=8 ROM Width=8 "*DEFAULT PAGE 1*"
|
||||
|
||||
41
Bin/UartBaudFix/rebuild.py
Normal file
41
Bin/UartBaudFix/rebuild.py
Normal file
File diff suppressed because one or more lines are too long
41
Bin/UartColdStart/rebuild.py
Normal file
41
Bin/UartColdStart/rebuild.py
Normal file
File diff suppressed because one or more lines are too long
@@ -1,167 +0,0 @@
|
||||
# Карта CAN-адресов `Balsam_167_periph` и `BALZAM_167`
|
||||
|
||||
## Формирование адреса peripheral
|
||||
|
||||
В `Source/Internal/main.c` выполняется:
|
||||
|
||||
```c
|
||||
get_Mode();
|
||||
InitCan(0, Mode);
|
||||
```
|
||||
|
||||
В `Source/Internal/ecan.c` настроены два extended CAN ID:
|
||||
|
||||
```c
|
||||
long id = 0x80BA0000;
|
||||
|
||||
MBOX0.MSGID.all = id + 0x10 + DevNum; /* передача */
|
||||
MBOX1.MSGID.all = id + DevNum; /* приём */
|
||||
```
|
||||
|
||||
`0x80000000` задаёт extended-формат и не является частью отображаемого
|
||||
29-битного идентификатора. Фактические адреса на шине:
|
||||
|
||||
```text
|
||||
TX peripheral = 0x00BA0010 + Mode
|
||||
RX peripheral = 0x00BA0000 + Mode
|
||||
```
|
||||
|
||||
## Адреса всех режимов peripheral
|
||||
|
||||
| `Mode` | Назначение | TX peripheral -> BALZAM | RX BALZAM -> peripheral |
|
||||
|---:|---|---:|---:|
|
||||
| 1 | `adr_TRN1` | `0x00BA0011` | `0x00BA0001` |
|
||||
| 2 | `adr_TRN2` | `0x00BA0012` | `0x00BA0002` |
|
||||
| 3 | `adr_POW1` | `0x00BA0013` | `0x00BA0003` |
|
||||
| 4 | `adr_POW2` | `0x00BA0014` | `0x00BA0004` |
|
||||
| 5 | `adr_LOA1`, УМП1 | `0x00BA0015` | `0x00BA0005` |
|
||||
| 6 | `adr_LOA2`, УМП2 | `0x00BA0016` | `0x00BA0006` |
|
||||
| 7 | `adr_ENG1` | `0x00BA0017` | `0x00BA0007` |
|
||||
| 8 | `adr_PULT` | `0x00BA0018` | `0x00BA0008` |
|
||||
| 9 | `adr_SHKF` | `0x00BA0019` | `0x00BA0009` |
|
||||
|
||||
## Приёмные адреса основного контроллера
|
||||
|
||||
В `BALZAM_167/Src/balzam_7/CanSetupBalzam7.c` настроено:
|
||||
|
||||
| RX mailbox | CAN ID | Запись обработчиком |
|
||||
|---:|---:|---|
|
||||
| 0 | `0x00BA0010` | `Unites[1]` |
|
||||
| 1 | `0x00BA0011` | `Unites[2]` |
|
||||
| 2 | `0x00BA0012` | `Unites[3]` |
|
||||
| 3 | `0x00BA0013` | `Unites[4]` |
|
||||
| 4 | `0x00BA0014` | `Unites[5]` |
|
||||
| 5 | `0x00BA0015` | `Unites[6]` |
|
||||
| 6 | `0x00BA0016` | `Unites[7]` |
|
||||
| 7 | `0x00BA0017` | `Unites[8]` |
|
||||
| 8 | `0x00BA0018` | `Unites[9]` |
|
||||
| 9 | `0x00745019` | специальная обработка MPU |
|
||||
| 10 | `0x00BA001A` | `Unites[11]` |
|
||||
| 11 | `0x00BA001B` | `Unites[12]` |
|
||||
|
||||
Причина такого соответствия — запись в обработчике:
|
||||
|
||||
```c
|
||||
Unites[box + 1][register_address] = received_data;
|
||||
```
|
||||
|
||||
## Имена индексов `Unites`
|
||||
|
||||
Текущие определения в `CanSetupBalzam7.h`:
|
||||
|
||||
| Индекс | Имя устройства |
|
||||
|---:|---|
|
||||
| 1 | `UKSS1_CAN_DEVICE` |
|
||||
| 2 | `UKSS4_CAN_DEVICE` |
|
||||
| 3 | `UKSS2_CAN_DEVICE` |
|
||||
| 4 | `UKSS3_CAN_DEVICE` |
|
||||
| 5 | `UMP1_CAN_DEVICE` |
|
||||
| 6 | `UMP2_CAN_DEVICE` |
|
||||
| 7 | `UKSS8_CAN_DEVICE` |
|
||||
| 8 | `VPU1_CAN_DEVICE` |
|
||||
| 9 | `UKSS5_CAN_DEVICE` |
|
||||
| 10 | `MPU_CAN_DEVICE` |
|
||||
| 11 | `UKSS6_CAN_DEVICE` |
|
||||
| 12 | `UKSS7_CAN_DEVICE` |
|
||||
|
||||
## Фактическое попадание пакетов
|
||||
|
||||
При текущем коде пакет peripheral с `Mode=N` принимается mailbox `N`, после
|
||||
чего записывается в `Unites[N+1]`.
|
||||
|
||||
| Peripheral | TX CAN ID | Фактический `Unites` | Имя по текущим константам |
|
||||
|---|---:|---:|---|
|
||||
| `adr_TRN1`, Mode 1 | `0x00BA0011` | `Unites[2]` | `UKSS4_CAN_DEVICE` |
|
||||
| `adr_TRN2`, Mode 2 | `0x00BA0012` | `Unites[3]` | `UKSS2_CAN_DEVICE` |
|
||||
| `adr_POW1`, Mode 3 | `0x00BA0013` | `Unites[4]` | `UKSS3_CAN_DEVICE` |
|
||||
| `adr_POW2`, Mode 4 | `0x00BA0014` | `Unites[5]` | `UMP1_CAN_DEVICE` |
|
||||
| `adr_LOA1`, Mode 5 | `0x00BA0015` | `Unites[6]` | `UMP2_CAN_DEVICE` |
|
||||
| `adr_LOA2`, Mode 6 | `0x00BA0016` | `Unites[7]` | `UKSS8_CAN_DEVICE` |
|
||||
| `adr_ENG1`, Mode 7 | `0x00BA0017` | `Unites[8]` | `VPU1_CAN_DEVICE` |
|
||||
| `adr_PULT`, Mode 8 | `0x00BA0018` | `Unites[9]` | `UKSS5_CAN_DEVICE` |
|
||||
| `adr_SHKF`, Mode 9 | `0x00BA0019` | нет приёма | — |
|
||||
|
||||
## Связь с ошибкой обрыва фаз
|
||||
|
||||
Peripheral передаёт регистры ошибок `modbus[0]`, `modbus[1]` и `modbus[2]`
|
||||
в CAN-пакете с начальным адресом данных `0`. Признак обрыва/перекоса `Wry`
|
||||
занимает бит 2:
|
||||
|
||||
```text
|
||||
Wry = 0x0004
|
||||
```
|
||||
|
||||
Основной контроллер выставляет:
|
||||
|
||||
```c
|
||||
mpu_out[125].bit6 =
|
||||
(Unites[UMP1_CAN_DEVICE][0] & 0x0004) ||
|
||||
(Unites[UMP1_CAN_DEVICE][1] & 0x0004);
|
||||
|
||||
mpu_out[125].bit10 =
|
||||
(Unites[UMP2_CAN_DEVICE][0] & 0x0004) ||
|
||||
(Unites[UMP2_CAN_DEVICE][1] & 0x0004);
|
||||
```
|
||||
|
||||
С учётом `UMP1_CAN_DEVICE=5` и `UMP2_CAN_DEVICE=6` получаем:
|
||||
|
||||
| Выход MPU | Читаемые данные | CAN ID, заполняющий эти данные |
|
||||
|---|---|---:|
|
||||
| `mpu_out[125].bit6` | `Unites[5][0/1]` | `0x00BA0014` |
|
||||
| `mpu_out[125].bit10` | `Unites[6][0/1]` | `0x00BA0015` |
|
||||
|
||||
Но УМП отправляют:
|
||||
|
||||
| Плата | Фактический CAN ID | Куда пакет попадает сейчас |
|
||||
|---|---:|---|
|
||||
| УМП1, `Mode=5` | `0x00BA0015` | `Unites[6]`, область УМП2 |
|
||||
| УМП2, `Mode=6` | `0x00BA0016` | `Unites[7]`, область `UKSS8` |
|
||||
|
||||
Таким образом, сейчас присутствует смещение адреса на единицу. УМП1 может
|
||||
влиять на `mpu_out[125].bit10` вместо `bit6`, а УМП2 не попадает ни в один из
|
||||
двух ожидаемых массивов УМП.
|
||||
|
||||
## Обратное направление
|
||||
|
||||
Основной контроллер отправляет устройству с индексом `N` через mailbox
|
||||
`15 + N`, которому назначен CAN ID с номером `N - 1`.
|
||||
|
||||
| Получатель | TX CAN ID BALZAM | RX CAN ID peripheral |
|
||||
|---|---:|---:|
|
||||
| УМП1 | `0x00BA0004` | `0x00BA0005` |
|
||||
| УМП2 | `0x00BA0005` | `0x00BA0006` |
|
||||
|
||||
В обратном направлении также имеется смещение на единицу.
|
||||
|
||||
## Вывод
|
||||
|
||||
Перед изменением кода необходимо сверить CAN-трассу и реальные положения
|
||||
адресных перемычек. После подтверждения адресной схемы возможны два варианта:
|
||||
|
||||
1. использовать при настройке CAN peripheral значение `Mode - 1`;
|
||||
2. перенастроить RX/TX mailbox основного контроллера под текущие значения
|
||||
`Mode` peripheral.
|
||||
|
||||
Комментарии возле mailbox основного проекта частично не совпадают с текущими
|
||||
константами устройств, поэтому менять адреса только по комментариям нельзя.
|
||||
|
||||
Binary file not shown.
140
Doc/COMMENT_AUDIT.md
Normal file
140
Doc/COMMENT_AUDIT.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Проверка комментариев и кодировки
|
||||
|
||||
Проверка относится к редактируемым исходникам C/H, ASM, CMD, тестовым INC и Python.
|
||||
Для каждой непустой строки кода проверяется русский текст на ней или непосредственно перед ней.
|
||||
Пустые строки, текст комментариев и содержимое многострочных строк данных не считаются кодом.
|
||||
Качество и достоверность пояснений этой проверкой не устанавливаются; совпадение возможно и в строковом литерале.
|
||||
Охват: исходники из Git-индекса. Сгенерированные файлы и подключённые соседние библиотеки проверяются отдельно.
|
||||
Исходные уведомления TI сохранены. JSON-паспорта, индексы IDE, таблицы XLS и двоичные
|
||||
результаты сборки не допускают исходных комментариев; их назначение описано в документации.
|
||||
|
||||
UTF-8 проверен в 157 текстовых файлах. Строк кода: 18866.
|
||||
|
||||
| Файл | Строк кода | С русским текстом рядом |
|
||||
| --- | ---: | ---: |
|
||||
| Bin/EepromPublishFix/rebuild.py | 41 | 41 |
|
||||
| Bin/StartupWait3s/rebuild.py | 41 | 41 |
|
||||
| Bin/UartColdStart/rebuild.py | 41 | 41 |
|
||||
| F28335.cmd | 69 | 69 |
|
||||
| Source/External/v120/DSP2833x_common/include/DSP2833x_DefaultIsr.h | 89 | 89 |
|
||||
| Source/External/v120/DSP2833x_common/include/DSP2833x_Dma_defines.h | 44 | 44 |
|
||||
| Source/External/v120/DSP2833x_common/include/DSP2833x_EPwm_defines.h | 89 | 89 |
|
||||
| Source/External/v120/DSP2833x_common/include/DSP2833x_Examples.h | 33 | 33 |
|
||||
| Source/External/v120/DSP2833x_common/include/DSP2833x_GlobalPrototypes.h | 156 | 156 |
|
||||
| Source/External/v120/DSP2833x_common/include/DSP2833x_I2c_defines.h | 58 | 58 |
|
||||
| Source/External/v120/DSP2833x_common/include/DSP2833x_SWPrioritizedIsrLevels.h | 5097 | 5097 |
|
||||
| Source/External/v120/DSP2833x_common/include/DSP28x_Project.h | 5 | 5 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_ADC_cal.asm | 8 | 8 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_Adc.c | 14 | 14 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_CpuTimers.c | 45 | 45 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_PieCtrl.c | 37 | 37 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_PieVect.c | 143 | 143 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_SWPrioritizedDefaultIsr.c | 1012 | 1012 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_SWPrioritizedPieVect.c | 392 | 392 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_SysCtrl.c | 188 | 188 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_Xintf.c | 123 | 123 |
|
||||
| Source/External/v120/DSP2833x_common/source/DSP2833x_usDelay.asm | 7 | 7 |
|
||||
| Source/External/v120/DSP2833x_headers/cmd/DSP2833x_Headers_BIOS.cmd | 107 | 107 |
|
||||
| Source/External/v120/DSP2833x_headers/cmd/DSP2833x_Headers_nonBIOS.cmd | 108 | 108 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_Adc.h | 201 | 201 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_CpuTimers.h | 93 | 93 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_DMA.h | 142 | 142 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_DevEmu.h | 57 | 57 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_Device.h | 287 | 287 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_ECan.h | 948 | 948 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_ECap.h | 94 | 94 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_EPwm.h | 297 | 297 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_EQep.h | 165 | 165 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_Gpio.h | 320 | 320 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_I2c.h | 126 | 126 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_Mcbsp.h | 584 | 584 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_PieCtrl.h | 107 | 107 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_PieVect.h | 141 | 141 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_Sci.h | 142 | 142 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_Spi.h | 109 | 109 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_SysCtrl.h | 259 | 259 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_XIntrupt.h | 44 | 44 |
|
||||
| Source/External/v120/DSP2833x_headers/include/DSP2833x_Xintf.h | 77 | 77 |
|
||||
| Source/External/v120/DSP2833x_headers/source/DSP2833x_GlobalVariableDefs.c | 301 | 301 |
|
||||
| Source/Internal/ADC.c | 244 | 244 |
|
||||
| Source/Internal/DAC.c | 253 | 253 |
|
||||
| Source/Internal/Include/ADC.h | 4 | 4 |
|
||||
| Source/Internal/Include/DAC.h | 11 | 11 |
|
||||
| Source/Internal/Include/GPIO_table.h | 329 | 329 |
|
||||
| Source/Internal/Include/RS485.h | 84 | 84 |
|
||||
| Source/Internal/Include/bios_dsp.h | 42 | 42 |
|
||||
| Source/Internal/Include/caliber.h | 35 | 35 |
|
||||
| Source/Internal/Include/cntrl_adr.h | 17 | 17 |
|
||||
| Source/Internal/Include/crc16.h | 6 | 6 |
|
||||
| Source/Internal/Include/ecan.h | 4 | 4 |
|
||||
| Source/Internal/Include/eeprom_config.h | 9 | 9 |
|
||||
| Source/Internal/Include/filter_bat2.h | 36 | 36 |
|
||||
| Source/Internal/Include/gas167.h | 17 | 17 |
|
||||
| Source/Internal/Include/kanal.h | 1 | 1 |
|
||||
| Source/Internal/Include/log_to_mem.h | 36 | 36 |
|
||||
| Source/Internal/Include/measure.h | 90 | 90 |
|
||||
| Source/Internal/Include/message.h | 32 | 32 |
|
||||
| Source/Internal/Include/package.h | 128 | 128 |
|
||||
| Source/Internal/Include/peripher.h | 128 | 128 |
|
||||
| Source/Internal/Include/pulto.h | 1 | 1 |
|
||||
| Source/Internal/Include/spise2p.h | 74 | 74 |
|
||||
| Source/Internal/Include/tools.h | 5 | 5 |
|
||||
| Source/Internal/Include/ump_can_protocol.h | 8 | 8 |
|
||||
| Source/Internal/RS485.c | 534 | 534 |
|
||||
| Source/Internal/bios.c | 236 | 236 |
|
||||
| Source/Internal/cntrl_adr.c | 17 | 17 |
|
||||
| Source/Internal/crc16.c | 158 | 158 |
|
||||
| Source/Internal/ecan.c | 236 | 236 |
|
||||
| Source/Internal/filter_bat2.c | 12 | 12 |
|
||||
| Source/Internal/gas167.c | 54 | 54 |
|
||||
| Source/Internal/kanal.c | 153 | 153 |
|
||||
| Source/Internal/log_to_mem.c | 217 | 217 |
|
||||
| Source/Internal/main.c | 167 | 167 |
|
||||
| Source/Internal/measure.c | 625 | 625 |
|
||||
| Source/Internal/message.c | 293 | 293 |
|
||||
| Source/Internal/peripher.c | 227 | 227 |
|
||||
| Source/Internal/pulto.c | 88 | 88 |
|
||||
| Source/Internal/shared_ump.c | 4 | 4 |
|
||||
| Source/Internal/spise2p.c | 326 | 326 |
|
||||
| Source/Internal/tools.c | 31 | 31 |
|
||||
| UKSSTMS320F28335/28335_RAM_lnk.cmd | 58 | 58 |
|
||||
| UKSSTMS320F28335/firmware_version.h | 6 | 6 |
|
||||
| UKSSTMS320F28335/prepare_identity.py | 41 | 41 |
|
||||
| tests/comments/run_test.py | 129 | 129 |
|
||||
| tests/eeprom_profiles/check_publication.py | 18 | 18 |
|
||||
| tests/eeprom_profiles/run_test.py | 20 | 20 |
|
||||
| tests/eeprom_profiles/spi_test.c | 46 | 46 |
|
||||
| tests/eeprom_profiles/stubs/DSP2833x_Device.h | 22 | 22 |
|
||||
| tests/firmware_identity/check_build.py | 35 | 35 |
|
||||
| tests/firmware_identity/port_test.c | 29 | 29 |
|
||||
| tests/gas167/check_image.py | 44 | 44 |
|
||||
| tests/gas167/gas167_test.c | 213 | 213 |
|
||||
| tests/gas167/run_test.py | 49 | 49 |
|
||||
| tests/load_control/load_control_test.c | 170 | 170 |
|
||||
| tests/load_control/run_test.py | 15 | 15 |
|
||||
| tests/load_control/stubs/DSP2833x_Device.h | 9 | 9 |
|
||||
| tests/load_control/stubs/DSP2833x_SWPrioritizedIsrLevels.h | 0 | 0 |
|
||||
| tests/load_control/stubs/RS485.h | 0 | 0 |
|
||||
| tests/load_control/stubs/filter_bat2.h | 0 | 0 |
|
||||
| tests/load_control/stubs/measure.h | 4 | 4 |
|
||||
| tests/load_control/stubs/message.h | 1 | 1 |
|
||||
| tests/load_control/stubs/package.h | 18 | 18 |
|
||||
| tests/load_control/stubs/peripher.h | 14 | 14 |
|
||||
| tests/load_control/stubs/tools.h | 0 | 0 |
|
||||
| tests/rs232_fifo/model.inc | 122 | 122 |
|
||||
| tests/rs232_fifo/run_test.py | 53 | 53 |
|
||||
| tests/ump_logger/init_test.c | 44 | 44 |
|
||||
| tests/ump_logger/recorder_test.c | 152 | 152 |
|
||||
| tests/ump_logger/run_init_test.py | 30 | 30 |
|
||||
| tests/ump_logger/run_test.py | 34 | 34 |
|
||||
| tests/ump_logger/stubs/ADC.h | 1 | 1 |
|
||||
| tests/ump_logger/stubs/DAC.h | 1 | 1 |
|
||||
| tests/ump_logger/stubs/DSP2833x_Device.h | 9 | 9 |
|
||||
| tests/ump_logger/stubs/RS485.h | 0 | 0 |
|
||||
| tests/ump_logger/stubs/filter_bat2.h | 0 | 0 |
|
||||
| tests/ump_logger/stubs/measure.h | 2 | 2 |
|
||||
| tests/ump_logger/stubs/message.h | 0 | 0 |
|
||||
| tests/ump_logger/stubs/package.h | 11 | 11 |
|
||||
| tests/ump_logger/stubs/peripher.h | 0 | 0 |
|
||||
| tests/ump_logger/test_firmware_image.py | 51 | 51 |
|
||||
| tests/ump_logger/ti_syntax.h | 2 | 2 |
|
||||
288
Doc/DAC_SPI_REVIEW.md
Normal file
288
Doc/DAC_SPI_REVIEW.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# SPI и управление ЦАП в Бальзам 167
|
||||
|
||||
Дата анализа: 23.09.2026. Рассмотрена текущая рабочая копия проекта `167`.
|
||||
Документ описывает существующий код и предложения; прошивка в рамках этого анализа не изменялась.
|
||||
|
||||
## 1. Как устроено сейчас
|
||||
|
||||
ЦАП обслуживает **программный SPI через GPIO**, реализованный в `DAC.c`.
|
||||
Аппаратный SPI-A используется отдельно для EEPROM в `spise2p.c`.
|
||||
Изменение `SpiaRegs.SPIBRR` не меняет скорость передачи в ЦАП.
|
||||
|
||||
| Сигнал ЦАП | Вывод DSP | Имя в таблице платы | Действие |
|
||||
|---|---|---|---|
|
||||
| CS | GPIO59 | csdac, 1:13B | 0 на время кадра, затем 1 |
|
||||
| DIN / MOSI | GPIO60 | didac, 1:13A | данные от DSP к ЦАП |
|
||||
| SCLK | GPIO63 | clkdac, 1:14A | 16 тактов на слово |
|
||||
|
||||
Обозначения контактов взяты из комментариев `GPIO_table.h`, а не из проверенной схемы.
|
||||
MISO в драйвере отсутствует: код отправляет команды, но не читает подтверждение или статус ЦАП.
|
||||
Для платы нагрузки `get_Mode()` выбирает обычные GPIO и выходные направления этих линий.
|
||||
|
||||
Цепочка работы:
|
||||
|
||||
```text
|
||||
CPU Timer1: 1000 Гц, период 1 мс
|
||||
→ cpu_timer1_isr_SENS(), только Desk == dsk_LOAD
|
||||
→ Load_runner()
|
||||
→ каждые 5 вызовов: расчёт задания / инициализация
|
||||
→ Anal_output(kod, time_dac)
|
||||
→ dSEND(16-битное слово)
|
||||
→ GPIO59, GPIO60, GPIO63
|
||||
→ ump_log_tick()
|
||||
```
|
||||
|
||||
`READY_FREQ=1000`, `DAC_FREQ=200`, поэтому `period_dac=5`.
|
||||
200 Гц — частота обновления задания, **не частота SCLK**.
|
||||
`LOAD_TIME=30`, `time_dac=6000` — количество шагов, используемое в расчёте разгона.
|
||||
Вызов `dSEND` синхронный: обработчик таймера занят, пока не выставлены все биты.
|
||||
|
||||
## 2. Что происходит внутри одного SPI-кадра
|
||||
|
||||
Функция `dSEND(word)` выполняет:
|
||||
|
||||
1. Опускает CS и вызывает `DSP28x_usDelay(1L)`.
|
||||
2. Повторяет 16 раз: SCLK=1 → DIN=старший бит → сдвиг слова влево → задержка → SCLK=0 → задержка.
|
||||
3. Поднимает CS.
|
||||
|
||||
Передача начинается со старшего бита: D15 … D0. После кадра SCLK остаётся в 0,
|
||||
DIN — в состоянии последнего бита. Между кадрами CS остаётся в 1.
|
||||
Перед первым кадром `dSEND` отдельно не устанавливает исходное состояние SCLK.
|
||||
|
||||
Последовательность одного бита:
|
||||
|
||||
```text
|
||||
SCLK ↑ → выставить DIN → выдержать время → SCLK ↓ → выдержать время
|
||||
```
|
||||
|
||||
Новый бит устанавливается **после восходящего фронта**, но до нисходящего.
|
||||
Следовательно, код рассчитан на чтение данных по нисходящему фронту; это
|
||||
вывод из последовательности операций, а не подтверждение режима конкретной микросхемы.
|
||||
При SCLK idle=0 такое поведение соответствует замыслу SPI mode 1.
|
||||
Если приёмник читает по восходящему фронту, нужного setup-time здесь нет.
|
||||
Нельзя менять фронты по привычному примеру SPI mode 0 без проверки схемы и паспорта ЦАП.
|
||||
|
||||
Из исходников установлены такие слова:
|
||||
|
||||
| Вызов | Передаваемое слово |
|
||||
|---|---|
|
||||
| `Init_DAC()` | `0x9002` |
|
||||
| Обычное обновление | `0x8000 | (out & 0x0FFF)` |
|
||||
| Ручная калибровка | `0x8000 | (DAC_cal() & 0x0FFF)` |
|
||||
|
||||
Локальная переменная `x` в `Anal_output()` каждый раз получает 0. Ветка отправки
|
||||
без `0x8000` сейчас не выполняется. Точный смысл командных битов, номера канала,
|
||||
режима питания и `0x9002` нельзя достоверно назвать: маркировка ЦАП в исследованных
|
||||
исходниках не указана. Нужны схема или название установленной микросхемы.
|
||||
|
||||
После отправки `0x9002` функция `Init_DAC()` также переключает `RES_OUT_1` —
|
||||
для платы нагрузки это GPIO9. Это отдельная линия с неизвестным здесь
|
||||
электрическим назначением; считать её аппаратным RESET или LDAC без схемы нельзя.
|
||||
|
||||
## 3. Задержки и влияние прерываний
|
||||
|
||||
`DSP28x_usDelay(1L)` **не задаёт 1 мкс**. Ассемблерная функция принимает счётчик
|
||||
циклов своего внутреннего цикла. Для микросекунд библиотека предоставляет макрос
|
||||
`DELAY_US`, который предварительно пересчитывает время.
|
||||
|
||||
В комментарии самой ассемблерной функции приведена модель `9 + 5 × LoopCount`
|
||||
тактов процессора. Она применима с оговорками о памяти без wait-state; вызовы,
|
||||
GPIO-записи, цикл C и прерывания дополнительно влияют на реальную длительность.
|
||||
Поэтому по числу `1L` нельзя вычислять частоту SCLK как 500 кГц или 1 МГц.
|
||||
|
||||
В проекте `XCLKIN=30 МГц`, `CLKMULT=2`, PLL множитель 4, делитель 2:
|
||||
расчётная частота SYSCLKOUT — **60 МГц**, если входной генератор соответствует
|
||||
константе. При этом `CPU_RATE` для макроса `DELAY_US` остался `6.667 нс`
|
||||
(150 МГц). Это несоответствие не участвует в прямом вызове `DSP28x_usDelay(1L)`,
|
||||
но помешает простой замене на `DELAY_US(1)`: сначала надо согласовать CPU_RATE
|
||||
с фактической частотой. При 60 МГц период такта примерно 16.667 нс.
|
||||
|
||||
В таймерном ISR выполняется `EINT` после настройки `IER/MINT13`.
|
||||
В текущей таблице приоритетов Group9 имеет уровень 1, Timer1 — 4;
|
||||
разрешённые прерывания CAN/UART могут удлинять части SPI-кадра.
|
||||
Сам `dSEND` не запрещает прерывания и не имеет защиты от повторного входа.
|
||||
В найденных вызовах передача ЦАП идёт из `Load_runner`; добавлять второго
|
||||
вызывающего без организации единого владельца передачи нельзя.
|
||||
|
||||
Это не доказывает потерю данных: некоторые ЦАП допускают произвольное растяжение
|
||||
SCLK. Следует проверить паспортные ограничения и измерить минимальные и
|
||||
максимальные времена под нагрузкой CAN/RS. Полный запрет прерываний на кадр
|
||||
может уменьшить разброс, но увеличит задержку обработки связи.
|
||||
|
||||
## 4. Инициализация и расчёт аналогового выхода
|
||||
|
||||
`Setup_DAC_time()` задаёт `WAKEpowse=601`. Счётчик уменьшается с частотой 200 Гц.
|
||||
Во время примерно трёхсекундной стартовой фазы `Init_DAC()` вызывается шесть раз,
|
||||
при остатках 600, 500, 400, 300, 200, 100. После этого начинается обычный вывод.
|
||||
Команда `cInitDac` вызывает повторную инициализацию; на этом шаге слово задания
|
||||
не отправляется. При остановленном УМП счётчик `x` в `Load_runner` также вызывает
|
||||
периодическую инициализацию примерно раз в 5.12 с. Это другая переменная `x`,
|
||||
не связанная с постоянным нулём в `Anal_output`.
|
||||
|
||||
Расчёт кода:
|
||||
|
||||
```text
|
||||
out = DAC_min + vrot × DAC_max / maxx − vrot × DAC_min / maxx
|
||||
при cCalibrDac: out = DAC_cal
|
||||
затем out &= 0x0FFF
|
||||
```
|
||||
|
||||
Два деления здесь целочисленные. Их нельзя без проверки заменить одним:
|
||||
`DAC_min + vrot × (DAC_max − DAC_min) / maxx` может дать другое округление.
|
||||
Сначала нужно определить требуемое округление и допустимость изменения результата.
|
||||
|
||||
В `modbus[0x7B]` сохраняется отправленный 12-битный код, а в `modbus[0x1C]` —
|
||||
расчётное задание в десятых долях мА. Это **не измерение выходного тока**.
|
||||
В режиме `cCalibrDac` эти значения могут описывать разные вещи: в ЦАП уходит
|
||||
ручной код, а `0x1C` остаётся результатом формулы разгона.
|
||||
|
||||
## 5. Что стоит исправить в первую очередь
|
||||
|
||||
### 5.1. Порядок запуска таймера — высокий приоритет
|
||||
|
||||
В `main()` выполняются `timer_Init(); EnableInterrupts();`, а затем загрузка
|
||||
параметров и только после неё `Setup_DAC_time()`.
|
||||
В `cpu_timer1_isr_SENS` перед `Load_runner()` нет проверки `READY`.
|
||||
До настройки глобальные `period_dac`, `time_dac`, `WAKEpowse` нулевые.
|
||||
|
||||
Если в этом промежутке сработает Timer1 на плате нагрузки, условие счётчика
|
||||
проходит при нулевом `period_dac`, стартовая задержка отсутствует, и путь может
|
||||
дойти до `Anal_output(..., 0)` — деления на ноль. Это найденный путь выполнения,
|
||||
не результат воспроизведения на железе.
|
||||
|
||||
Предложение: до допуска обслуживания ЦАП настроить GPIO в известное состояние,
|
||||
загрузить/проверить параметры и выполнить `Setup_DAC_time`. Для этого можно
|
||||
отдельно разрешать ветку ЦАП флагом готовности или запускать Timer1 позднее.
|
||||
Нельзя просто отключить все прерывания на время загрузки: EEPROM использует Timer2.
|
||||
Дополнительно проверять `maxx > 0` и допустимость `period_dac` перед расчётом.
|
||||
|
||||
### 5.2. Ошибка ограничения уставки
|
||||
|
||||
В `Load_runner` есть строка:
|
||||
|
||||
```c
|
||||
if (dac_stop > 16) dac_go = 16;
|
||||
```
|
||||
|
||||
При превышении конечной уставки меняется начальная. Вероятное намерение —
|
||||
ограничивать `dac_stop`, но это надо подтвердить требованиями к разгонной
|
||||
характеристике. Ранее `dac_go` ограничивается диапазоном 0..5, а эта строка
|
||||
может сразу заменить его на 16. Следующая проверка способна поднять `dac_stop`
|
||||
до 17. Это влияет на ток независимо от исправности SPI.
|
||||
|
||||
Предложение: описать допустимые пары начальной/конечной уставок в мА,
|
||||
проверять их совместно и протестировать границы. Внутри алгоритма из обеих
|
||||
уставок вычитается 4 мА; ограничения должны учитывать это смещение.
|
||||
|
||||
### 5.3. Маскирование вместо насыщения
|
||||
|
||||
`out & 0xFFF` обрезает старшие биты, но не ограничивает числовое значение:
|
||||
4096 превращается в 0, −1 — в 4095. При ошибочной калибровке или выходе
|
||||
за диапазон это создаёт скачок кода.
|
||||
|
||||
Предложение: сначала проверить входные данные и ограничить результат
|
||||
диапазоном 0..4095, затем сформировать командное слово. Для ошибочных параметров
|
||||
явно определить поведение: отказ, удержание предыдущего кода или заданное
|
||||
проектом аварийное значение. Не выбирать «0» автоматически: код и ток связаны
|
||||
калибровкой и внешней схемой.
|
||||
|
||||
### 5.4. Реальная длительность разгона
|
||||
|
||||
После половины диапазона `count_load` увеличивается дважды за шаг:
|
||||
один раз в `if(count_load > time_dac/2)`, второй — в `++count_load`.
|
||||
Поэтому достижение конца при `LOAD_TIME=30` занимает примерно **22.5 с**,
|
||||
а не 30 с, без учёта начальной фазы и задержек исполнения.
|
||||
Это может быть намеренной двухступенчатой характеристикой.
|
||||
Предложение: явно описать её либо перейти к расчёту по прошедшему времени,
|
||||
если требование действительно состоит в линейном разгоне за 30 с.
|
||||
|
||||
## 6. Улучшения непосредственно SPI
|
||||
|
||||
| Изменение | Польза | Что проверить |
|
||||
|---|---|---|
|
||||
| Явный `dac_bus_init`: CS=1, SCLK в idle, DIN определён; затем включение выходов | Предсказуемый первый кадр | Схема, подтяжки, активные уровни |
|
||||
| Именованные задержки setup/hold/high/low/CS-high | Понятные временные ограничения | Паспорт ЦАП и фактическая частота DSP |
|
||||
| Имена констант вместо `0x9002`, `0x8000`, `0xFFF` | Ясный смысл команд | Сначала установить модель ЦАП |
|
||||
| Один владелец передачи и флаг занятости | Исключает наложение двух кадров | Все вызывающие и разрешённые ISR |
|
||||
| Отдельные функции расчёта кода и отправки слова | Проверка алгоритма без железа | Сохранение округления и масштаба |
|
||||
| Диагностика отправок/максимальной длительности | Показывает нагрузку и задержки | Счётчик отправок не считать ACK от ЦАП |
|
||||
| Удаление неиспользуемого `wast()` и недостижимой ветки `x` | Упрощает чтение | Не затронуть другой `x` в Load_runner |
|
||||
|
||||
Не следует повышать DAC_FREQ ради ускорения SPI: меняется алгоритм обновления,
|
||||
число шагов и стартовые интервалы. Для других частот проверить целочисленность
|
||||
отношения READY_FREQ/DAC_FREQ и диапазон 16-битного `time_dac` на C28x.
|
||||
Текущие 6000 шагов помещаются; будущие LOAD_TIME/DAC_FREQ могут вызвать переполнение.
|
||||
|
||||
Вариант без переделки платы: сохранить GPIO-передачу, нормировать её тайминги,
|
||||
измерить длительность кадра и только затем решать, нужна ли короткая критическая секция.
|
||||
Не переносить отправку в основной цикл без анализа задержек: в проекте есть
|
||||
блокирующие операции EEPROM. Если переносить — использовать явную очередь/последнее
|
||||
задание с оговорённым временем обслуживания и отдельными командами инициализации.
|
||||
|
||||
## 7. Можно ли перейти на аппаратный SPI
|
||||
|
||||
У F28335 один SPI-A. Его выводы могут быть GPIO16/17/18/19 или GPIO54/55/56/57.
|
||||
GPIO60 и GPIO63 не имеют функции SPISIMOA/SPICLKA, поэтому текущие DIN/SCLK
|
||||
не переводятся на SPI-A одной настройкой mux. Нужны изменения соединений.
|
||||
Это подтверждается [таблицами выводов TI, SPRS439Q](https://www.ti.com/lit/ds/symlink/tms320f28335.pdf).
|
||||
|
||||
В данном проекте SPI-A уже обслуживает EEPROM на GPIO16/17/18 и CS=GPIO19.
|
||||
Вариант общей шины требует подключения ЦАП к тем же MOSI/SCLK и отдельного CS,
|
||||
проверки электрической совместимости и последовательного доступа к SPI-A.
|
||||
Если меняются длина слова/фаза/частота, переключать настройки можно только
|
||||
после завершения предыдущей операции. Текущий автомат EEPROM работает через
|
||||
Timer2 и сам меняет формат слова: потребуется общий владелец шины.
|
||||
|
||||
Сначала достаточно рассмотреть один 16-битный аппаратный кадр с ограниченным
|
||||
ожиданием либо прерыванием завершения. FIFO/DMA усложнят короткую передачу;
|
||||
их необходимость следует обосновывать измерениями. CS надо отпускать после
|
||||
фактического окончания сдвига последнего бита, а не сразу после записи TXBUF.
|
||||
Возможность DMA именно для выбранного периферийного блока отдельно проверять
|
||||
по TRM, не переносить механически решение STM32.
|
||||
|
||||
Для будущего порта STM32 можно сохранить общий расчёт и формат слова,
|
||||
а отправку реализовать аппаратным SPI на выводах конкретной платы. Нынешний
|
||||
эмулятор лишь генерирует поля ЦАП в журнале; он не подтверждает физические
|
||||
SPI-фронты и выходной ток устройства.
|
||||
|
||||
## 8. Практический порядок работ и проверка
|
||||
|
||||
1. Установить модель ЦАП, назначение GPIO9, схемные инверсии и требования timing.
|
||||
2. Исправить порядок готовности ЦАП при запуске и защитить деление на ноль.
|
||||
3. Согласовать диапазоны уставок, исправить ограничение и обрезание кода.
|
||||
4. Снять текущие CS/SCLK/DIN при запуске, рабочем разгоне и нагрузке CAN/RS.
|
||||
5. Нормировать программные задержки; аппаратный SPI выбирать по результатам измерений.
|
||||
|
||||
Логический анализатор подключить к CS, SCLK, DIN и общей земле; при необходимости
|
||||
добавить GPIO9. Записать 16 бит каждого кадра, порядок битов, `0x9002`,
|
||||
минимум/середину/максимум кода, setup/hold DIN, CS setup/hold, SCLK high/low,
|
||||
длину кадра и интервал обновления. Отдельно проверить первый кадр после сброса.
|
||||
Частоту дискретизации анализатора выбрать по измеренному SCLK с запасом.
|
||||
Осциллографом проверить форму фронтов и выбросы, внешним измерителем — ток.
|
||||
|
||||
После правок проверить граничные и ошибочные уставки, `maxx=0`, калибровку,
|
||||
разгон/останов, cInitDac, сохранение параметров EEPROM одновременно с CAN/RS.
|
||||
Тесты расчёта должны фиксировать требуемое округление и поведение вне диапазона;
|
||||
программная трасса GPIO — количество фронтов и порядок данных. Проверка GPIO
|
||||
на компьютере не заменяет измерение времён на собранной плате.
|
||||
|
||||
## 9. Основания анализа
|
||||
|
||||
Факты о текущем поведении взяты из следующих файлов; номера строк относятся
|
||||
к рабочей копии на дату анализа:
|
||||
|
||||
- [Формирование кадра, инициализация, расчёт выхода и разгон](C:/setcorp/git/tms_periph_28335/167/Source/Internal/DAC.c:45).
|
||||
- [Запуск таймера и порядок инициализации](C:/setcorp/git/tms_periph_28335/167/Source/Internal/main.c:26).
|
||||
- [Вызов Load_runner из ISR](C:/setcorp/git/tms_periph_28335/167/Source/Internal/measure.c:119).
|
||||
- [Частоты и время разгона](C:/setcorp/git/tms_periph_28335/167/Source/Internal/Include/measure.h:73).
|
||||
- [Назначение линий платы](C:/setcorp/git/tms_periph_28335/167/Source/Internal/Include/GPIO_table.h:294).
|
||||
- [Mux и направления GPIO](C:/setcorp/git/tms_periph_28335/167/Source/Internal/peripher.c:44).
|
||||
- [Аппаратный SPI EEPROM](C:/setcorp/git/tms_periph_28335/167/Source/Internal/spise2p.c:98).
|
||||
- [Счётчик ассемблерной задержки](C:/setcorp/git/tms_periph_28335/167/Source/External/v120/DSP2833x_common/source/DSP2833x_usDelay.asm:62).
|
||||
- [Настройки PLL и CPU_RATE](C:/setcorp/git/tms_periph_28335/167/Source/External/v120/DSP2833x_common/include/DSP2833x_Examples.h:66).
|
||||
- [Приоритеты прерываний](C:/setcorp/git/tms_periph_28335/167/Source/External/v120/DSP2833x_common/include/DSP2833x_SWPrioritizedIsrLevels.h:61).
|
||||
|
||||
Модель ЦАП и электрическая схема не установлены. Режим выборки, назначение
|
||||
командных битов и допустимые длительности нельзя считать подтверждёнными
|
||||
до сверки с документацией конкретной микросхемы. Сборка/прошивка и стендовые
|
||||
измерения в рамках подготовки этого документа не выполнялись.
|
||||
67
Doc/Doxyfile
67
Doc/Doxyfile
@@ -1,67 +0,0 @@
|
||||
# Doxygen configuration for the Balsam 167 peripheral controller firmware.
|
||||
# Run from this directory with build.bat or: doxygen Doxyfile
|
||||
|
||||
PROJECT_NAME = "Balsam 167 Peripheral"
|
||||
PROJECT_NUMBER = "1.0"
|
||||
PROJECT_BRIEF = "TMS320F28335 peripheral controller firmware"
|
||||
|
||||
OUTPUT_DIRECTORY = build/api
|
||||
OUTPUT_LANGUAGE = Russian
|
||||
INPUT_ENCODING = UTF-8
|
||||
INPUT_FILE_ENCODING = *.c=UTF-8 \
|
||||
*.h=UTF-8
|
||||
TAB_SIZE = 4
|
||||
|
||||
INPUT = mainpage.md \
|
||||
api.dox \
|
||||
files.dox \
|
||||
README_CCS12.md \
|
||||
PHASE_BREAK_ERROR_FLOW.md \
|
||||
PHASE_COMPARISON_BALSAM_165_167.md \
|
||||
PHASE_VOLTAGE_CALCULATION.md \
|
||||
PHASE_VOLTAGE_WEAK_POINTS.md \
|
||||
../Source/Internal
|
||||
FILE_PATTERNS = *.c *.h *.md *.dox
|
||||
RECURSIVE = YES
|
||||
USE_MDFILE_AS_MAINPAGE = mainpage.md
|
||||
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
MARKDOWN_SUPPORT = YES
|
||||
AUTOLINK_SUPPORT = YES
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
SORT_MEMBER_DOCS = NO
|
||||
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
PREDEFINED = interrupt= \
|
||||
__interrupt= \
|
||||
EALLOW= \
|
||||
EDIS=
|
||||
ALIASES = precondition="\pre"
|
||||
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
WARN_IF_DOC_ERROR = NO
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_LOGFILE = build/doxygen-warnings.log
|
||||
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
GENERATE_TREEVIEW = YES
|
||||
FULL_SIDEBAR = NO
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
ALPHABETICAL_INDEX = YES
|
||||
SEARCHENGINE = YES
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
HAVE_DOT = NO
|
||||
136
Doc/EEPROM_LAYOUT.md
Normal file
136
Doc/EEPROM_LAYOUT.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# EEPROM 167: выбор AT25256B / M95M02
|
||||
|
||||
Маркировка платы `ATMLH516 5EBL` определяет AT25256B: **256 Кбит**, то есть
|
||||
**32 768 байт**. Расшифровка и характеристики приведены в
|
||||
[даташите Microchip](https://ww1.microchip.com/downloads/aemDocuments/documents/MPD/ProductDocuments/DataSheets/AT25128B-AT25256B-128-256-Kbit-SPI-Serial-EEPROM-Industrial-Grade-Data-Sheet-DS20006193.pdf).
|
||||
|
||||
Константы общей разметки находятся в
|
||||
[templates/include/balsam167_eeprom_layout.h](../../newProject/SETGUI/third_party/templates/c/set-protocol/include/balsam167_eeprom_layout.h).
|
||||
`spise2p.h` использует их для физического размера, количества слов и длины
|
||||
страницы. `message.c` — для адреса параметров. Размер массива параметров
|
||||
проверяется относительно `ANSWER_LEN` на этапе компиляции.
|
||||
|
||||
`F28335.cmd` включает тот же заголовок и экспортирует символы `_EEPROM_*` в
|
||||
`.map`. Путь к templates/c/set-protocol добавлен в search path линкера CLI и CCS.
|
||||
EEPROM не стала секцией CPU MEMORY: SPI-образ загружается в RAM загрузчиком.
|
||||
Расположение `.text`, `.cinit`, `.econst`, `.switch` не менялось.
|
||||
|
||||
| Область | Начало, байт | Конец, исключая | Размер |
|
||||
|---|---:|---:|---:|
|
||||
| Прошивка SCI8 | `0x0000` | `0x7EFC` | 32 508 |
|
||||
| Параметры | `0x7EFC` | `0x7FFE` | 258 |
|
||||
| Неиспользуемое слово | `0x7FFE` | `0x8000` | 2 |
|
||||
|
||||
`check_firmware.ps1` получает размер и резерв из общего заголовка и сверяет
|
||||
резерв с `ANSWER_LEN`. При нестандартном checkout передайте `-TemplatesRoot`;
|
||||
`build_logger.ps1` делает это автоматически. Исторические параметры не перенесены.
|
||||
|
||||
Чтение с платы, единицы адресов, порядок байтов и сохранение дампа описаны в
|
||||
[руководстве SETGUI](../../newProject/SETGUI/docs/BALSAM167_EEPROM.md).
|
||||
Для старой прошивки reader использует CMD_PEEK (2 байта за запрос).
|
||||
Версия 0.1.1 также поддерживает блочное чтение FC03, регистры 0x8000..0xBFFF,
|
||||
до 120 слов (240 байт) за запрос. Полный дамп требует 137 запросов.
|
||||
Границы и формат заданы в templates, GUI использует тонкий Python-порт.
|
||||
Блочное чтение выполняется с разрешёнными прерываниями для работы SPI Timer2.
|
||||
Запись через это окно запрещена; параметры и их расположение не изменяются.
|
||||
|
||||
Размер каждого нового BIN проверяется при сборке; прежний вариант с одним
|
||||
PEEK занимал 32 286 байт. Точный размер новой сборки указан в её manifest.
|
||||
Для реального увеличения памяти потребовались бы другая микросхема, проверка
|
||||
SPI-загрузчика и драйвера, а не только правка линкера.
|
||||
|
||||
|
||||
## Выбор типа памяти (прошивка 0.1.2)
|
||||
|
||||
По умолчанию остаётся AT25256B. Автоматического определения ёмкости нет:
|
||||
контрольные записи для определения типа не выполняются. Выбранный тип должен
|
||||
совпадать с физической микросхемой до запуска программы и чтения параметров.
|
||||
|
||||
### CCS12
|
||||
|
||||
Откройте `Source/Internal/Include/eeprom_config.h`:
|
||||
|
||||
```c
|
||||
#define EEPROM_M95M02 0 /* AT25256B, 32 КиБ */
|
||||
/* Для установленной M95M02 измените значение на 1. */
|
||||
```
|
||||
|
||||
После изменения выполните **Project → Clean**, затем **Rebuild**. Этот файл
|
||||
читают драйвер, обработчик команд и F28335.cmd; post-build использует тот же
|
||||
выбор. Не задавайте противоречащий ему отдельный define только компилятору CCS:
|
||||
тогда компилятор, линкер и проверка BIN могут получить разные настройки.
|
||||
|
||||
### Сборка скриптом
|
||||
|
||||
```powershell
|
||||
./build_logger.ps1 -Eeprom AT25256B -OutputDirectory ./Bin/EepromProfiles/AT25256B -ImageName UKSSTMS320F28335_AT25256B
|
||||
./build_logger.ps1 -Eeprom M95M02 -OutputDirectory ./Bin/EepromProfiles/M95M02 -ImageName UKSSTMS320F28335_M95M02
|
||||
```
|
||||
|
||||
Параметр скрипта передаётся компилятору, линкеру и проверке размера; исходный
|
||||
config не меняется. Скрипт по умолчанию собирает AT25256B. Рядом с BIN создаются
|
||||
manifest и SHA-256; поле `eeprom` в manifest различает аппаратные варианты.
|
||||
UART остаётся 115200; алгоритм UART и FIFO не изменялся.
|
||||
|
||||
| Параметр | AT25256B | M95M02-DR |
|
||||
|---|---:|---:|
|
||||
| Ёмкость, байт | 32768 | 262144 |
|
||||
| Адрес SPI | 2 байта | 3 байта |
|
||||
| Страница записи, байт | 64 | 256 |
|
||||
| Начало параметров, байт | 0x7EFC | 0x3FEFC |
|
||||
| Начало параметров, слова | 0x3F7E | 0x1FF7E |
|
||||
| Конец параметров, исключая | 0x7FFE | 0x3FFFE |
|
||||
| Максимальная область BIN | 32508 | 261884 |
|
||||
|
||||
Последние два байта не используются. У M95M02 старшие адресные биты передаются
|
||||
отдельным восьмибитным тактом, затем младшие 16 бит. Адреса и длины драйвера
|
||||
расширены до 32 бит только в сборке M95M02. Запись делится по физическим страницам;
|
||||
готовность определяется WIP в регистре состояния. На плате с новым чипом ещё
|
||||
нужна проверка записи/считывания и холодного SPI boot; тесты на ПК не заменяют её.
|
||||
|
||||
### SETGUI
|
||||
|
||||
На вкладках **EEPROM 167** и **Загрузка / запуск / прошивка** есть синхронный
|
||||
чекбокс **M95M02 · 256 КиБ**. Снято — AT25256B · 32 КиБ. Он выбирает протокол
|
||||
и допустимый диапазон ПК, но не перепрограммирует тип EEPROM работающей платы.
|
||||
Во время чтения/загрузки переключатель блокируется.
|
||||
|
||||
Для полного дампа нажмите «Вся EEPROM»: 32768 либо 262144 байта. Длина блока
|
||||
остаётся 240 байт. M95M02 требует блочного чтения; автоматический переход на
|
||||
PEEK запрещён. Неподходящая прошивка должна отклонить запрос, а не вернуть
|
||||
повторяющиеся первые 32 КиБ как полный дамп. Дамп можно передать кнопкой
|
||||
«Сравнить с файлом…» напрямую в сравнение BIN.
|
||||
|
||||
При загрузке BIN проверяется поле `eeprom`, если оно присутствует в manifest.
|
||||
Старые файлы без этого поля не позволяют проверить тип. Команда «В SEEPROM»
|
||||
использует отдельный подкод M95M02; старая прошивка его не исполняет. Операция
|
||||
может завершиться таймаутом при несовпадении типа; это не успешная запись.
|
||||
GUI ограничивает отдельную загрузку в RAM существующим пределом 199993 байт:
|
||||
ёмкость EEPROM 256 КиБ сама по себе не увеличивает буфер загрузки или RAM CPU.
|
||||
|
||||
### Замена микросхемы и параметры
|
||||
|
||||
Сначала сохраните полный дамп старой EEPROM и настройки платы. После установки
|
||||
M95M02 запустите её сборку через CCS, запишите соответствующий BIN и сохраните
|
||||
параметры штатной командой Save. Параметры автоматически не мигрируют с 0x7EFC
|
||||
на 0x3FEFC. Простое копирование старого полного дампа в начало новой памяти
|
||||
не переносит настройки в их новую область и оставляет старый вариант прошивки.
|
||||
|
||||
### Общий протокол templates
|
||||
|
||||
Реализация и границы: `balsam167_eeprom_layout.h`, `balsam167_eeprom_block.h`,
|
||||
`periph28335.c`. Публичные функции `*_profile` получают 0 (AT25256B) или 1
|
||||
(M95M02); старые функции и структура reader из четырёх uint32_t сохранены.
|
||||
Python — тонкий ctypes-порт. Профили ПМ67/2812 и STM этим выбором не изменяются.
|
||||
|
||||
Для M95M02 используется частное расширение окна FC03: адрес 0x8000…0xFFFF,
|
||||
quantity = 0x8000 | (bank << 8) | word_count, bank 0…3, word_count 1…120.
|
||||
Каждый запрос содержит свой банк 64 КиБ; общего переключаемого банкового
|
||||
регистра нет. Блок не пересекает границу банка. Это не стандартное количество
|
||||
регистров Modbus — пользоваться следует общим API templates.
|
||||
Подкод EXTEND записи: 4 для AT25256B, 0x44 для M95M02. Адрес назначения в словах,
|
||||
размер в байтах. Обе стороны проверяют границу области прошивки.
|
||||
|
||||
Проверки: C-тест полного дампа 256 КиБ с нечётного адреса, все переходы банков,
|
||||
CRC и выход за границы; Qt-тесты выбора и запрета fallback; host-тест реального
|
||||
SPI-автомата `python tests/eeprom_profiles/run_test.py`; сборка обоих вариантов TI.
|
||||
167
Doc/FIRMWARE_IDENTITY.md
Normal file
167
Doc/FIRMWARE_IDENTITY.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# 167: версия работающей прошивки, SHA-256 и выпуск
|
||||
|
||||
## Что подключено
|
||||
|
||||
167 использует общий `templates/c/firmware-info`, а не копию Climate.
|
||||
Работающий ПМ35 отдаёт 12 регистров версии через RS и служебный CAN.
|
||||
После сборки на компьютере создаются SHA-256 BIN и JSON-паспорт.
|
||||
|
||||
Общая подробная инструкция, включая перенос на TMS320F2812 и STM32:
|
||||
[BUILD_IDENTITY.md](../../newProject/SETGUI/third_party/templates/c/firmware-info/BUILD_IDENTITY.md).
|
||||
|
||||
| Файл проекта | Роль |
|
||||
|---|---|
|
||||
| `UKSSTMS320F28335/firmware_version.h` | Редактируемый номер выпуска: FIRMWARE_VERSION_MAJOR/MINOR/PATCH |
|
||||
| `UKSSTMS320F28335/firmware_identity.json` | Product и target; версия берётся из C-заголовка |
|
||||
| `Source/Internal/shared_ump.c` | Подключение общей таблицы версии и привязка к UMP ПМ35 |
|
||||
| `UKSSTMS320F28335/prepare_identity.py` | Генерация идентичности из C-заголовка перед CCS Debug/Release |
|
||||
| `build_logger.ps1` | Полный CLI build: prepare, compile, link, SCI8, size check, seal |
|
||||
| `build_bin.bat` | Debug post-build: проверка SCI8 и паспорт конечного BIN |
|
||||
| `tests/firmware_identity/port_test.c` | Host-проверка привязки версии к реальному порту 167 |
|
||||
|
||||
Номер `0.1.0` — начальная версия разработки этого механизма; он не выдаётся за
|
||||
историческую версию предыдущих BIN. Назначайте release-номер вручную перед выпуском.
|
||||
|
||||
## Сборка из PowerShell
|
||||
|
||||
Из корня 167:
|
||||
|
||||
```powershell
|
||||
./build_logger.ps1 -OutputDirectory "$PWD/Bin/FirmwareIdentity" `
|
||||
-ImageName UKSSTMS320F28335
|
||||
```
|
||||
|
||||
По умолчанию применяется `-O2 --opt_for_speed=0`. Результаты:
|
||||
|
||||
```text
|
||||
Bin/FirmwareIdentity/UKSSTMS320F28335.bin
|
||||
Bin/FirmwareIdentity/UKSSTMS320F28335.bin.manifest.json
|
||||
Bin/FirmwareIdentity/UKSSTMS320F28335.bin.sha256
|
||||
Bin/FirmwareIdentity/generated/firmware_identity.h
|
||||
Bin/FirmwareIdentity/generated/firmware_identity.json
|
||||
```
|
||||
|
||||
Проверка файла перед передачей:
|
||||
|
||||
```powershell
|
||||
python ../newProject/SETGUI/third_party/templates/c/firmware-info/tools/identity.py verify `
|
||||
--image Bin/FirmwareIdentity/UKSSTMS320F28335.bin `
|
||||
--manifest Bin/FirmwareIdentity/UKSSTMS320F28335.bin.manifest.json
|
||||
```
|
||||
|
||||
CLI принимает `-TemplatesRoot`, если общий checkout расположен иначе. Все
|
||||
исходники общего механизма собираются непосредственно из этого checkout.
|
||||
|
||||
## Сборка CCS
|
||||
|
||||
В `.cproject` добавлены pre-build и include paths `${BuildDirectory}/generated` и
|
||||
`templates/c/firmware-info/include`. После изменения настроек закройте/откройте
|
||||
проект в IDE, затем выполните Clean/Rebuild.
|
||||
|
||||
Pre-build требует Python 3.10+ и Git в PATH процесса CCS. `Generated` принадлежит
|
||||
этому проекту: не запускайте Debug/Release одновременно. Для параллельных
|
||||
сборок используйте CLI с разными output-каталогами.
|
||||
|
||||
Штатный Debug post-build создаёт в `Bin`:
|
||||
|
||||
```text
|
||||
UKSSTMS320F28335_<commit>.bin
|
||||
UKSSTMS320F28335_<commit>.bin.manifest.json
|
||||
UKSSTMS320F28335_<commit>.bin.sha256
|
||||
```
|
||||
|
||||
Имя BIN исторически содержит HEAD без dirty-суффикса; достоверные признаки dirty
|
||||
находятся внутри ответа версии и паспорта. Не определяйте чистоту только по имени.
|
||||
Release-конфигурация получает embedded identity через pre-build, но её старый
|
||||
проект не имел автоматического BIN post-build. Для готового проверенного BIN с
|
||||
паспортом используйте описанный CLI либо настройте release-конверсию по общей
|
||||
инструкции; нельзя запускать Debug `build_bin.bat` на Release и ожидать другой `.out`.
|
||||
|
||||
Если CCS пишет `Error ... (ignored)`, сборка не считается успешной: убедитесь,
|
||||
что последняя проверка и `seal` завершились без ошибок. Старый BIN с таким же
|
||||
именем может оставаться на диске после неудачной сборки.
|
||||
|
||||
## Как прочитать версию
|
||||
|
||||
По прямому RS232/RS485: Modbus **03**, адрес начала **4608 (`0x1200`)**, **12 слов**.
|
||||
Это zero-based адрес в запросе, а не обозначение `4xxxx` в интерфейсе терминала.
|
||||
Адрес ведомого остаётся текущим `CNTRL_ADDR`. Возвращается стандартный RTU-ответ
|
||||
с 24 байтами данных и CRC; дополнительного legacy padding в этом окне нет.
|
||||
|
||||
| Адрес | Содержимое |
|
||||
|---|---|
|
||||
| `0x1200` | Версия формата = 1 |
|
||||
| `0x1201..0x1203` | Major, minor, patch |
|
||||
| `0x1204` | Год UTC |
|
||||
| `0x1205` | Месяц:день, старший:младший октет |
|
||||
| `0x1206` | Час:минута UTC |
|
||||
| `0x1207` | Секунда |
|
||||
| `0x1208..0x120B` | 8 ASCII-символов Build ID, по два на слово |
|
||||
|
||||
По служебному CAN ПМ35: запрос UMP функции 03, `0x1200`, 12 слов; ответ состоит
|
||||
из шести фрагментов. Используется выбранный Mode и существующий token запроса.
|
||||
CAN ПМ67 не переназначается. Запись функции 06 в окно версии запрещена.
|
||||
|
||||
Старый образ может вернуть исключение или неизвестный контракт. Это не следует
|
||||
заменять «ожидаемой» версией выбранного BIN. После прошивки переподключитесь или
|
||||
явно обновите чтение: ответ должен поступить с устройства, а не из кэша GUI.
|
||||
|
||||
## Что сравнивать после заливки
|
||||
|
||||
Сравните SemVer, все поля UTC и Build ID с паспортом именно загруженного BIN.
|
||||
`+` означает локальные изменения приложения **или templates**; полный Git SHA
|
||||
и состояние обоих деревьев записаны в JSON. Проверка SHA на ПК подтверждает
|
||||
целостность файла, но не заменяет проверку программатором записанной памяти.
|
||||
|
||||
В контракте нет аппаратного product ID и хеша всей памяти. Подключённый профиль
|
||||
должен оставаться ПМ35/167, а файл — `product=Balsam-167-PM35`,
|
||||
`target=TMS320F28335`. Не переносите файл на ПМ67 только по похожему имени.
|
||||
|
||||
## Влияние на память и параметры
|
||||
|
||||
С проверенными настройками текущий образ занимает **32 286 байт**, предел —
|
||||
**32 508**, запас **222 байта**. Механизм добавил 116 байт относительно сборки
|
||||
без него. Это результат конкретной сборки, не обещание для следующих изменений.
|
||||
|
||||
Таблица версии — часть `.econst` прошивки. Её не сохраняют в область параметров;
|
||||
старые настройки не могут подменить версию после обновления. Размер буфера лога
|
||||
и размещение EEPROM-параметров не менялись. Дата не разбирается на MCU, SHA-256
|
||||
не вычисляется на MCU. Проверка размера `check_firmware.ps1` остаётся обязательной.
|
||||
|
||||
## Проверки и ограничения
|
||||
|
||||
Проверка соответствия паспорта **реально встроенной** таблице в собранном SCI8:
|
||||
|
||||
```powershell
|
||||
python tests/firmware_identity/check_build.py Bin/FirmwareIdentity/UKSSTMS320F28335.bin
|
||||
```
|
||||
|
||||
Этот независимый тест также сверяет SHA и размер, проходит boot-блоки и ищет
|
||||
точное 12-словное представление версии. Он обнаружит старый объект версии или
|
||||
паспорт другой сборки. Это тест для 167, не транспортный код для GUI.
|
||||
|
||||
Host-тест реального порта (GCC должен быть в PATH):
|
||||
|
||||
```powershell
|
||||
$templates = '../newProject/SETGUI/third_party/templates'
|
||||
gcc -std=c99 -Wall -Wextra -Werror `
|
||||
"-I$templates/c/firmware-info/include" -IBin/FirmwareIdentity/generated `
|
||||
"-I$templates/c/set-protocol" "-I$templates/c/set-protocol/ports/tms320f28335" `
|
||||
tests/firmware_identity/port_test.c Source/Internal/shared_ump.c `
|
||||
-o Bin/FirmwareIdentity/port_test.exe
|
||||
./Bin/FirmwareIdentity/port_test.exe
|
||||
python tests/ump_logger/test_firmware_image.py
|
||||
python tests/ump_logger/run_test.py
|
||||
python tests/ump_logger/run_init_test.py
|
||||
```
|
||||
|
||||
Проверены полный TI build 167, формат SCI8, host-тесты протокола и регистратора,
|
||||
общие тесты identity/SHA, компиляция общего C-кода TI C28x без FPU и ARM Cortex-M4.
|
||||
Это не аппаратная проверка TMS2812/STM32 и не полноценная сборка другого проекта.
|
||||
Физическое чтение нового окна версии и проверку после загрузки нужно выполнить
|
||||
на стенде. В SETGUI на вкладке «Загрузка / запуск / прошивка» доступны
|
||||
«Прочитать версию с платы» и «Проверить файл»: показаны SemVer, дата UTC,
|
||||
Build ID и сравнение с выбранным BIN. Для проверки файла держите рядом его
|
||||
`.bin.manifest.json`; GUI проверяет product/target, размер и SHA-256 и повторяет
|
||||
проверку перед передачей. BIN без паспорта отмечается как непроверенный старый
|
||||
образ; неверный паспорт блокирует загрузку. После RESET прочитайте версию снова.
|
||||
98
Doc/GAS_167_M95M02.md
Normal file
98
Doc/GAS_167_M95M02.md
Normal file
File diff suppressed because one or more lines are too long
97
Doc/GAS_ADDRESS_ALLOCATION.md
Normal file
97
Doc/GAS_ADDRESS_ALLOCATION.md
Normal file
File diff suppressed because one or more lines are too long
270
Doc/GAS_MODBUS_MAP.md
Normal file
270
Doc/GAS_MODBUS_MAP.md
Normal file
File diff suppressed because one or more lines are too long
241
Doc/GAS_MODBUS_PROJECT_COMPARISON.md
Normal file
241
Doc/GAS_MODBUS_PROJECT_COMPARISON.md
Normal file
File diff suppressed because one or more lines are too long
119
Doc/PERIPH28335_CAN.md
Normal file
119
Doc/PERIPH28335_CAN.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# periph_28335: общая панель RS/CAN и регистратор УМП
|
||||
|
||||
## Где находятся панели
|
||||
|
||||
В верхнем ряду вкладок, рядом с **Altera Logic**, появилась **periph_28335**.
|
||||
Внутри неё:
|
||||
|
||||
- **Dima / CAN terminal** — существующий CAN-терминал, его проекты, узлы и настройки адаптера;
|
||||
- **rs232_periph_28335** — существующие операции RS232/485, Modbus и настройки COM;
|
||||
- **Логгер УМП** — единая панель графиков и архива для обоих транспортов.
|
||||
|
||||
В общей группе CAN остались «Шина CAN / мост» и «DevBoard_V1».
|
||||
В общей группе RS232/485 остался RS_TERMINAL_2812.
|
||||
Терминалы сохраняют свои соединения: перенос вкладок не создаёт новые порты.
|
||||
|
||||
## Онлайн и чтение по CAN
|
||||
|
||||
1. Откройте **periph_28335 → Dima / CAN terminal → Настройки**.
|
||||
2. Выберите Candle/gs_usb либо SLCAN/Lawicel и канал адаптера.
|
||||
Для штатной прошивки Бальзам 167 используется CAN 250000 бит/с.
|
||||
Нажмите «Подключить».
|
||||
3. Перейдите в соседнюю вкладку **Логгер УМП**.
|
||||
4. В строке **Связь логгера** выберите **CAN · адаптер Dima**.
|
||||
5. Укажите **CAN-плата (Mode)**: физический номер платы в прошивке, 1..16.
|
||||
Платы нагрузки Бальзам 167 имеют номера 5/6; выбирайте фактически подключённую.
|
||||
Это не RS-адрес 16 и не индекс строки таблицы Dima. Выбор проекта в Dima
|
||||
не меняет CAN-адрес регистратора: он явно определяется этим полем.
|
||||
6. Нажмите **Начать запись** или **Онлайн**, если запись на плате уже идёт.
|
||||
Остальные действия, флажки, легенда, единицы мА и CSV одинаковы для RS и CAN.
|
||||
7. После команды отключения и секунды постинтервала нажмите
|
||||
**Прочитать отключение**. Запись текущего банка на плате продолжается.
|
||||
|
||||
Кнопка **Настройки связи** открывает настройки выбранного транспорта.
|
||||
Состояние адаптера/порта и адреса CAN постоянно отображаются над графиком.
|
||||
**Прервать обмен** останавливает чтение GUI, не посылая команду остановки
|
||||
регистратора или УМП. При переключении канала/платы незавершённые запросы
|
||||
отменяются, поздние ответы не продолжают старую цепочку.
|
||||
|
||||
Для RS выберите **RS232/485** и настройте COM в соседней RS-панели:
|
||||
обычно 115200, адрес 16. Сообщения «не подключён» и «занят запросом» разделены.
|
||||
Отключение RS-порта не останавливает CAN-просмотр. CAN-разрыв не мешает RS.
|
||||
Демо, если оно включено в сборке, по-прежнему работает без физической платы.
|
||||
|
||||
## Изменения прошивки
|
||||
|
||||
Для CAN требуется новая прошивка этой ветки. Предыдущая версия регистратора
|
||||
умела отдавать данные только через Modbus. Старая плата игнорирует новые
|
||||
служебные запросы; GUI сообщает о тайм-ауте без изменения команд УМП.
|
||||
|
||||
- MBOX0: прежняя передача технологических данных, ID 0xBA0010 + Mode - 1.
|
||||
- MBOX1: прежний приём команд, ID 0xBA0000 + Mode - 1; дополнительно
|
||||
распознаётся служебный заголовок 0x1F00 и длина ровно 8 байт.
|
||||
- MBOX2: отдельные ответы регистратора, ID 0xBA0020 + Mode - 1.
|
||||
|
||||
Биты маски записи регистров у служебного запроса равны нулю. Обработчик
|
||||
перехватывает его до изменения modbus[] и до журналирования CAN-команд:
|
||||
опрос собственного журнала не заполняет журнал.
|
||||
|
||||
Запрос ставится в очередь из ISR. Основной цикл формирует целый снимок
|
||||
под короткой блокировкой IRQ и отправляет максимум один кадр за вызов
|
||||
UMP_CAN_service(). Ожидания передачи в цикле нет. Перед следующим
|
||||
фрагментом приоритет отдаётся ожидающей штатной телеметрии MBOX0.
|
||||
Если ACK служебного mailbox не приходит 250 тиков таймера, передача
|
||||
отменяется. При этом штатные CAN-команды и MBOX0 не отменяются.
|
||||
|
||||
По CAN доступны те же расширенные адреса 0x1000 / 0x1010 / 0x1100,
|
||||
состав записи и версия снимка 2. Новый протокол не даёт писать через
|
||||
служебный запрос в технологические адреса 0..127.
|
||||
|
||||
## Формат кадров
|
||||
|
||||
CAN 2.0B, расширенный ID, 8 байт данных. Порядок соответствует существующей
|
||||
прошивке: MDL (слова 1,2), затем MDH (заголовок, слово 0). Каждое слово
|
||||
содержит сначала старший байт.
|
||||
|
||||
Запрос: `[адрес BE16, значение/длина BE16, 0x1F00 BE16, token:function BE16]`.
|
||||
Функция 3 — чтение, 6 — запись; token — номер запроса 1..255.
|
||||
|
||||
Ответ: `[данные0 BE16, данные1 BE16, (0x1F00+индекс) BE16, token:error BE16]`.
|
||||
Номер фрагмента 0..61, в нём два слова снимка. Ошибка 0 означает успех,
|
||||
1 — неизвестная функция, 2 — неверный адрес/диапазон, 3 — запрещённое значение.
|
||||
У записи успешный ответ содержит эхо адреса и значения.
|
||||
|
||||
Пример: Mode=5, token=7, чтение статуса 16 слов.
|
||||
Запрос ID `0x00BA0004`, данные `10 00 00 10 1F 00 07 03`.
|
||||
Ответы ID `0x00BA0024`, восемь фрагментов по два слова.
|
||||
Онлайн-снимок из 124 слов передаётся 62 фрагментами.
|
||||
|
||||
GUI принимает только ответ выбранной платы с номером текущего запроса,
|
||||
восстанавливает порядок фрагментов, игнорирует одинаковые дубликаты и
|
||||
отклоняет противоречащие. Неполный снимок не попадает на график.
|
||||
После потери подтверждения записи GUI прямо сообщает, что команда могла
|
||||
выполниться; автоматического повторного старта регистратора нет.
|
||||
|
||||
Онлайн показывает последние три записи из полного снимка. При высокой
|
||||
нагрузке шины/низкой скорости возможны пропуски онлайн-отображения;
|
||||
они считаются существующим счётчиком. Архив читается целиком по блокам.
|
||||
Предполагается один активный читатель архива: его курсор общий для RS/CAN.
|
||||
Одновременное управление архивным курсором из двух независимых программ
|
||||
не поддерживается.
|
||||
|
||||
## Проверки и ограничения
|
||||
|
||||
Пройдены тесты протокола, сборки всех 62 фрагментов, неверного адреса/токена,
|
||||
пропущенных и повторных фрагментов, ACK и ошибок, отмены при смене канала,
|
||||
иерархии вкладок и сохранения RS/демо. Набор тестов выполнен на Qt 6 и Qt 5.
|
||||
В прошивке проверен настоящий код формирования ответов через host-тест;
|
||||
изменённые C-файлы прошли проверку синтаксиса Clang с исходными заголовками.
|
||||
|
||||
Сборка TI/CCS, проверка MAP и испытание CAN на реальной плате ещё требуются.
|
||||
Особенно проверить тайминги IRQ и приоритет штатной телеметрии на нагруженной
|
||||
шине. Файлы прошивки Bin/*.out/hex не заменены. Архив остаётся в ОЗУ:
|
||||
команда отключения фиксирует его, пропадание питания стирает.
|
||||
|
||||
## Общее ядро templates
|
||||
|
||||
Сервер CAN/RS логгера подключён через `Source/Internal/shared_ump.c`.
|
||||
Для сборки требуется соседний `../../templates`. Контракт и порты:
|
||||
`templates/c/set-protocol/docs/UMP_PROTOCOL.md`.
|
||||
@@ -1,337 +0,0 @@
|
||||
@page phase_break_error_flow Детектирование и передача ошибки обрыва фаз
|
||||
|
||||
# Детектирование и передача ошибки обрыва фаз
|
||||
|
||||
## 1. Назначение
|
||||
|
||||
Документ описывает полную связь от входов АЦП платы УМП до выставления
|
||||
признаков обрыва фаз в `modbus_table_mpu_out[125]` основного контроллера
|
||||
`BALZAM_167`.
|
||||
|
||||
В текущей реализации обрыв определяется как сильный перекос действующих
|
||||
значений фаз. Отдельных независимых флагов для физических фаз A, B и C нет.
|
||||
Передаётся общий флаг `Wry` с маской `0x0004`.
|
||||
|
||||
## 2. Общая цепочка сигнала
|
||||
|
||||
```text
|
||||
Фазные напряжения
|
||||
|
|
||||
v
|
||||
АЦП peripheral-платы
|
||||
CONV02 -> channel 0 -> измеряемая фаза A
|
||||
CONV03 -> channel 1 -> измеряемая фаза C
|
||||
|
|
||||
v
|
||||
Current_count(0), Current_count(1)
|
||||
|
|
||||
+--> RMS A = lev_count[0]
|
||||
+--> RMS C = lev_count[1]
|
||||
+--> RMS B = lev_count[4], расчёт B = -(A + C)
|
||||
|
|
||||
v
|
||||
Выбор Max = max(RMS A, RMS B, RMS C)
|
||||
|
|
||||
v
|
||||
(Max - RMS проверяемой фазы) / Max > 0.30
|
||||
AND Max > Curr_Edge
|
||||
|
|
||||
v
|
||||
Счётчик выдержки er_anal()
|
||||
|
|
||||
v
|
||||
error.bit.Wry = 1 (бит 2, маска 0x0004)
|
||||
|
|
||||
v
|
||||
sens_error[0] / sens_error[1]
|
||||
|
|
||||
v
|
||||
modbus[0] / modbus[1]
|
||||
|
|
||||
v
|
||||
Быстрый CAN-цикл peripheral-платы
|
||||
|
|
||||
v
|
||||
Unites[UMP1_CAN_DEVICE][0/1]
|
||||
или Unites[UMP2_CAN_DEVICE][0/1]
|
||||
|
|
||||
v
|
||||
BALZAM_167, update_abnormal.c
|
||||
|
|
||||
+--> mpu_out[125].bit6 — УМП1
|
||||
+--> mpu_out[125].bit10 — УМП2
|
||||
```
|
||||
|
||||
## 3. Связь входов АЦП с фазами
|
||||
|
||||
Для режима УМП (`Desk == dsk_LOAD`) преобразования настроены в
|
||||
`Source/Internal/ADC.c`.
|
||||
|
||||
| АЦП | Физический вход | Внутренний канал | Назначение |
|
||||
|---|---:|---:|---|
|
||||
| `CONV02` | `ADCINA5` | `0` | измеряемое напряжение фазы A |
|
||||
| `CONV03` | `ADCINA4` | `1` | измеряемое напряжение фазы C |
|
||||
| `CONV04` | `ADCINA7` | `2` | ток первого канала |
|
||||
| `CONV05` | `ADCINA2` | `3` | ток второго канала |
|
||||
|
||||
В обработчике АЦП результаты `ADCRESULT2...ADCRESULT5` записываются в
|
||||
`adc_table_lem[0...3]`, после чего для каждого канала вызывается
|
||||
`Current_count(i)`.
|
||||
|
||||
## 4. Расчёт действующих значений
|
||||
|
||||
Из отсчёта АЦП вычитается сохранённый нулевой уровень и применяется
|
||||
калибровочный коэффициент:
|
||||
|
||||
```c
|
||||
Current = (Numb - Zero_lev[chan]) * powK[chan];
|
||||
```
|
||||
|
||||
Действующее значение измеряемой фазы рассчитывается через экспоненциальное
|
||||
усреднение квадрата:
|
||||
|
||||
```c
|
||||
lev_quadr[chan] +=
|
||||
((Current * Current) - lev_quadr[chan]) / (1.0 * ADC_FREQ);
|
||||
|
||||
lev_count[chan] = sqrt(lev_quadr[chan]);
|
||||
```
|
||||
|
||||
Третья фаза непосредственно не измеряется. Она восстанавливается из условия
|
||||
нулевой суммы фаз:
|
||||
|
||||
```text
|
||||
A + B + C = 0
|
||||
B = -(A + C)
|
||||
```
|
||||
|
||||
В коде:
|
||||
|
||||
```c
|
||||
Numb = -Current - aCurrent;
|
||||
lev_quadr[thrd] +=
|
||||
(Numb * Numb - lev_quadr[thrd]) / (1.0 * ADC_FREQ);
|
||||
lev_count[thrd] = sqrt(lev_quadr[thrd]);
|
||||
```
|
||||
|
||||
Диагностические значения публикуются в следующих регистрах:
|
||||
|
||||
| Регистр peripheral | Значение |
|
||||
|---:|---|
|
||||
| `0x68` | RMS фазы A |
|
||||
| `0x69` | RMS фазы C |
|
||||
| `0x6A` | расчётный RMS фазы B |
|
||||
| `0x6B` | RMS первого токового канала |
|
||||
| `0x6C` | RMS второго токового канала |
|
||||
| `0x6D` | расчётный RMS третьего тока |
|
||||
|
||||
## 5. Условие выставления `Wry`
|
||||
|
||||
Для каждой пары выбирается максимальный уровень:
|
||||
|
||||
```c
|
||||
Max = max(lev_count[chan], lev_count[pair], lev_count[thrd]);
|
||||
```
|
||||
|
||||
Ошибка набирается при выполнении обоих условий:
|
||||
|
||||
```text
|
||||
(Max - PhaseRms) / Max > 0.30
|
||||
Max > Curr_Edge
|
||||
```
|
||||
|
||||
Для УМП устанавливается:
|
||||
|
||||
```c
|
||||
Curr_Edge = 300;
|
||||
```
|
||||
|
||||
Следовательно, флаг формируется, когда:
|
||||
|
||||
1. максимальная из трёх фаз больше `300`;
|
||||
2. проверяемая фаза ниже максимальной более чем на 30%;
|
||||
3. счётчик `er_anal()` достиг выдержки.
|
||||
|
||||
Пример:
|
||||
|
||||
```text
|
||||
RMS A = 400
|
||||
RMS B = 390
|
||||
RMS C = 100
|
||||
|
||||
Max = 400
|
||||
(400 - 100) / 400 = 0.75
|
||||
0.75 > 0.30 -> условие обрыва/перекоса фазы C активно
|
||||
```
|
||||
|
||||
Если все три уровня одновременно ниже `Curr_Edge`, `Wry` не выставляется.
|
||||
Полное пропадание напряжения должно определяться диагностикой низкого уровня
|
||||
`Out`, а не фазовым перекосом `Wry`.
|
||||
|
||||
## 6. Выдержка времени
|
||||
|
||||
Частота обработки:
|
||||
|
||||
```c
|
||||
#define ADC_FREQ 3750
|
||||
```
|
||||
|
||||
Порог счётчика:
|
||||
|
||||
```c
|
||||
time_3sec = 3 * ADC_FREQ; /* 11250 */
|
||||
```
|
||||
|
||||
Функция `er_anal()` увеличивает счётчик на каждом ошибочном отсчёте и уменьшает
|
||||
его на каждом нормальном отсчёте:
|
||||
|
||||
```c
|
||||
if (term) {
|
||||
if (*count >= edge)
|
||||
return 1;
|
||||
(*count)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*count == 0)
|
||||
return 0;
|
||||
|
||||
(*count)--;
|
||||
return 0;
|
||||
```
|
||||
|
||||
Для измеряемых фаз A и C номинальная выдержка составляет около 3 секунд.
|
||||
Расчётная фаза B проверяется при обработке обоих измеряемых каналов, поэтому
|
||||
её общий счётчик увеличивается дважды за цикл АЦП. Фактическая выдержка для B
|
||||
может составлять около 1,5 секунды.
|
||||
|
||||
После запуска УМП диагностика блокируется на время `WAKE`:
|
||||
|
||||
```c
|
||||
WAKE_TIME = 10L * ADC_FREQ;
|
||||
```
|
||||
|
||||
То есть первые 10 секунд после запуска `Wry` не формируется.
|
||||
|
||||
## 7. Формирование регистра ошибки peripheral-платы
|
||||
|
||||
Структура регистра ошибки определена в `Source/Internal/Include/measure.h`:
|
||||
|
||||
| Бит | Маска | Поле | Назначение |
|
||||
|---:|---:|---|---|
|
||||
| 0 | `0x0001` | `Tear` | крайнее значение АЦП/обрыв датчика |
|
||||
| 2 | `0x0004` | `Wry` | перекос или предполагаемый обрыв фазы |
|
||||
| 3 | `0x0008` | `Out` | низкий общий уровень |
|
||||
| 4 | `0x0010` | `Over` | превышение тока |
|
||||
| 5 | `0x0020` | `Hyper` | превышение напряжения |
|
||||
| 8 | `0x0100` | `Stop` | требование аварийного останова |
|
||||
| 9 | `0x0200` | `Ready` | готовность канала |
|
||||
| 14 | `0x4000` | `Ignor` | запрет локального останова |
|
||||
| 15 | `0x8000` | `Bypas` | полное исключение канала |
|
||||
|
||||
После достижения выдержки выполняется:
|
||||
|
||||
```c
|
||||
error.bit.Wry = 1;
|
||||
|
||||
if (!ignor)
|
||||
error.bit.Stop = 1;
|
||||
```
|
||||
|
||||
Поведение управляющих признаков:
|
||||
|
||||
| Состояние | `Wry` | `Stop` | Передача по CAN |
|
||||
|---|---:|---:|---:|
|
||||
| обычный канал | 1 | 1 | да |
|
||||
| `Ignor = 1` | 1 | 0 | да |
|
||||
| `Bypas = 1` | 0 | 0 | передаётся регистр без ошибки |
|
||||
| `WAKE != 0` | 0 | 0 | передаётся регистр без ошибки |
|
||||
|
||||
Для УМП признаки напряжений находятся в регистрах ошибок:
|
||||
|
||||
| Регистр | Содержит `Wry` при проблеме |
|
||||
|---:|---|
|
||||
| `modbus[0]` | измеряемая фаза A или расчётная фаза B |
|
||||
| `modbus[1]` | измеряемая фаза C или расчётная фаза B |
|
||||
|
||||
В основном контроллере регистры `0` и `1` объединяются логическим ИЛИ, поэтому
|
||||
для индикации достаточно наличия маски `0x0004` в любом из них.
|
||||
|
||||
## 8. Передача по CAN
|
||||
|
||||
`Init_packMask()` включает регистры ошибок УМП `0...3` в быстрый CAN-цикл.
|
||||
Главный цикл peripheral-платы вызывает:
|
||||
|
||||
```c
|
||||
CAN_send(0, modbus, address);
|
||||
```
|
||||
|
||||
Один CAN-пакет содержит начальный адрес и три 16-битных регистра. Основной
|
||||
контроллер принимает пакет и записывает данные в массив:
|
||||
|
||||
```text
|
||||
Unites[номер устройства][адрес регистра]
|
||||
```
|
||||
|
||||
Соответствие устройств:
|
||||
|
||||
| Устройство | CAN-индекс основного контроллера | Регистры флага |
|
||||
|---|---:|---:|
|
||||
| УМП1 | `UMP1_CAN_DEVICE = 5` | `Unites[5][0]`, `Unites[5][1]` |
|
||||
| УМП2 | `UMP2_CAN_DEVICE = 6` | `Unites[6][0]`, `Unites[6][1]` |
|
||||
|
||||
## 9. Выставление `mpu_out[125]`
|
||||
|
||||
Основной контроллер выполняет проверку в
|
||||
`BALZAM_167/Src/balzam_7/update_abnormal.c`.
|
||||
|
||||
### УМП1
|
||||
|
||||
```c
|
||||
modbus_table_mpu_out[125].bit.bit6 =
|
||||
(Unites[UMP1_CAN_DEVICE][0] & 0x4) ||
|
||||
(Unites[UMP1_CAN_DEVICE][1] & 0x4)
|
||||
? 1 : 0;
|
||||
```
|
||||
|
||||
### УМП2
|
||||
|
||||
```c
|
||||
modbus_table_mpu_out[125].bit.bit10 =
|
||||
(Unites[UMP2_CAN_DEVICE][0] & 0x4) ||
|
||||
(Unites[UMP2_CAN_DEVICE][1] & 0x4)
|
||||
? 1 : 0;
|
||||
```
|
||||
|
||||
Оба признака разрешены только при следующем условии:
|
||||
|
||||
```c
|
||||
f.FittingScheme == 1
|
||||
```
|
||||
|
||||
Если выбрана другая схема, основной контроллер принудительно записывает ноль
|
||||
в `mpu_out[125].bit6` и `mpu_out[125].bit10` независимо от данных УМП.
|
||||
|
||||
## 10. Итоговая таблица связей
|
||||
|
||||
| Физическое событие | Peripheral-регистр | Передаваемая маска | Приёмник | Выход MPU |
|
||||
|---|---:|---:|---|---|
|
||||
| перекос/обрыв A на УМП1 | `modbus[0]` | `0x0004` | `Unites[5][0]` | `mpu_out[125].bit6` |
|
||||
| расчётный перекос B на УМП1 | `modbus[0]` или `[1]` | `0x0004` | `Unites[5][0/1]` | `mpu_out[125].bit6` |
|
||||
| перекос/обрыв C на УМП1 | `modbus[1]` | `0x0004` | `Unites[5][1]` | `mpu_out[125].bit6` |
|
||||
| перекос/обрыв A на УМП2 | `modbus[0]` | `0x0004` | `Unites[6][0]` | `mpu_out[125].bit10` |
|
||||
| расчётный перекос B на УМП2 | `modbus[0]` или `[1]` | `0x0004` | `Unites[6][0/1]` | `mpu_out[125].bit10` |
|
||||
| перекос/обрыв C на УМП2 | `modbus[1]` | `0x0004` | `Unites[6][1]` | `mpu_out[125].bit10` |
|
||||
|
||||
## 11. Ограничения алгоритма
|
||||
|
||||
1. `Wry` означает как обрыв, так и сильный перекос более 30%; эти события не
|
||||
различаются.
|
||||
2. Фаза B не измеряется непосредственно. Если при физическом обрыве B фазы A
|
||||
и C остаются нормальными, расчётная B также может выглядеть нормальной и
|
||||
ошибка не будет обнаружена.
|
||||
3. Одновременное исчезновение всех фаз не создаёт `Wry`, потому что не
|
||||
выполняется условие `Max > 300`.
|
||||
4. Из-за двойной проверки расчётной фазы B её выдержка короче выдержки A и C.
|
||||
5. Выходные биты `mpu_out[125].bit6` и `bit10` не показывают конкретную фазу,
|
||||
а только общий факт фазового перекоса соответствующего УМП.
|
||||
@@ -1,600 +0,0 @@
|
||||
@page phase_comparison_balsam Сравнение фазовой части Balsam 165 и Balsam 167
|
||||
|
||||
# Сравнение фазовой части Balsam 165 и Balsam 167
|
||||
|
||||
## Область сравнения
|
||||
|
||||
Сравнивались:
|
||||
|
||||
- захват фазных сигналов АЦП;
|
||||
- удаление нулевого смещения;
|
||||
- масштабирование в физические единицы;
|
||||
- расчёт общего действующего значения;
|
||||
- расчёт уровней отдельных фаз A, B и C;
|
||||
- диагностика перекоса и обрыва фаз;
|
||||
- диагностические биты и регистры Modbus;
|
||||
- пороги напряжения и выдержки времени.
|
||||
|
||||
Исходные проекты:
|
||||
|
||||
- `K:/git_project/Balsam_165_periph`;
|
||||
- `K:/git_project/Balsam_167_periph`.
|
||||
|
||||
Основные файлы:
|
||||
|
||||
| Проект | Файл |
|
||||
|---|---|
|
||||
| Balsam 165 | `K:/git_project/Balsam_165_periph/Source/Internal/measure.c` |
|
||||
| Balsam 165 | `K:/git_project/Balsam_165_periph/Source/Internal/ADC.c` |
|
||||
| Balsam 165 | `K:/git_project/Balsam_165_periph/Source/Internal/Include/measure.h` |
|
||||
| Balsam 165 | `K:/git_project/Balsam_165_periph/Doc/Balsam 165 data stru.xls` |
|
||||
| Balsam 167 | `Source/Internal/measure.c` |
|
||||
| Balsam 167 | `Source/Internal/ADC.c` |
|
||||
| Balsam 167 | `Source/Internal/Include/measure.h` |
|
||||
| Balsam 167 | `Doc/Balsam 167 data stru.xls` |
|
||||
|
||||
## Вывод
|
||||
|
||||
Balsam 167 использует более правильный способ расчёта действующих значений
|
||||
отдельных фаз: усреднение квадрата с последующим извлечением корня. Balsam 165
|
||||
сглаживает модуль сигнала, что не является настоящим RMS.
|
||||
|
||||
При этом в Balsam 167 появились две ошибки индексации:
|
||||
|
||||
1. Парный канал записывается по абсолютному индексу, но читается по
|
||||
относительному.
|
||||
2. Бит `Ignor` устанавливается у абсолютного номера датчика, но проверяется у
|
||||
относительного `chan`.
|
||||
|
||||
Для УМП, где `pow_addr == 0`, первая ошибка не проявляется. Для силового блока
|
||||
она может приводить к дублированию фазных уровней и ложному `Wry + Stop`.
|
||||
|
||||
Рекомендуемый вариант: сохранить RMS-алгоритм Balsam 167, исправить индексацию
|
||||
и выполнять диагностику трёх фаз один раз после обработки всей пары каналов.
|
||||
|
||||
## Сводная таблица
|
||||
|
||||
| Параметр | Balsam 165 | Balsam 167 | Оценка |
|
||||
|---|---|---|---|
|
||||
| Частота АЦП | 5000 Гц | 3750 Гц | Изменена |
|
||||
| Выбор фазных входов АЦП | `CONV02…CONV05` | `CONV02…CONV05` | Одинаковый |
|
||||
| Формула `im_calc()` | Одинаковая | Одинаковая | Без изменений |
|
||||
| Фаза B | `-A-C`, для `dsk_COMM` эквивалентная разность | `-A-C` после смены знака A | По модулю эквивалентно |
|
||||
| Уровень отдельной фазы | EMA от `abs(x)` | `sqrt(EMA(x²))` | 167 корректнее |
|
||||
| Частота фильтра результата | 5 Гц | 3 Гц | 167 медленнее |
|
||||
| Тип `lev_count[]` | `float` | `int` | В 167 раньше теряется дробная часть |
|
||||
| Порог перекоса | 20% | 30% | 167 менее чувствителен |
|
||||
| Выдержка измеряемой фазы | около 1,5 с | около 3 с | 167 медленнее |
|
||||
| Выдержка восстановленной фазы | около 0,75 с | около 1,5 с | В обеих версиях вдвое короче |
|
||||
| `Curr_Edge`, УМП | 100 | 300 | Порог существенно повышен |
|
||||
| `Curr_Edge`, силовой блок | 40 | 200 | Порог существенно повышен |
|
||||
| Низкое `Utr` | без выдержки | счётчик около 3 с | Улучшено, но блокируется `Ignor` |
|
||||
| Верхнее `Utr` | без выдержки | без выдержки | Без улучшения |
|
||||
| Калибровка входов | жёсткий `curK[]` | Modbus/EEPROM `Caliber[]` | 167 гибче |
|
||||
| Пары каналов силового блока | корректные относительные индексы | несогласованные индексы | Регрессия 167 |
|
||||
| Обработка `Ignor` | правильный абсолютный датчик | проверяется `chan` | Регрессия 167 |
|
||||
| Отдельные биты фаз A/B/C | нет | нет | Общий недостаток |
|
||||
| Контроль пределов АЦП U/I | нет | нет | Общий недостаток |
|
||||
|
||||
## 1. Захват сигналов АЦП
|
||||
|
||||
Для УМП обе версии используют одинаковые входы:
|
||||
|
||||
```c
|
||||
CONV02 = 0x5; // напряжение 1
|
||||
CONV03 = 0x4; // напряжение 2
|
||||
CONV04 = 0x7; // ток 1
|
||||
CONV05 = 0x2; // ток 2
|
||||
```
|
||||
|
||||
Данные читаются из результатов `ADCRESULT2…ADCRESULT5`, после чего вызывается
|
||||
`Current_count(i)`.
|
||||
|
||||
Различается частота обработки:
|
||||
|
||||
```text
|
||||
Balsam 165: ADC_FREQ = 5000 Гц
|
||||
Balsam 167: ADC_FREQ = 3750 Гц
|
||||
```
|
||||
|
||||
Назначение входов УМП:
|
||||
|
||||
| `chan` | Сигнал |
|
||||
|---:|---|
|
||||
| 0 | `Utr A` |
|
||||
| 1 | `Utr C` |
|
||||
| 2 | `Itr A` |
|
||||
| 3 | `Itr C` |
|
||||
|
||||
Фаза B физически не измеряется.
|
||||
|
||||
## 2. Нулевое смещение
|
||||
|
||||
В обеих версиях используется медленное усреднение:
|
||||
|
||||
```text
|
||||
zero[n] = zero[n-1] + (ADC-zero[n-1]) / (5 * ADC_FREQ)
|
||||
```
|
||||
|
||||
### Balsam 165
|
||||
|
||||
Ноль записывается постоянно:
|
||||
|
||||
```c
|
||||
Zero_lev[chan] = filterbat(&out_filter[chan], zer_count[chan]);
|
||||
```
|
||||
|
||||
Для подстройки используются те же `out_filter[]`, которые участвуют в другой
|
||||
обработке сигналов.
|
||||
|
||||
### Balsam 167
|
||||
|
||||
Добавлены отдельные фильтры `zer_filter[]`:
|
||||
|
||||
```c
|
||||
Zer = filterbat(&zer_filter[chan], zer_count[chan]);
|
||||
if (WAKE < (WAKE_TIME / 2)) Zero_lev[chan] = Zer;
|
||||
```
|
||||
|
||||
Разделение фильтров является улучшением. Однако после того как `WAKE` достиг
|
||||
нуля, условие остаётся истинным. Подстройка нуля фактически продолжается во
|
||||
время всей работы.
|
||||
|
||||
Если подстройка нужна только при запуске, должно проверяться также `WAKE > 0`.
|
||||
|
||||
## 3. Масштабирование
|
||||
|
||||
### Balsam 165
|
||||
|
||||
Используются жёстко заданные коэффициенты `curK[]`:
|
||||
|
||||
| Устройство | Напряжение | Ток |
|
||||
|---|---:|---:|
|
||||
| УМП 1/2 | `0.386` | `4.82` |
|
||||
| Силовой блок | `0.402` | — |
|
||||
|
||||
Коэффициенты одинаковы для однотипных каналов и не берутся из EEPROM.
|
||||
|
||||
### Balsam 167
|
||||
|
||||
Коэффициенты вычисляются из `Caliber[0…3]`:
|
||||
|
||||
```text
|
||||
напряжение: powK = Caliber / 10000
|
||||
ток: powK = Caliber / 1000
|
||||
```
|
||||
|
||||
Преимущества:
|
||||
|
||||
- индивидуальная калибровка каждого входа;
|
||||
- отдельные значения для экземпляров устройств;
|
||||
- сохранение и загрузка через EEPROM.
|
||||
|
||||
Значения тока заметно отличаются от Balsam 165. Например, для УМП 1 в
|
||||
Balsam 167 используются `3.505` и `3.380` вместо `4.82`. Это может быть связано
|
||||
с изменением аппаратной части или новой калибровкой и требует стендовой сверки.
|
||||
|
||||
## 4. Общий уровень трёхфазного сигнала
|
||||
|
||||
Функция `im_calc()` в проектах совпадает:
|
||||
|
||||
```text
|
||||
isA = -1.5 * (a + b)
|
||||
isB = cos(π/6) * (a - b)
|
||||
Amplitude = 2/3 * sqrt(isA² + isB²)
|
||||
Level = Amplitude / sqrt(2)
|
||||
```
|
||||
|
||||
Эквивалентная формула амплитуды:
|
||||
|
||||
```text
|
||||
Amplitude = 2/sqrt(3) * sqrt(a² + a*b + b²)
|
||||
```
|
||||
|
||||
### Фильтрация общего уровня
|
||||
|
||||
Balsam 165 сначала делит амплитуду на `sqrt(2)`, затем фильтрует `Level`
|
||||
фильтром 5 Гц. Для тока и всех каналов `dsk_COMM` используется дополнительная
|
||||
статическая переменная `ffLev`.
|
||||
|
||||
`ffLev` одна на все вызовы функции. На силовом блоке результаты разных пар
|
||||
могут влиять друг на друга.
|
||||
|
||||
Balsam 167 фильтрует амплитуду отдельным фильтром текущего датчика:
|
||||
|
||||
```c
|
||||
Amplitude = filterbat(&out_filter[sens], im_calc(Current, aCurrent));
|
||||
Level = Amplitude / RADIX2;
|
||||
```
|
||||
|
||||
Это устраняет общий `ffLev` и разделяет состояния фильтров разных пар.
|
||||
|
||||
### Зона нечувствительности
|
||||
|
||||
Balsam 165:
|
||||
|
||||
```text
|
||||
Level < Curr_Edge -> Level = 0
|
||||
```
|
||||
|
||||
Для УМП порог равен 100 единицам RMS.
|
||||
|
||||
Balsam 167:
|
||||
|
||||
```text
|
||||
напряжение: Amplitude < 20 -> 0
|
||||
ток: Amplitude < 75 -> 0
|
||||
```
|
||||
|
||||
В пересчёте на RMS это примерно 14,1 для напряжения и 53,0 для тока. Поэтому
|
||||
Balsam 167 публикует слабые сигналы, которые Balsam 165 обнулял.
|
||||
|
||||
## 5. Уровни отдельных фаз
|
||||
|
||||
### Balsam 165: среднее модуля
|
||||
|
||||
```c
|
||||
lev_count[chan] +=
|
||||
(fabs(Current) - lev_count[chan]) / (ADC_FREQ / 5);
|
||||
```
|
||||
|
||||
Для синусоиды установившееся значение соответствует среднему модулю:
|
||||
|
||||
```text
|
||||
MeanAbs = 2/π * Amplitude ≈ 0.6366 * Amplitude
|
||||
```
|
||||
|
||||
### Balsam 167: настоящий RMS
|
||||
|
||||
```c
|
||||
lev_quadr[chan] +=
|
||||
(Current * Current - lev_quadr[chan]) / ADC_FREQ;
|
||||
lev_count[chan] = sqrt(lev_quadr[chan]);
|
||||
```
|
||||
|
||||
Для синусоиды:
|
||||
|
||||
```text
|
||||
RMS = 1/sqrt(2) * Amplitude ≈ 0.7071 * Amplitude
|
||||
```
|
||||
|
||||
При одинаковом входном масштабе Balsam 167 показывает примерно в 1,1107 раза,
|
||||
или на 11,1%, больше Balsam 165.
|
||||
|
||||
Это изменение влияет на абсолютные фазные уровни, но почти не влияет на
|
||||
отношение минимальной фазы к максимальной, используемое для `Wry`.
|
||||
|
||||
### Скорость сглаживания
|
||||
|
||||
Balsam 165 использует коэффициент `5/ADC_FREQ`, что соответствует постоянной
|
||||
времени около 0,2 с.
|
||||
|
||||
Balsam 167 использует коэффициент `1/ADC_FREQ`, что соответствует постоянной
|
||||
времени около 1 с. Фазные уровни Balsam 167 изменяются медленнее и стабильнее.
|
||||
|
||||
## 6. Восстановление фазы B
|
||||
|
||||
Для УМП в обеих версиях:
|
||||
|
||||
```text
|
||||
B = -A - C
|
||||
```
|
||||
|
||||
Для силового блока в Balsam 165 используется:
|
||||
|
||||
```text
|
||||
third = current_channel - first_channel
|
||||
```
|
||||
|
||||
В Balsam 167 сначала меняется знак сохранённого первого канала, затем
|
||||
применяется общая формула `-Current-aCurrent`. Результат отличается знаком, но
|
||||
для RMS знак не имеет значения.
|
||||
|
||||
Основной недостаток общий: фаза B не измеряется. Неисправность B определяется
|
||||
только через математическую связь с A и C.
|
||||
|
||||
## 7. Карта фазных регистров
|
||||
|
||||
В Balsam 165 код записывает:
|
||||
|
||||
```text
|
||||
0x68 + n*3 + 0 = текущий нечётный канал, для УМП фаза C
|
||||
0x68 + n*3 + 1 = парный канал, для УМП фаза A
|
||||
0x68 + n*3 + 2 = восстановленная фаза B
|
||||
```
|
||||
|
||||
То есть фактический порядок для УМП:
|
||||
|
||||
```text
|
||||
C, A, B
|
||||
```
|
||||
|
||||
В Balsam 167 первые две записи переставлены:
|
||||
|
||||
```text
|
||||
0x68 + n*3 + 0 = парный канал A
|
||||
0x68 + n*3 + 1 = текущий канал C
|
||||
0x68 + n*3 + 2 = восстановленная фаза B
|
||||
```
|
||||
|
||||
Порядок соответствует карте Balsam 167:
|
||||
|
||||
| Регистр | УМП |
|
||||
|---:|---|
|
||||
| `0x68` | `Utr A` |
|
||||
| `0x69` | `Utr C` |
|
||||
| `0x6A` | `Utr B` |
|
||||
| `0x6B` | `Itr A` |
|
||||
| `0x6C` | `Itr C` |
|
||||
| `0x6D` | `Itr B` |
|
||||
|
||||
В карте Balsam 165 эти регистры не описаны как фазные. Адрес `0x68` обозначен
|
||||
как яркость ламп, хотя исходный код записывает туда фазный уровень. Это риск
|
||||
несовместимости прошивки с внешним ПО и документацией.
|
||||
|
||||
## 8. Диагностика `Wry`
|
||||
|
||||
В обеих версиях используется отношение:
|
||||
|
||||
```text
|
||||
Max = max(phase_A, phase_C, phase_B)
|
||||
deviation = (Max - phase) / Max
|
||||
```
|
||||
|
||||
### Balsam 165
|
||||
|
||||
```text
|
||||
deviation > 20%
|
||||
Max > Curr_Edge
|
||||
выдержка измеряемой фазы ≈ 1,5 с
|
||||
```
|
||||
|
||||
`Curr_Edge`:
|
||||
|
||||
| Режим | Значение |
|
||||
|---|---:|
|
||||
| УМП | 100 |
|
||||
| Силовой блок | 40 |
|
||||
|
||||
### Balsam 167
|
||||
|
||||
```text
|
||||
deviation > 30%
|
||||
Max > Curr_Edge
|
||||
выдержка измеряемой фазы ≈ 3 с
|
||||
```
|
||||
|
||||
`Curr_Edge`:
|
||||
|
||||
| Режим | Значение |
|
||||
|---|---:|
|
||||
| УМП | 300 |
|
||||
| Силовой блок | 200 |
|
||||
|
||||
Balsam 167 значительно менее чувствителен к перекосу и реагирует медленнее.
|
||||
|
||||
### Ошибка выдержки восстановленной фазы
|
||||
|
||||
Один счётчик `err_count[thrd]` вызывается при обработке обоих каналов пары.
|
||||
Поэтому он увеличивается дважды за цикл АЦП.
|
||||
|
||||
Фактическая выдержка постоянного дефекта фазы B:
|
||||
|
||||
| Проект | Заданная | Фактическая для B |
|
||||
|---|---:|---:|
|
||||
| Balsam 165 | 1,5 с | около 0,75 с |
|
||||
| Balsam 167 | 3 с | около 1,5 с |
|
||||
|
||||
Проблема присутствует в обеих версиях.
|
||||
|
||||
### Деление на ноль
|
||||
|
||||
Обе версии сначала вычисляют отношение с делением на `Max`, а затем проверяют
|
||||
нижний порог:
|
||||
|
||||
```c
|
||||
((Max - phase) / Max > limit) && (Max > Curr_Edge)
|
||||
```
|
||||
|
||||
При `Max == 0` выполняется `0/0`. Безопасный порядок:
|
||||
|
||||
```c
|
||||
(Max > Curr_Edge) && (((Max - phase) / Max) > limit)
|
||||
```
|
||||
|
||||
## 9. Различия обработки `Ignor`
|
||||
|
||||
### Balsam 165
|
||||
|
||||
Используется правильный абсолютный номер датчика:
|
||||
|
||||
```c
|
||||
sens = tpl_cans + chan;
|
||||
ignor = sens_error[sens].bit.Ignor;
|
||||
```
|
||||
|
||||
Ошибки `Wry`, `Out` и `Hyper` продолжают вычисляться и передаваться, но
|
||||
`Stop` не устанавливается для игнорируемого канала.
|
||||
|
||||
### Balsam 167
|
||||
|
||||
Проверяется относительный индекс:
|
||||
|
||||
```c
|
||||
sens = pow_addr + chan;
|
||||
if (WAKE || sens_error[chan].bit.Ignor) goto fin;
|
||||
```
|
||||
|
||||
Последствия различаются по типу устройства.
|
||||
|
||||
#### УМП
|
||||
|
||||
Для УМП `pow_addr == 0`, поэтому индекс формально совпадает. Каналам напряжения
|
||||
`0x00` и `0x01` по умолчанию устанавливается `Ignor`. В результате Balsam 167
|
||||
полностью пропускает для напряжения:
|
||||
|
||||
- `Wry`;
|
||||
- `Out` при `Utr < 300 В`;
|
||||
- `Hyper` при `Utr > 420 В`;
|
||||
- `Stop`.
|
||||
|
||||
В Balsam 165 эти информационные биты вычислялись, но `Stop` блокировался.
|
||||
|
||||
#### Силовой блок
|
||||
|
||||
На силовом блоке `pow_addr != 0`. `Ignor` устанавливается в
|
||||
`sens_error[pow_addr+chan]`, но проверяется `sens_error[chan]`.
|
||||
|
||||
Из-за этого игнорирование может не сработать, а `Wry + Stop` сформироваться для
|
||||
канала, который должен быть исключён из диагностики.
|
||||
|
||||
## 10. Регрессия `sens_pair` в Balsam 167
|
||||
|
||||
В Balsam 165 пары хранятся относительно `chan`:
|
||||
|
||||
```c
|
||||
sens_pair[0] = 1;
|
||||
sens_pair[1] = 0;
|
||||
sens_pair[2] = 3;
|
||||
sens_pair[3] = 2;
|
||||
pair = sens_pair[chan];
|
||||
```
|
||||
|
||||
В Balsam 167 пары записываются по абсолютному индексу:
|
||||
|
||||
```c
|
||||
sens_pair[pow_addr+i] = pow_addr+(i^1);
|
||||
```
|
||||
|
||||
Но чтение осталось старым:
|
||||
|
||||
```c
|
||||
pair = sens_pair[chan];
|
||||
```
|
||||
|
||||
Для силового блока элементы `sens_pair[0…3]` после общей инициализации равны
|
||||
`0, 1, 2, 3`. Следовательно, `pair` указывает на текущий канал, а не на
|
||||
соседний.
|
||||
|
||||
Последствия:
|
||||
|
||||
- один фазный уровень может записываться дважды;
|
||||
- максимальная фаза выбирается из неполного набора;
|
||||
- `Wry` может быть пропущен или сформирован ошибочно;
|
||||
- карта `0x68…0x6D` для силового блока не соответствует ожидаемой.
|
||||
|
||||
Вероятное исправление:
|
||||
|
||||
```c
|
||||
pair = sens_pair[sens] - pow_addr;
|
||||
```
|
||||
|
||||
Окончательный вариант следует подтвердить стендовым тестом и ожидаемым
|
||||
порядком фаз в регистрах.
|
||||
|
||||
## 11. Пороговые уровни УМП
|
||||
|
||||
Заводские уставки в проектах совпадают:
|
||||
|
||||
| Сигнал | Нижний порог | Верхний порог |
|
||||
|---|---:|---:|
|
||||
| `Utr` | 300 В | 420 В |
|
||||
| `Itr` | 800 А, предупреждение | 900 А, авария |
|
||||
|
||||
Различается обработка нижнего напряжения:
|
||||
|
||||
| Проект | Реакция `Utr < 300 В` |
|
||||
|---|---|
|
||||
| Balsam 165 | `Out` сразу; `Stop` блокируется при штатном `Ignor` |
|
||||
| Balsam 167 | счётчик около 3 с, но при штатном `Ignor` проверка не выполняется |
|
||||
|
||||
Верхний порог `Utr > 420 В` в обеих версиях не имеет отдельной выдержки и
|
||||
гистерезиса.
|
||||
|
||||
## 12. Диагностические биты
|
||||
|
||||
Расположение основных битов не изменилось:
|
||||
|
||||
| Бит | Маска | Имя | Назначение |
|
||||
|---:|---:|---|---|
|
||||
| 0 | `0x0001` | `Tear` | обрыв датчика/предельное значение АЦП |
|
||||
| 2 | `0x0004` | `Wry` | перекос фаз |
|
||||
| 3 | `0x0008` | `Out` | ниже нижнего порога |
|
||||
| 4 | `0x0010` | `Over` | выше предупредительного порога |
|
||||
| 5 | `0x0020` | `Hyper` | выше аварийного порога |
|
||||
| 8 | `0x0100` | `Stop` | авария |
|
||||
| 9 | `0x0200` | `Ready` | готовность |
|
||||
| 14 | `0x4000` | `Ignor` | игнорировать аварию |
|
||||
| 15 | `0x8000` | `Bypas` | отключить канал |
|
||||
|
||||
В обеих версиях `Current_count()` не формирует `Tear` для фазных входов U/I.
|
||||
Поэтому неисправность измерительного тракта нельзя надёжно отличить от
|
||||
пропадания напряжения или тока.
|
||||
|
||||
## 13. Что следует перенести из Balsam 165
|
||||
|
||||
В Balsam 167 полезно вернуть следующие свойства реализации 165:
|
||||
|
||||
1. Согласованную систему индексов `sens_pair`.
|
||||
2. Проверку `Ignor` через абсолютный индекс `sens_error[sens]`.
|
||||
3. Использование `float` для внутренних фазных уровней до момента публикации.
|
||||
|
||||
Не следует возвращать:
|
||||
|
||||
- усреднение `fabs()` вместо RMS;
|
||||
- общий статический фильтр `ffLev`;
|
||||
- немедленное срабатывание нижнего напряжения;
|
||||
- жёсткие коэффициенты `curK[]`.
|
||||
|
||||
## 14. Рекомендуемая итоговая реализация
|
||||
|
||||
1. Считать все абсолютные номера датчиков один раз:
|
||||
|
||||
```c
|
||||
sens = pow_addr + chan;
|
||||
```
|
||||
|
||||
2. Хранить `sens_pair[]` либо полностью в относительных, либо полностью в
|
||||
абсолютных индексах. Не смешивать системы адресации.
|
||||
3. Сохранить RMS Balsam 167, но хранить `lev_count[]` как `float`.
|
||||
4. После поступления обоих отсчётов пары вычислять A, C и B в одном месте.
|
||||
5. Один раз за цикл обновлять три RMS и три диагностических счётчика.
|
||||
6. Проверять `Max > Curr_Edge` до деления.
|
||||
7. Проверять `Ignor` через `sens_error[sens]`.
|
||||
8. Разделить понятия:
|
||||
|
||||
- информационная ошибка присутствует;
|
||||
- ошибка участвует в формировании `Stop`.
|
||||
|
||||
9. Добавить отдельную маску фаз A/B/C.
|
||||
10. Добавить `Tear` по сырому значению АЦП.
|
||||
11. Добавить выдержку и гистерезис для 300/420 В.
|
||||
12. Явно определить, должна ли подстройка нуля работать после запуска.
|
||||
|
||||
## 15. Минимальные сравнительные тесты
|
||||
|
||||
| Тест | Что проверить |
|
||||
|---|---|
|
||||
| Одинаковая синусоида на обеих версиях | Разницу MeanAbs и RMS около 11,1% |
|
||||
| Номинальные A и C | Правильный порядок A/C/B в `0x68…0x6D` |
|
||||
| Обрыв A | RMS A, `Wry`, выдержку |
|
||||
| Обрыв C | RMS C, `Wry`, выдержку |
|
||||
| Нарушение вычисленной B | Отсутствие двойной скорости счётчика |
|
||||
| Перекос 20%, 25%, 30%, 35% | Различия порогов 165 и 167 |
|
||||
| `Max == 0` | Отсутствие деления на ноль |
|
||||
| `Utr = 299 В` | `Out` и выдержку |
|
||||
| `Utr = 421 В` | `Hyper` и отсутствие дребезга |
|
||||
| `Ignor = 1` | Ошибка видна, но не создаёт `Stop`, если это требуемая семантика |
|
||||
| Силовой блок, две пары | Отсутствие дублирования фазных RMS |
|
||||
| АЦП около 0 и 4095 | Формирование `Tear` |
|
||||
|
||||
## Заключение
|
||||
|
||||
Фазовый расчёт Balsam 167 является хорошей основой благодаря настоящему RMS,
|
||||
раздельным фильтрам и калибровке из регистров. Главный риск версии 167 находится
|
||||
не в математике RMS, а в адресации состояния каналов.
|
||||
|
||||
До исправления `sens_pair` и `Ignor` фазные регистры и `Wry` силового блока
|
||||
нельзя считать надёжными. Для УМП необходимо отдельно решить, должны ли
|
||||
напряжения с установленным `Ignor` продолжать формировать информационные
|
||||
`Wry`, `Out` и `Hyper`, как это происходило в Balsam 165.
|
||||
@@ -1,344 +0,0 @@
|
||||
@page phase_voltage_calculation Расчёт входных фаз, диагностика обрыва и уровни напряжения
|
||||
|
||||
# Расчёт входных фаз, диагностика обрыва и уровни напряжения
|
||||
|
||||
Документ составлен по исходникам прошивки Balsam 167 и карте регистров
|
||||
`Doc/Balsam 167 data stru.xls`.
|
||||
|
||||
## Где находится код
|
||||
|
||||
Основная обработка входных напряжений и токов находится в
|
||||
`Source/Internal/measure.c`:
|
||||
|
||||
- `im_calc()` — восстановление амплитуды трёхфазного сигнала, строки 82–89;
|
||||
- `Current_count()` — смещение АЦП, масштабирование, RMS фаз, общий уровень и
|
||||
диагностика перекоса/пропадания, строки 444–614;
|
||||
- `Power_count()` — контроль отдельных источников питания шкафа ВЭП,
|
||||
строки 769–841;
|
||||
- `er_anal()` — выдержка времени для диагностических признаков,
|
||||
строки 423–432.
|
||||
|
||||
Частота расчёта задаётся как `ADC_FREQ = 3750 Гц` в
|
||||
`Source/Internal/Include/measure.h:73`. Выбор каналов АЦП выполняется в
|
||||
`Source/Internal/ADC.c`, а пороги по умолчанию — в
|
||||
`Source/Internal/message.c:24–135`.
|
||||
|
||||
## 1. Получение входных отсчётов
|
||||
|
||||
Для плат с измерением напряжения/тока обрабатываются четыре входа:
|
||||
|
||||
| `chan` | Назначение для УМП (`dsk_LOAD`) | Сырой регистр |
|
||||
|---:|---|---:|
|
||||
| 0 | напряжение фазы A (`Utr A`) | `0x64` |
|
||||
| 1 | напряжение фазы C (`Utr C`) | `0x65` |
|
||||
| 2 | ток фазы A (`Itr A`) | `0x66` |
|
||||
| 3 | ток фазы C (`Itr C`) | `0x67` |
|
||||
|
||||
В `ADC.c:228–233` результат АЦП читается так:
|
||||
|
||||
```c
|
||||
adc_table_lem[i] = *((&AdcRegs.ADCRESULT0)+i+2) >> 4;
|
||||
Current_count(i);
|
||||
```
|
||||
|
||||
То есть используются 12 старших значащих бит результата АЦП.
|
||||
|
||||
### Удаление нулевого смещения и перевод в физические единицы
|
||||
|
||||
В `Current_count()` выполняется:
|
||||
|
||||
```text
|
||||
N = adc_table_lem[chan]
|
||||
X = (N - Zero_lev[chan]) * powK[chan]
|
||||
```
|
||||
|
||||
`Zero_lev[0..3]` хранится в регистрах `0x70…0x73`; значение по умолчанию —
|
||||
`0x800 = 2048`. Ноль дополнительно подстраивается медленным фильтром:
|
||||
|
||||
```text
|
||||
zero[n] = zero[n-1] + (N - zero[n-1]) / (5 * 3750)
|
||||
```
|
||||
|
||||
Коэффициент `powK` формируется из калибровки `Caliber[0..3]`:
|
||||
|
||||
```text
|
||||
для напряжения: powK = Caliber / 10000
|
||||
для тока: powK = Caliber / 1000
|
||||
```
|
||||
|
||||
Калибровочные значения находятся в Modbus-регистрах `0x74…0x77`, могут быть
|
||||
загружены из EEPROM и поэтому не обязаны совпадать со значениями по умолчанию.
|
||||
|
||||
Для Balsam 167 значения по умолчанию такие:
|
||||
|
||||
| Устройство | Каналы | `Caliber` | `powK` |
|
||||
|---|---|---|---|
|
||||
| Силовой 1, адрес 3 | `UA1, UB1, UA2, UB2` | `4936, 4877, 4972, 4857` | `0.4936, 0.4877, 0.4972, 0.4857` |
|
||||
| Силовой 2, адрес 4 | `UA1, UB1, UA2, UB2` | `4876, 5005, 4876, 4847` | `0.4876, 0.5005, 0.4876, 0.4847` |
|
||||
| УМП 1, адрес 5 | `Utr A, Utr C, Itr A, Itr C` | `3820, 3790, 3505, 3380` | `0.3820, 0.3790, 3.505, 3.380` |
|
||||
| УМП 2, адрес 6 | `Utr A, Utr C, Itr A, Itr C` | `3835, 3785, 3522, 3332` | `0.3835, 0.3785, 3.522, 3.332` |
|
||||
|
||||
Источник значений: `Source/Internal/Include/caliber.h`, секция
|
||||
`#if BALSAM == 167`.
|
||||
|
||||
## 2. Расчёт амплитуды и действующего значения
|
||||
|
||||
Функция `im_calc(a, b)` использует два измеренных фазных сигнала:
|
||||
|
||||
```text
|
||||
isA = -1.5 * (a + b)
|
||||
isB = cos(π/6) * (a - b)
|
||||
Amplitude = 2/3 * sqrt(isA² + isB²)
|
||||
```
|
||||
|
||||
Эквивалентная свёрнутая формула:
|
||||
|
||||
```text
|
||||
Amplitude = 2/sqrt(3) * sqrt(a² + a*b + b²)
|
||||
```
|
||||
|
||||
После цифрового фильтра Баттерворта 3 Гц получается амплитуда сигнала.
|
||||
Действующее значение вычисляется как:
|
||||
|
||||
```text
|
||||
Level = Amplitude / sqrt(2)
|
||||
```
|
||||
|
||||
Для каналов напряжения амплитуда принудительно обнуляется при
|
||||
`Amplitude < 20`; для каналов тока — при `Amplitude < 75`.
|
||||
|
||||
Результат пары записывается в два регистра данных:
|
||||
|
||||
```text
|
||||
sens_data[нечётный канал] = Amplitude
|
||||
sens_data[чётный канал] = Level
|
||||
```
|
||||
|
||||
Для УМП это даёт:
|
||||
|
||||
| Регистр | Значение |
|
||||
|---:|---|
|
||||
| `0x18` | действующее `Utr` |
|
||||
| `0x19` | амплитудное `Utr` |
|
||||
| `0x1A` | действующее `Itr` |
|
||||
| `0x1B` | амплитудное `Itr` |
|
||||
|
||||
Для силового блока адреса данных сдвинуты из-за температурных каналов:
|
||||
`0x28/0x29` — действующее/амплитудное `Uвх1`, `0x2A/0x2B` —
|
||||
действующее/амплитудное `Uвх2`.
|
||||
|
||||
## 3. Действующие значения отдельных фаз
|
||||
|
||||
Для каждой пары измеряются две фазы, третья восстанавливается по условию
|
||||
трёхпроводной системы:
|
||||
|
||||
```text
|
||||
x3 = -x1 - x2
|
||||
```
|
||||
|
||||
Для каждого из трёх сигналов считается скользящее среднеквадратичное значение:
|
||||
|
||||
```text
|
||||
Qphase[n] = Qphase[n-1] + (xphase² - Qphase[n-1]) / 3750
|
||||
RMSphase = sqrt(Qphase)
|
||||
```
|
||||
|
||||
`lev_count[]` имеет тип `int`, поэтому сохранённый RMS усекается до целого.
|
||||
|
||||
Карта регистров фаз для УМП:
|
||||
|
||||
| Регистр | Пара входов | Значение |
|
||||
|---:|---|---|
|
||||
| `0x68` | напряжение | RMS фазы A (`Utr A`) |
|
||||
| `0x69` | напряжение | RMS фазы C (`Utr C`) |
|
||||
| `0x6A` | напряжение | RMS восстановленной фазы B (`Utr B`) |
|
||||
| `0x6B` | ток | RMS фазы A (`Itr A`) |
|
||||
| `0x6C` | ток | RMS фазы C (`Itr C`) |
|
||||
| `0x6D` | ток | RMS восстановленной фазы B (`Itr B`) |
|
||||
|
||||
В коде назначение пары определяется как `feed = chan >> 1`, а начальный адрес
|
||||
фазных уровней — как `0x68 + feed * 3`.
|
||||
|
||||
## 4. Диагностика обрыва или сильного перекоса фазы
|
||||
|
||||
Отдельных битов «обрыв фазы A», «обрыв фазы B» и «обрыв фазы C» в прошивке
|
||||
нет. Есть общий признак сильного отличия одной из трёх фаз — `Wry`.
|
||||
Конкретную пропавшую фазу надо определять по минимальному значению среди
|
||||
регистров `0x68…0x6A` или `0x6B…0x6D`.
|
||||
|
||||
Алгоритм в `Current_count()`:
|
||||
|
||||
```text
|
||||
Max = max(RMS_A, RMS_B, RMS_C)
|
||||
|
||||
перекос фазы = ((Max - RMS_phase) / Max > 0.30) AND (Max > Curr_Edge)
|
||||
```
|
||||
|
||||
Условие проходит через реверсивный счётчик `er_anal()`: при наличии ошибки он
|
||||
увеличивается, а при исчезновении уменьшается, но не сбрасывается сразу. Порог
|
||||
для измеряемой фазы равен примерно 3 секундам
|
||||
(`time_3sec = 3 * ADC_FREQ = 11250` отсчётов). Для восстановленной фазы один и
|
||||
тот же счётчик вызывается из обоих каналов пары, поэтому при постоянной ошибке
|
||||
порог фактически достигается примерно вдвое быстрее — около 1,5 секунды.
|
||||
После достижения порога устанавливаются:
|
||||
|
||||
| Бит диагностического слова | Маска | Имя | Значение |
|
||||
|---:|---:|---|---|
|
||||
| 2 | `0x0004` | `Wry` | перекос/пропадание одной из фаз более чем на 30% от максимальной |
|
||||
| 8 | `0x0100` | `Stop` | авария, устанавливается вместе с `Wry` |
|
||||
|
||||
Для УМП `Curr_Edge = 300`. Поэтому фазовая диагностика не работает при
|
||||
`Max <= 300` и не реагирует на слабый сигнал/шум около нуля.
|
||||
|
||||
Диагностические слова УМП:
|
||||
|
||||
| Регистр | Канал |
|
||||
|---:|---|
|
||||
| `0x00` | `Utr A` |
|
||||
| `0x01` | `Utr C` |
|
||||
| `0x02` | `Itr A` |
|
||||
| `0x03` | `Itr C` |
|
||||
|
||||
При одиночном пропадании фаз ожидается следующая комбинация:
|
||||
|
||||
| Пропавшая фаза | Напряжение | Ток |
|
||||
|---|---|---|
|
||||
| A | `0x00.Wry` | `0x02.Wry` |
|
||||
| C | `0x01.Wry` | `0x03.Wry` |
|
||||
| B, восстановленная | `0x00.Wry` и `0x01.Wry` | `0x02.Wry` и `0x03.Wry` |
|
||||
|
||||
Вместе с каждым `Wry` ставится `Stop`. Эта комбинация выведена из порядка
|
||||
проверок в коде, но при сложном перекосе она неоднозначна. Надёжнее определять
|
||||
проблемную фазу по тройке RMS-регистров.
|
||||
|
||||
В месте чтения Modbus признаки можно проверять масками:
|
||||
|
||||
```c
|
||||
// Напряжение УМП
|
||||
bool phase_a_fault = (modbus[0x00] & 0x0004) != 0;
|
||||
bool phase_c_fault = (modbus[0x01] & 0x0004) != 0;
|
||||
bool voltage_stop = ((modbus[0x00] | modbus[0x01]) & 0x0100) != 0;
|
||||
|
||||
// Ток УМП
|
||||
bool current_a_fault = (modbus[0x02] & 0x0004) != 0;
|
||||
bool current_c_fault = (modbus[0x03] & 0x0004) != 0;
|
||||
bool current_stop = ((modbus[0x02] | modbus[0x03]) & 0x0100) != 0;
|
||||
```
|
||||
|
||||
Названия `phase_a_fault` и `phase_c_fault` здесь условные: каждый `Wry` также
|
||||
участвует в контроле восстановленной фазы B. Для точной индикации следует
|
||||
сравнить сами уровни `0x68…0x6D`.
|
||||
|
||||
### Другие связанные биты диагностики
|
||||
|
||||
Структура диагностического слова задана в
|
||||
`Source/Internal/Include/measure.h:19–46`:
|
||||
|
||||
| Бит | Маска | Имя | Назначение |
|
||||
|---:|---:|---|---|
|
||||
| 0 | `0x0001` | `Tear` | обрыв датчика/крайнее значение АЦП; в фазовом расчёте не формируется |
|
||||
| 2 | `0x0004` | `Wry` | перекос парных датчиков/фаз |
|
||||
| 3 | `0x0008` | `Out` | уровень ниже нижней уставки |
|
||||
| 4 | `0x0010` | `Over` | уровень выше предупредительной уставки |
|
||||
| 5 | `0x0020` | `Hyper` | уровень выше аварийной верхней уставки |
|
||||
| 6 | `0x0040` | `Contr` | нет сигнала на одном из дискретных входов контроля |
|
||||
| 8 | `0x0100` | `Stop` | аварийный останов |
|
||||
| 9 | `0x0200` | `Ready` | готовность, равна `!Stop` |
|
||||
| 10–13 | `0x0400…0x2000` | `Discr1…Discr4` | отдельные дискретные входы контроля |
|
||||
| 14 | `0x4000` | `Ignor` | игнорировать диагностику |
|
||||
| 15 | `0x8000` | `Bypas` | отключить канал |
|
||||
|
||||
`reset_errs()` сохраняет управляющие биты 13–15 маской `NOER = 0xE000`,
|
||||
добавляет вычисленные ошибки и каждый цикл формирует `Ready = !Stop`.
|
||||
|
||||
## 5. Уровни напряжения УМП
|
||||
|
||||
Проверка уровня выполняется только после расчёта общей амплитуды/RMS пары и
|
||||
только для нечётного канала пары (`Current_count():569–591`).
|
||||
|
||||
### Входное напряжение `Utr`
|
||||
|
||||
| Условие | Выдержка | Устанавливаемые биты |
|
||||
|---|---:|---|
|
||||
| `Level < 300 В` | около 3 с | `Out` (бит 3) + `Stop` (бит 8) |
|
||||
| `Level > 420 В` | без отдельной выдержки | `Hyper` (бит 5) + `Stop` (бит 8) |
|
||||
|
||||
Уставки находятся в `sens_lo_edge[0/1]` (Modbus `0x48/0x49`) и
|
||||
`sens_hi_edge[0/1]` (Modbus `0x30/0x31`). Значения выше — заводские; записью
|
||||
по Modbus или загрузкой EEPROM они могут быть изменены.
|
||||
|
||||
### Ток `Itr`
|
||||
|
||||
Для полноты связанной логики:
|
||||
|
||||
| Условие | Биты |
|
||||
|---|---|
|
||||
| `Level > 800 А` | `Over` (бит 4), предупреждение |
|
||||
| `Level > 900 А` | `Hyper` (бит 5) + `Stop` (бит 8) |
|
||||
|
||||
## 6. Контроль напряжений шкафа ВЭП (`Power_count`)
|
||||
|
||||
На плате шкафа каждый канал масштабируется напрямую:
|
||||
|
||||
```text
|
||||
Power = ADC_table[chan] * powK[sens_type[chan]]
|
||||
```
|
||||
|
||||
Коэффициенты заданы в `measure.c:52–65`: `0.127` для каналов 380 В и
|
||||
`0.0076` для низковольтных каналов.
|
||||
|
||||
Нижние уровни по умолчанию:
|
||||
|
||||
| Каналы | Контролируемое напряжение | Нижний уровень |
|
||||
|---:|---|---:|
|
||||
| 0, 1 | 380 В, фидеры 1 и 2 | 300 В |
|
||||
| 2, 3 | 31 В, фидеры 1 и 2 | 15 В |
|
||||
| 4, 5 | 31 В UC, фидеры 1 и 2 | 15 В |
|
||||
| 6 | 24 В ПУ | 20 В |
|
||||
| 7 | 27 В ФА | 22 В |
|
||||
| 8 | 24 В ПК | 20 В |
|
||||
| 9 | 15 В ДР | 10 В |
|
||||
| 10 | +24 В ДТ | 20 В |
|
||||
| 11 | −24 В ДТ | 20 В по модулю измеряемого значения |
|
||||
| 12 | 24 В ПМУ | 20 В |
|
||||
|
||||
Если `Power < sens_lo_edge[chan]`, ставится `Out` (бит 3). `Stop` (бит 8)
|
||||
ставится, когда `Out` уже установлен и у парного канала. Пары заданы как
|
||||
`0↔1`, `2↔3`, `4↔5`; одиночные каналы спарены сами с собой. Поэтому для
|
||||
двухфидерных источников аварийный останов означает пропадание обоих фидеров,
|
||||
а пропадание одного фидера даёт только `Out` в его диагностическом слове.
|
||||
|
||||
Проверка превышения верхней уставки в `Power_count():829–835` закомментирована
|
||||
и фактически не выполняется.
|
||||
|
||||
## 7. Особенности текущей реализации
|
||||
|
||||
1. На силовых блоках (`dsk_COMM`) четырём каналам назначается `Ignor` по
|
||||
абсолютным индексам `pow_addr…pow_addr+3` (`measure.c:359–365`), но проверка
|
||||
в `Current_count()` обращается к `sens_error[chan].Ignor`. Из-за разных
|
||||
индексов назначенный `Ignor` может не отключать фазовую диагностику.
|
||||
2. В `Current_count()` используется `pair = sens_pair[chan]`, тогда как для
|
||||
силового блока пары инициализируются по абсолютному индексу
|
||||
`sens_pair[pow_addr + chan]`. Для УМП, где `pow_addr == 0`, это работает как
|
||||
задумано. На силовом блоке индекс `pair` остаётся равен текущему `chan`, что
|
||||
может дублировать один фазовый RMS вместо чтения парного канала.
|
||||
3. Следствие двух ошибок индексации: на силовом блоке `Wry` может формироваться,
|
||||
хотя для канала выставлен `Ignor`, и опираться на неверно сопоставленные
|
||||
фазовые уровни. Эту часть логики нельзя считать надёжной без исправления или
|
||||
стендовой проверки.
|
||||
4. В выражении перекоса деление на `Max` записано раньше проверки
|
||||
`Max > Curr_Edge`. При `Max == 0` сначала вычисляется деление `0/0`.
|
||||
Безопаснее сначала проверять порог, затем выполнять деление.
|
||||
5. Все публикуемые значения и пороги хранятся в 16-битных регистрах как целые числа;
|
||||
дробная часть после вычислений отбрасывается.
|
||||
|
||||
## Краткий итог
|
||||
|
||||
- Фазы: два сигнала измеряются, третий восстанавливается как `-x1-x2`.
|
||||
- RMS каждой фазы: корень из экспоненциально усреднённого квадрата.
|
||||
- Общий RMS входа: амплитуда `im_calc()` после фильтра, делённая на `sqrt(2)`.
|
||||
- Обрыв/перекос одной фазы: `Wry`, бит 2; авария: `Stop`, бит 8.
|
||||
- Определение конкретной фазы: по минимальному из трёх RMS-регистров, отдельного
|
||||
фазового бита нет.
|
||||
- Низкое `Utr`: ниже 300 В около 3 секунд — `Out + Stop`.
|
||||
- Высокое `Utr`: выше 420 В — `Hyper + Stop`.
|
||||
@@ -1,289 +0,0 @@
|
||||
@page phase_voltage_weak_points Слабые места расчёта фаз и контроля напряжения
|
||||
|
||||
# Слабые места расчёта фаз и контроля напряжения
|
||||
|
||||
Документ относится к алгоритмам из `Source/Internal/measure.c`, структуре
|
||||
диагностики из `Source/Internal/Include/measure.h` и карте регистров
|
||||
`Doc/Balsam 167 data stru.xls`.
|
||||
|
||||
## Критические проблемы
|
||||
|
||||
### 1. Неверная индексация парного канала на силовом блоке
|
||||
|
||||
В `Current_count()` используется:
|
||||
|
||||
```c
|
||||
pair = sens_pair[chan];
|
||||
```
|
||||
|
||||
При этом пары каналов инициализируются по абсолютному адресу:
|
||||
|
||||
```c
|
||||
sens_pair[pow_addr+i] = pow_addr+(i^1);
|
||||
```
|
||||
|
||||
Для УМП `pow_addr == 0`, поэтому ошибка не проявляется. На силовом блоке
|
||||
`pow_addr != 0`, и `sens_pair[chan]` остаётся равным самому `chan`.
|
||||
|
||||
Последствия:
|
||||
|
||||
- вместо парного фазового RMS может использоваться текущий канал;
|
||||
- регистры `0x68…0x6D` могут содержать дублирующиеся значения;
|
||||
- расчёт максимальной фазы и диагностика `Wry` могут быть неверными.
|
||||
|
||||
Рекомендуемое исправление требует определить, в какой системе индексов должен
|
||||
работать `lev_count[]`. Вероятный вариант:
|
||||
|
||||
```c
|
||||
pair = sens_pair[sens] - pow_addr;
|
||||
```
|
||||
|
||||
Перед изменением необходимо проверить ожидаемую карту каналов на силовом блоке.
|
||||
|
||||
### 2. Бит `Ignor` проверяется по неверному индексу
|
||||
|
||||
В `Init_sensors_more()` бит устанавливается так:
|
||||
|
||||
```c
|
||||
Modbus[pow_addr+i].bit.bitE = 1;
|
||||
```
|
||||
|
||||
Но в `Current_count()` проверяется:
|
||||
|
||||
```c
|
||||
if (WAKE || sens_error[chan].bit.Ignor) goto fin;
|
||||
```
|
||||
|
||||
Следует проверять диагностическое слово текущего датчика:
|
||||
|
||||
```c
|
||||
if (WAKE || sens_error[sens].bit.Ignor) goto fin;
|
||||
```
|
||||
|
||||
Последствие текущего кода: `Wry` может формироваться для канала, который должен
|
||||
быть исключён из диагностики.
|
||||
|
||||
### 3. Деление на ноль в расчёте перекоса
|
||||
|
||||
Текущее условие:
|
||||
|
||||
```c
|
||||
((Numb - lev_count[chan]) / Numb > 0.3) && (Numb > Curr_Edge)
|
||||
```
|
||||
|
||||
Левая часть вычисляется раньше проверки `Numb > Curr_Edge`. При `Numb == 0`
|
||||
сначала выполняется деление `0/0`.
|
||||
|
||||
Безопасный порядок:
|
||||
|
||||
```c
|
||||
(Numb > Curr_Edge) &&
|
||||
(((Numb - lev_count[chan]) / Numb) > 0.3)
|
||||
```
|
||||
|
||||
Такое же изменение требуется для проверки `lev_count[thrd]`.
|
||||
|
||||
## Высокий приоритет
|
||||
|
||||
### 4. Нет независимых признаков обрыва фаз A, B и C
|
||||
|
||||
Прошивка формирует общий бит:
|
||||
|
||||
| Бит | Маска | Имя |
|
||||
|---:|---:|---|
|
||||
| 2 | `0x0004` | `Wry` |
|
||||
|
||||
Отдельных битов `PhaseA`, `PhaseB`, `PhaseC` нет. Конкретная фаза определяется
|
||||
косвенно по RMS-регистрам `0x68…0x6D`.
|
||||
|
||||
Фаза B физически не измеряется и восстанавливается:
|
||||
|
||||
```text
|
||||
B = -A - C
|
||||
```
|
||||
|
||||
Из-за этого повреждение фазы B не всегда можно однозначно отличить от
|
||||
изменения измеряемых фаз A и C.
|
||||
|
||||
Рекомендуется формировать отдельную маску состояния фаз, например:
|
||||
|
||||
| Бит | Назначение |
|
||||
|---:|---|
|
||||
| 0 | низкий RMS фазы A |
|
||||
| 1 | низкий RMS фазы B |
|
||||
| 2 | низкий RMS фазы C |
|
||||
| 3 | общий перекос фаз |
|
||||
|
||||
### 5. Выдержка восстановленной фазы примерно вдвое короче
|
||||
|
||||
Для восстановленной фазы используется `err_count[thrd]`. Одна и та же ячейка
|
||||
счётчика проверяется при обработке обоих каналов пары. Поэтому она может
|
||||
увеличиваться два раза за один цикл АЦП.
|
||||
|
||||
Ожидаемое время:
|
||||
|
||||
```text
|
||||
11250 / 3750 = 3 секунды
|
||||
```
|
||||
|
||||
Фактическое время для восстановленной фазы при двух вызовах за цикл:
|
||||
|
||||
```text
|
||||
11250 / (2 * 3750) ≈ 1,5 секунды
|
||||
```
|
||||
|
||||
Рекомендуется выполнять проверку всех трёх фаз один раз после обновления всей
|
||||
пары каналов.
|
||||
|
||||
### 6. Для входов U/I не формируется `Tear`
|
||||
|
||||
Бит `Tear` объявлен как бит 0 диагностического слова, но `Current_count()` его
|
||||
не устанавливает. Нет отдельной проверки АЦП на значения около 0 или 4095.
|
||||
|
||||
Последствия:
|
||||
|
||||
- обрыв или короткое замыкание измерительного тракта может выглядеть как
|
||||
обычное отсутствие напряжения;
|
||||
- невозможно отличить пропадание сети от неисправности самого датчика.
|
||||
|
||||
Рекомендуется добавить контроль сырого значения АЦП с выдержкой времени и
|
||||
отдельными порогами около нижней и верхней границ диапазона.
|
||||
|
||||
### 7. Подстройка нуля продолжается после запуска
|
||||
|
||||
Ноль обновляется при условии:
|
||||
|
||||
```c
|
||||
if (WAKE < (WAKE_TIME / 2)) Zero_lev[chan] = Zer;
|
||||
```
|
||||
|
||||
`WAKE` уменьшается до нуля. После запуска выражение `0 < WAKE_TIME/2` остаётся
|
||||
истинным, поэтому `Zero_lev` продолжает изменяться во время работы.
|
||||
|
||||
Риск: медленная постоянная составляющая или неисправность входа может частично
|
||||
компенсироваться алгоритмом нуля.
|
||||
|
||||
Если подстройка нужна только при запуске, условие должно ограничивать окно:
|
||||
|
||||
```c
|
||||
if ((WAKE > 0) && (WAKE < (WAKE_TIME / 2))) {
|
||||
Zero_lev[chan] = Zer;
|
||||
}
|
||||
```
|
||||
|
||||
Если непрерывная подстройка задумана, её следует явно документировать и
|
||||
ограничить допустимым диапазоном изменения.
|
||||
|
||||
## Средний приоритет
|
||||
|
||||
### 8. Жёсткая зона нечувствительности
|
||||
|
||||
Для напряжения применяется:
|
||||
|
||||
```c
|
||||
if (Amplitude < 20) Amplitude = 0;
|
||||
```
|
||||
|
||||
Для тока применяется порог 75. Реальный слабый сигнал ниже порога становится
|
||||
неотличим от полного отсутствия сигнала.
|
||||
|
||||
Рекомендуется использовать отдельные пороги включения и выключения
|
||||
(гистерезис), а также сохранить необрезанное диагностическое значение.
|
||||
|
||||
### 9. Несимметричная запись ошибок пары
|
||||
|
||||
Проверки общего уровня `Level` выполняются только при `!ist`, то есть в
|
||||
нечётном канале пары. Поэтому `Out` и `Hyper` записываются только в одно из двух
|
||||
диагностических слов.
|
||||
|
||||
Например, для напряжения УМП низкий общий уровень записывается в `0x01`, хотя
|
||||
само измерение относится ко всей трёхфазной системе.
|
||||
|
||||
Рекомендуется выделить отдельное диагностическое слово системы или явно
|
||||
дублировать общий признак в оба слова пары.
|
||||
|
||||
### 10. Контроль перенапряжения шкафа ВЭП отключён
|
||||
|
||||
В `Power_count()` проверка:
|
||||
|
||||
```c
|
||||
if (Power > sens_hi_edge[chan])
|
||||
```
|
||||
|
||||
закомментирована. В рабочем коде контролируется только падение напряжения.
|
||||
Неисправность с повышением напряжения не создаёт `Hyper` и `Stop`.
|
||||
|
||||
Перед включением проверки необходимо задать и проверить верхние уставки для
|
||||
всех типов источников питания.
|
||||
|
||||
### 11. Недостаточный гистерезис порогов
|
||||
|
||||
Верхний порог `Utr > 420 В` проверяется непосредственно, без отдельного
|
||||
счётчика и без порога возврата. При шуме около 420 В диагностический бит может
|
||||
часто переключаться.
|
||||
|
||||
Для нижнего порога используется реверсивный счётчик, но состояние также не
|
||||
имеет явно заданных разных порогов срабатывания и возврата.
|
||||
|
||||
Рекомендуется добавить:
|
||||
|
||||
- выдержку времени для перенапряжения;
|
||||
- разные пороги срабатывания и возврата;
|
||||
- насыщение и явный сброс диагностических счётчиков.
|
||||
|
||||
### 12. Потеря дробной части RMS
|
||||
|
||||
`lev_count[]` и Modbus-регистры имеют целочисленный тип. Результат `sqrt()`
|
||||
сохраняется с отбрасыванием дробной части.
|
||||
|
||||
Для текущих порогов в сотнях вольт это не критично, но ухудшает точность
|
||||
индикации и поведение около границы. При необходимости можно передавать
|
||||
значения в десятых долях единицы.
|
||||
|
||||
## Дополнительные риски
|
||||
|
||||
### Разная задержка аварии у парных источников
|
||||
|
||||
В `Power_count()` бит `Stop` устанавливается, если `Out` уже присутствует у
|
||||
парного канала. Из-за последовательной обработки второй канал пары может
|
||||
получить `Stop` раньше первого. Первый получит его только при следующем опросе.
|
||||
|
||||
### Одиночный источник спарен сам с собой
|
||||
|
||||
Для непарных источников `sens_pair[chan] == chan`. После первого обнаружения
|
||||
`Out` бит `Stop` появится при следующем вызове, когда будет прочитано собственное
|
||||
предыдущее состояние `Out`. Это неочевидная зависимость от предыдущего цикла.
|
||||
|
||||
### Уставки доступны для записи без локальной проверки диапазона
|
||||
|
||||
Команда Modbus записывает переданное значение непосредственно в массив
|
||||
регистров. В расчёте не видно проверки допустимого диапазона порогов. Ошибочная
|
||||
уставка может полностью отключить контроль или вызвать постоянную аварию.
|
||||
|
||||
## Рекомендуемый порядок исправлений
|
||||
|
||||
1. Исправить индексацию `sens_pair` и `sens_error[].Ignor`.
|
||||
2. Переставить проверку `Numb > Curr_Edge` перед делением.
|
||||
3. Перенести расчёт и диагностику трёх фаз в один вызов на пару каналов.
|
||||
4. Добавить отдельные признаки состояния фаз A/B/C.
|
||||
5. Добавить диагностику предельных значений АЦП (`Tear`).
|
||||
6. Определить требуемый режим подстройки нуля и ограничить его.
|
||||
7. Добавить выдержку и гистерезис верхнего/нижнего напряжения.
|
||||
8. Проверить все изменения стендовыми тестами: нормальная сеть, обрыв каждой
|
||||
фазы, перекос, пропадание обоих фидеров, пониженное и повышенное напряжение.
|
||||
|
||||
## Минимальный набор тестов
|
||||
|
||||
| Тест | Ожидаемый результат |
|
||||
|---|---|
|
||||
| Номинальное трёхфазное напряжение | `Wry=0`, `Out=0`, `Hyper=0`, `Stop=0` |
|
||||
| Обрыв измеряемой фазы A | снижение RMS A, отдельный признак A, затем `Stop` |
|
||||
| Обрыв измеряемой фазы C | снижение RMS C, отдельный признак C, затем `Stop` |
|
||||
| Нарушение восстановленной фазы B | снижение вычисленного RMS B без двойной скорости счётчика |
|
||||
| Перекос ровно 30% | проверка граничного условия `>` |
|
||||
| `Max = 0` | отсутствие деления на ноль |
|
||||
| `Utr < 300 В` | `Out`, после выдержки `Stop` |
|
||||
| `Utr > 420 В` | `Hyper`, после заданной выдержки `Stop` |
|
||||
| АЦП около 0 или 4095 | `Tear`, отличие от пропадания сети |
|
||||
| Канал с `Ignor=1` | отсутствие новых автоматических ошибок этого канала |
|
||||
| Отключённый канал `Bypas=1` | нулевые данные, сохранён только `Bypas` |
|
||||
@@ -1,16 +0,0 @@
|
||||
# Документация Balsam 167
|
||||
|
||||
Запустите `build.bat` из этого каталога. Скрипт всегда собирает обзорную
|
||||
страницу в `build/index.html`. Скрипт использует переносимый Doxygen из
|
||||
`.tools/doxygen-1.18.0` либо `doxygen.exe` из `PATH` и создаёт API-справочник
|
||||
в `build/api/html/index.html`. Без Doxygen по
|
||||
этому адресу создаётся поясняющая страница, поэтому ссылка из обзора не
|
||||
остаётся битой.
|
||||
|
||||
Исходные файлы старого проекта сохранены в CP1251. `Doxyfile` явно задаёт эту
|
||||
кодировку для `*.c` и `*.h`, а новые файлы документации хранятся в UTF-8.
|
||||
|
||||
```bat
|
||||
cd Doc
|
||||
build.bat
|
||||
```
|
||||
@@ -1,53 +0,0 @@
|
||||
# Сборка проекта в Code Composer Studio 12
|
||||
|
||||
Проект поддерживает обе IDE параллельно:
|
||||
|
||||
- CCS 3 использует корневой файл `UKSSTMS320F28335.pjt`;
|
||||
- CCS 12 использует проект из каталога `UKSSTMS320F28335`.
|
||||
|
||||
Файлы CCS 3 не изменялись. Объектные файлы и итоговые образы двух систем
|
||||
сборки разнесены по разным каталогам и не перезаписывают друг друга.
|
||||
|
||||
## Импорт
|
||||
|
||||
1. Откройте **File → Import → Code Composer Studio → CCS Projects**.
|
||||
2. В **Select search-directory** укажите каталог репозитория.
|
||||
3. Выберите проект **UKSSTMS320F28335** и нажмите **Finish**.
|
||||
4. Выберите конфигурацию **Debug** или **Release** и выполните **Build Project**.
|
||||
|
||||
Проект настроен для `TMS320F28335`, COFF ABI и C2000 Compiler
|
||||
`22.6.0.LTS`, входящего в CCS 12.3.
|
||||
|
||||
## Результаты сборки
|
||||
|
||||
- CCS 3 продолжает использовать прежние каталоги `Debug`, `Release` и `Bin`.
|
||||
- CCS 12 Debug создаёт `.out`, `.hex`, `.bin` и `.map` в `Bin/CCS12`.
|
||||
- CCS 12 Release создаёт `UKSSTMS320F28335_Release.out` и
|
||||
`UKSSTMS320F28335_Release.map` в `Bin/CCS12`.
|
||||
|
||||
## Публикация прошивки
|
||||
|
||||
`publish_firmware.bat` создаёт Gitea Release, загружает образ, вычисляет
|
||||
SHA-256 и обновляет `firmware.releases` общего `update.json`. Перед запуском
|
||||
сохраните вход Gitea в SETGUI. Альтернативно задайте `GITEA_TOKEN` либо пару
|
||||
`GITEA_USER`/`GITEA_PASSWORD` в окружении CCS.
|
||||
|
||||
Пример отдельного шага после сборки CCS:
|
||||
|
||||
```bat
|
||||
"${SRC_ROOT}\publish_firmware.bat" "${SRC_ROOT}\Bin\CCS12\UKSSTMS320F28335.bin" "1.0.0" "Описание изменений" "tms"
|
||||
```
|
||||
|
||||
Путь к образу зависит от конфигурации CCS; первым параметром должен быть
|
||||
фактический полный путь созданного `.bin` или `.hex`. Версия задаётся в формате
|
||||
`MAJOR.MINOR.PATCH`. Повторный запуск той же версии заменяет asset и запись
|
||||
каталога, не создавая дубликат.
|
||||
|
||||
Для проверки файла и доступа к Gitea без публикации добавьте пятый параметр:
|
||||
|
||||
```bat
|
||||
"${SRC_ROOT}\publish_firmware.bat" "${SRC_ROOT}\Bin\CCS12\UKSSTMS320F28335.bin" "1.0.0" "Проверка" "tms" "check"
|
||||
```
|
||||
|
||||
Все пути к исходникам заданы относительно каталога проекта через `SRC_ROOT`;
|
||||
перенос репозитория в другой каталог не требует изменения настроек.
|
||||
97
Doc/RS232_FIFO.md
Normal file
97
Doc/RS232_FIFO.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# RS232 FIFO для ПМ35 / TMS320F28335
|
||||
|
||||
Ветка `pm35-uart-fifo`. FIFO включён **только SCI-A / COM_1 / RS232**.
|
||||
SCI-B / COM_2 / RS485 сохраняет прежние настройки и обработчики без FIFO.
|
||||
Скорости портов не менялись: RS232 115200; RS485 — прежние 57600/115200.
|
||||
|
||||
`Source/Internal/Include/RS485.h`: `RS232_USE_FIFO=1` по умолчанию.
|
||||
Для сборки прежнего пути передачи определить `RS232_USE_FIFO=0`.
|
||||
|
||||
## Работа
|
||||
|
||||
- TX заполняет до 16 байт, пополняет при остатке не более 8.
|
||||
- После постановки последнего байта порог переключается на 0. Следующее
|
||||
прерывание завершает передачу только после пустого FIFO и `TXEMPTY`.
|
||||
Ожидание внутри завершающего ISR ограничено остатком последнего символа;
|
||||
передача всего FIFO внутри ISR не ожидается.
|
||||
- Первый блок ставится в FIFO до разрешения TX-прерывания, под короткой
|
||||
IRQ-блокировкой с восстановлением прежнего состояния.
|
||||
- Убраны программные задержки перед передачей именно для SCI-A. Данные
|
||||
`BM_CHAR32` и упакованный поток `BM_PACKED` сохраняют прежний порядок байтов.
|
||||
Нулевая длина не обращается к указателю и не включает передатчик.
|
||||
- RX читает накопленные байты из FIFO. Порог 1 сохраняет немедленный приём
|
||||
коротких команд и остатка блока. `SCIRXBUF` читается один раз вместе с FE/PE.
|
||||
- Ошибка/переполнение аннулирует пакет и `BS_LoadOK`, очищает FIFO. После
|
||||
3–4 мс тишины обработчик таймера 1 мс возвращает SCI-A к ожиданию адреса.
|
||||
Продолжающийся повреждённый поток продлевает ожидание. CMD_LOAD после
|
||||
ошибки требует нового CMD_INITLOAD. Расчёт паузы предназначен для 115200.
|
||||
- Счётчики отладчика: `rs_a.fifo_rx_errors`, `rs_a.fifo_overflows`.
|
||||
|
||||
## Расчёт скорости и диагностика приёма
|
||||
|
||||
FIFO остаётся включённым. Для SCI используется формула TI SPRUI07:
|
||||
`baud = LSPCLK / (8 * (BRR + 1))`. Функция `RS_SetLineSpeed` округляет
|
||||
отношение `LSPCLK / (8 * baud)` и вычитает единицу перед записью BRR.
|
||||
При LSPCLK 60 МГц и заданных 115200 бод регистры должны содержать
|
||||
`SCIHBAUD=0`, `SCILBAUD=64` (`0x40`). Реальная скорость — 115384,6 бод,
|
||||
отклонение +0,16 %. Прежнее значение 65 давало 113636,4 бод; сама по себе
|
||||
эта разница не доказывает причину наблюдавшегося отказа на плате.
|
||||
|
||||
GPIO28 настраивается как асинхронный вход SCI-A с подтяжкой к уровню покоя.
|
||||
Прерывание RXERROR разрешается во время приёма: BREAK при пустом FIFO
|
||||
не может вызвать прерывание по порогу RXFFIL. Во время передачи оно
|
||||
отключается вместе с RX FIFO, чтобы ошибка RX не сбрасывала активный TX.
|
||||
|
||||
Для просмотра в CCS добавлены поля в RAM:
|
||||
|
||||
| Поле `rs_a` | Назначение |
|
||||
|---|---|
|
||||
| `fifo_rx_bytes` | Количество прочитанных из FIFO байтов, включая повреждённые |
|
||||
| `fifo_rx_last_word` | Последнее слово SCIRXBUF; данные в битах 7:0, FE/PE в битах 15:14 |
|
||||
| `fifo_rx_last_status` | SCIRXST последней ошибки до сброса; BREAK/FE/OE/PE в битах 5/4/3/2 |
|
||||
| `fifo_rx_last_error_word` | Повреждённое слово FE/PE либо ноль при общей ошибке до чтения FIFO |
|
||||
|
||||
Смотрите эти поля и отдельные регистры управления. Чтение SCIRXBUF в Watch
|
||||
изменяет состояние приёмника; для просмотра данных TI предусматривает
|
||||
SCIRXEMU. Описание регистров: [TI SPRUI07](https://www.ti.com/lit/ug/sprui07/sprui07.pdf).
|
||||
|
||||
Это UART-оптимизация. Она не меняет команды/формат логгера УМП и не подключает
|
||||
экспериментальный GAS-логгер. Размеры блоков чтения УМП остаются прежними.
|
||||
|
||||
## Проверка
|
||||
|
||||
```powershell
|
||||
python tests/rs232_fifo/run_test.py --cc C:/msys64/mingw64/bin/gcc.exe
|
||||
```
|
||||
|
||||
Тест извлекает рабочие функции из `RS485.c`; заменяется только поведение
|
||||
аппаратных регистров, ожидание продвижения UART и модель 16-битного char C28x.
|
||||
Проверены TX-длины 0/1/2/7/8/15/16/17/31/120/253/400, упакованный блок 8194,
|
||||
приём короткого/разделённого пакета и LOAD 8194, FIFO overflow, FE/PE,
|
||||
восстановление после тишины, остаток сдвигового регистра и независимость SCI-B.
|
||||
|
||||
Полная сборка TI C2000 22.6.0.LTS:
|
||||
|
||||
```powershell
|
||||
./build_logger.ps1 -OptimizeForSize -Rs232Fifo 1 `
|
||||
-OutputDirectory "$PWD/Bin/Rs232FifoTest" -ImageName PM35_167_rs232_fifo
|
||||
./build_logger.ps1 -OptimizeForSize -Rs232Fifo 0 `
|
||||
-OutputDirectory "$PWD/Bin/Rs232NoFifoTest" -ImageName PM35_167_rs232_no_fifo
|
||||
```
|
||||
|
||||
| Образ | Размер | Запас до параметров EEPROM |
|
||||
|---|---:|---:|
|
||||
| FIFO, `-O2 --opt_for_speed=0` | 32158 байт | 350 байт |
|
||||
| Без FIFO, те же параметры оптимизации | 31234 байта | 1274 байта |
|
||||
|
||||
Оба BIN прошли проверку структуры SCI8 и лимита 32508 байт существующим
|
||||
`check_firmware.ps1`. Старые `-O1 --opt_for_speed=3` с FIFO превышают лимит;
|
||||
для этого варианта обязателен `-OptimizeForSize`. Проверка запрещает выпуск
|
||||
слишком большого BIN и не даёт затронуть сохранённые параметры.
|
||||
Оптимизация размера применяется ко всей сборке, поэтому временные
|
||||
характеристики приложения нужно проверить на стенде.
|
||||
|
||||
На плату образы не загружены. Пока подтверждены сборка и тесты модели;
|
||||
ускорение чтения логгера и устойчивость физического RS232 не измерены.
|
||||
Для стенда сравнить одно и то же чтение архива на двух образах, проверить
|
||||
CMD_LOAD/UPLOAD и параллельный RS485. FIFO не увеличивает baud rate.
|
||||
112
Doc/SOURCE_GUIDE.md
Normal file
112
Doc/SOURCE_GUIDE.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Назначение исходников Бальзам-167
|
||||
|
||||
Все редактируемые исходники C/H, ASM, CMD и Python используют UTF-8 без BOM.
|
||||
Русский текст найден рядом с каждой строкой исходников из Git-индекса, однако
|
||||
часть пояснений шаблонная и требует содержательной доработки. Существующие уведомления TI
|
||||
и сведения о поставляемых файлах сохранены. Таблица формального покрытия,
|
||||
ограничения проверки и результаты проверки качества находятся в [COMMENT_AUDIT.md](COMMENT_AUDIT.md) и
|
||||
../tests/comments/run_test.py.
|
||||
|
||||
## Порядок работы
|
||||
|
||||
main.c сначала настраивает системные такты, PIE, внешнюю RAM, адрес платы,
|
||||
CAN и оба SCI. Затем запускает EEPROM, очищает RAM журнала, явно инициализирует
|
||||
регистратор и автомат LOAD, настраивает Timer1 и разрешает прерывания.
|
||||
Параметры читаются из EEPROM; для LOAD Setup_DAC_time применяет длительность
|
||||
нарастания тока и проверяет сохранённый тайм-аут CAN. Главный цикл обслуживает
|
||||
команды, сохранение параметров, события регистратора и передачу служебного CAN.
|
||||
|
||||
Timer1 задаёт основную частоту READY_FREQ=1000 Гц. Для измерительной платы
|
||||
обработчик находится в measure.c, для пульта — в pulto.c. Автомат нагрузки
|
||||
выполняется в Timer1: он владеет START/STOP/разрешением и обновлением тока ЦАП.
|
||||
Главный цикл не включает нагрузку поверх состояния защиты. Timer2 продвигает
|
||||
автомат EEPROM; ожидание SPI не выполняется внутри длительной блокировки IRQ.
|
||||
|
||||
## Внутренние модули
|
||||
|
||||
| Файл | Назначение и важные ограничения |
|
||||
| --- | --- |
|
||||
| main.c | Порядок запуска, общий цикл, команды загрузчика и Modbus; COM_1 115200 с FIFO. |
|
||||
| ADC.c | Настройка каналов АЦП, обработка преобразований и обновление фильтров. |
|
||||
| measure.c | Типы датчиков, температурные/токовые/мощностные расчёты, диагностика, периодический такт. |
|
||||
| filter_bat2.c | Накопительный фильтр; история и сумма обновляются вместе с новым отсчётом. |
|
||||
| DAC.c | Передача слов ЦАП и автомат нагрузки: свежесть CAN, напряжение, STOP и настраиваемый лимит пусков. |
|
||||
| ecan.c | Штатные CAN-кадры и отдельный служебный обмен УМП/GAS; ISR принимает, главный цикл передаёт ответ. |
|
||||
| RS485.c | SCI-A/SCI-B, разбор кадров и упаковка слов; FIFO используется только первым портом. |
|
||||
| message.c | FC03/FC06, маршрутизация УМП/GAS, заводские и сохраняемые параметры. |
|
||||
| gas167.c | Карта 167/v1; проверка всего диапазона до чтения; ограничение записи такое же, как у обычного Modbus. |
|
||||
| log_to_mem.c | Два банка RAM регистратора, события START/STOP/CAN/RS, замороженный архив и чтение через УМП. |
|
||||
| shared_ump.c | Подключение общего протокола и паспорта из соседнего репозитория; логика общей библиотеки здесь не дублируется. |
|
||||
| spise2p.c | SPI EEPROM: команда, адрес, порции данных, границы страниц и ожидание окончания записи. |
|
||||
| bios.c | Последовательный загрузчик, команды памяти и EXTEND; адрес EEPROM проверяется отдельно от RAM. |
|
||||
| cntrl_adr.c | Установка собственного/универсального адреса устройства. |
|
||||
| peripher.c | Аппаратные перемычки, тип платы, кнопки, выбор канала и служебные GPIO. |
|
||||
| kanal.c | Последовательная передача битов индикации выбранного канала. |
|
||||
| pulto.c | Периодический обработчик и обмен пульта. |
|
||||
| crc16.c | Таблицы и алгоритмы CRC для используемых пакетов. |
|
||||
| tools.c | Внешняя шина XINTF Zone7 и задержки в микросекундах. |
|
||||
|
||||
## Заголовки проекта
|
||||
|
||||
package.h определяет аппаратные адреса и псевдонимы modbus. Стартовый ток
|
||||
находится в 0x50, конечный — в 0x51. Сохраняемый LOAD_CAN_TIMEOUT занимает 0x52:
|
||||
разрешено 1..60000 мс; заводское значение 2000 мс устанавливается Default_params.
|
||||
Setup_DAC_time исправляет недопустимое сохранённое значение на 600 мс.
|
||||
Load_runner дополнительно использует 600 мс для локальной страховки при
|
||||
недопустимом значении. LOAD_STATUS=0x7C доступен только для чтения.
|
||||
LOAD_MAX_ATTEMPTS=0x7D — сохраняемый лимит 1..65535 пусков, по умолчанию 5;
|
||||
ноль при записи отклоняется. Текущий счётчик остаётся в слове 5 блока
|
||||
FC03(0x1300, 8), а подготовка тактов ЦАП не обнуляет настроенный лимит.
|
||||
|
||||
eeprom_config.h выбирает физическую микросхему при сборке. spise2p.h задаёт
|
||||
ширину адреса, длину страницы и типы задания SPI. gas167.h описывает границы
|
||||
профиля и контракт снимка. log_to_mem.h задаёт формат точек и ёмкость банков.
|
||||
RS485.h описывает состояние портов, буферы, FIFO и тайм-ауты.
|
||||
measure.h хранит частоты, типы датчиков и битовые состояния диагностики.
|
||||
caliber.h содержит заводские калибровочные значения. GPIO_table.h и peripher.h
|
||||
задают аппаратные сигналы. Остальные заголовки объявляют интерфейсы одноимённых
|
||||
модулей.
|
||||
|
||||
## Слово C28x и физические байты
|
||||
|
||||
На C28x int и char имеют ширину 16 бит. Адреса технологических регистров и GAS
|
||||
считаются словами. Размеры EEPROM, загрузочного SCI8 BIN и октеты RTU считаются
|
||||
8-битными байтами. Поэтому преобразование адреса EEPROM в байты выполняется
|
||||
явно. Хостовые проверки используют uint16_t и модель аппаратных регистров,
|
||||
чтобы обычные 8-битные char/32-битные int ПК не меняли смысл пакетов.
|
||||
|
||||
F28335.cmd размещает код в RAM и экспортирует абсолютные символы границ EEPROM.
|
||||
EEPROM не является памятью, доступной ядру напрямую: ROM загружает образ по SPI
|
||||
в RAM. Увеличение EEPROM не расширяет .text или RAM регистратора. Секция .logg
|
||||
остаётся в Zone7A. Подробные пределы: [EEPROM_LAYOUT.md](EEPROM_LAYOUT.md).
|
||||
|
||||
## Поставляемые TI файлы
|
||||
|
||||
DSP2833x_headers/include содержит структуры аппаратных регистров и их битовые
|
||||
поля. GlobalVariableDefs.c размещает структуры в именованных секциях; файлы
|
||||
Headers_BIOS.cmd/Headers_nonBIOS.cmd связывают их с аппаратными адресами.
|
||||
Рабочая сборка использует nonBIOS.
|
||||
|
||||
DSP2833x_common содержит начальную настройку тактов, таймеров, АЦП, PIE и XINTF,
|
||||
таблицы векторов и программные приоритеты ISR. В SWPrioritizedIsrLevels.h
|
||||
приоритет 0 исключает источник, меньшее ненулевое значение означает более
|
||||
высокий приоритет; MINT и MG вычисляют соответствующие маски.
|
||||
ADC_cal.asm и usDelay.asm обеспечивают фабричную калибровку/задержку C28x.
|
||||
Комментарии описывают исходный порядок инструкций; код поставляемых модулей
|
||||
не изменён.
|
||||
|
||||
## Настройки и результаты сборки
|
||||
|
||||
.project регистрирует связанные исходники и заголовки, .cproject задаёт Debug,
|
||||
Release, флаги, пути и pre/post-build. .ccsproject описывает устройство и
|
||||
инструментарий, .settings/*.prefs — настройки Eclipse/CCS. Эти XML и properties
|
||||
содержат русские комментарии без изменения значений опций.
|
||||
|
||||
firmware_identity.json — входные product/target. Паспорт BIN и
|
||||
profile-comparison.json — структурированные данные; комментарии JSON
|
||||
недопустимы. Их поля описаны в FIRMWARE_IDENTITY.md и GAS_167_M95M02.md.
|
||||
.bin/.hex/.out/.map, EXE, LIB и XLS — данные или результаты сторонних инструментов;
|
||||
их нельзя снабжать комментариями как исходный C-код. .paf2/.sbl и корневые
|
||||
.pjt/.lkf относятся к старым данным IDE/сборки. postBuildStep_Debug.old и fixya.bat
|
||||
сохранены как старые служебные сценарии; действующие шаги CCS определены в
|
||||
.cproject и соседних шаблонах.
|
||||
269
Doc/UMP_LOGGER.md
Normal file
269
Doc/UMP_LOGGER.md
Normal file
@@ -0,0 +1,269 @@
|
||||
# Логгер запуска и отключения УМП: прошивка Бальзам 167 и SetGUI
|
||||
|
||||
## Назначение и работа оператора
|
||||
|
||||
В SetGUI открыть ПМ35 → Настройки, выбрать COM, скорость (обычно 115200)
|
||||
и адрес контроллера (для рассматриваемого УМП — 5). Затем открыть вкладку **Логгер УМП**.
|
||||
Подключение используется существующее: прямой RS232/RS485 Modbus RTU.
|
||||
CAN-команды от управляющего контроллера фиксируются самой платой нагрузки.
|
||||
|
||||
1. **Начать запись** включает только регистратор, не пуск УМП.
|
||||
Период снимков по умолчанию 20 мс, диапазон 1–1000 мс.
|
||||
2. Левые флажки выбирают отображаемые сигналы. Аналоги рисуются линиями,
|
||||
дискретные сигналы — отдельными дорожками. Выбор не меняет состав
|
||||
записи на плате: скрытую кривую можно включить после захвата.
|
||||
3. **Онлайн** подключает график к уже идущей записи, в том числе после
|
||||
восстановления соединения. Тайм-аут не посылает плате команду останова.
|
||||
4. Фактическое включение STOP при переходе работающей нагрузки к снятому
|
||||
разрешению запускает фиксацию отключения. Постинтервал содержит 10%
|
||||
банка — 76 последующих точек, включая события CAN и I/O. Повторные
|
||||
STOP при уже остановленной нагрузке архив не заменяют.
|
||||
5. **Прочитать отключение** загружает архив, не останавливая запись на плате.
|
||||
На время чтения и просмотра архива онлайн-график приостанавливается;
|
||||
вернуться к нему можно кнопкой **Онлайн**.
|
||||
6. **Остановить и прочитать** останавливает только регистратор и читает
|
||||
текущий банк. При этом существующий архив отключения остаётся доступным.
|
||||
7. **Сохранить CSV** сохраняет поля загруженного/онлайн-буфера, выбранные
|
||||
правыми флажками «Запись в лог», а также время и код события. Выбор
|
||||
не зависит от видимости кривой. Множители графика не изменяют значения CSV.
|
||||
**Буфер GUI** задаёт число последних точек: от 800 до 100000, по умолчанию
|
||||
10000. Это отдельный буфер ПК, не ёмкость банка платы и не непрерывная
|
||||
запись на диск. **Сохранить график из GUI** позволяет выгрузить накопленную
|
||||
онлайн-историю после чтения архива платы.
|
||||
|
||||
При разрыве связи журнал на плате продолжает работать. Архив хранится в ОЗУ
|
||||
до следующей фиксации отключения либо перезагрузки/пропадания питания.
|
||||
EEPROM не используется: под отключением в этой задаче понимается команда
|
||||
управляющего контроллера, а не потеря питания.
|
||||
|
||||
## Память и точность
|
||||
|
||||
Использована существующая секция `.logg` по адресу 0x200000: 64000
|
||||
16-битных слов. Два банка по 760 записей × 12 слов занимают 18240 слов.
|
||||
Ёмкость в точках сохранена; сокращённая запись освобождает оставшуюся часть
|
||||
выделенного массива. При триггере сохраняются до 683 предыдущих точек,
|
||||
событие отключения и 76 последующих точек. При периоде 20 мс и отсутствии
|
||||
дополнительных событий постинтервал составляет примерно 1,52 секунды.
|
||||
События CAN и дискретов сокращают его временную длительность, но не число
|
||||
зарезервированных точек. Архив после заполнения постинтервала фиксируется,
|
||||
а запись продолжается в другом банке.
|
||||
|
||||
Время — 32-битный счётчик миллисекунд записи. Он идёт только при включённом
|
||||
регистраторе и не является абсолютным временем. События в одном тике имеют
|
||||
одинаковую отметку; порядок сохраняется порядком записей. На перезапуске
|
||||
регистратора счётчик продолжает прежнюю шкалу, при перезагрузке платы — 0.
|
||||
|
||||
Онлайн-опрос возвращает до десяти последних записей каждые 40 мс. Он не гарантирует
|
||||
передачу каждого события при высоком CAN-трафике, медленном UART или паузах
|
||||
GUI. Номера записей позволяют убрать дубликаты и явно показать пропуски.
|
||||
Полный сохранившийся фрагмент следует читать кнопкой архива. Частота 20 мс
|
||||
выбрана с учётом размера кадра; на низких скоростях нужна большая пауза
|
||||
снимков и подходящий тайм-аут RS.
|
||||
|
||||
Все писатели и чтение одного Modbus-блока используют короткие критические
|
||||
секции с восстановлением прежнего состояния IRQ. Внутри нет ожидания UART,
|
||||
EEPROM, выделения памяти или копирования целого банка. Реальную задержку
|
||||
прерываний и длительность критических секций нужно измерить на F28335.
|
||||
|
||||
## Состав записи v4: 12 слов
|
||||
|
||||
Из прошивки и списка графиков удалены 32 неотмеченных канала с двух
|
||||
скриншотов: остатки импульса/инициализации, код и калибровки ЦАП,
|
||||
измерения, ошибки, сырые CAN-слова/счётчики, маска команд, параметры
|
||||
разгона и каналы АЦП. Рабочие калибровочные регистры и сами измерения
|
||||
для управления платой продолжают использоваться по назначению.
|
||||
|
||||
В интерфейсе осталось 15 каналов:
|
||||
|
||||
| Группа | Каналы |
|
||||
|---|---|
|
||||
| Ток и уставки | Расчётное задание тока, начальная уставка, конечная уставка — мА |
|
||||
| Напряжения | ЗПТ1: U1 + U2 (ПМ67, рег. 306); ЗПТ2: U3 + U4 (ПМ67, рег. 9) — В |
|
||||
| Команды | Пуск УМП, сброс УМП |
|
||||
| Входы | OMEGA, Start_1, Res_in |
|
||||
| Выходы | START_DPTB, STOP_DPTB, RES_OUT_2 |
|
||||
| События | Событие отключения, усечение постинтервала |
|
||||
|
||||
«Усечение постинтервала» оставлено для чтения прежних журналов; текущая
|
||||
прошивка v4 бит 9 события не устанавливает. Расчётное задание тока —
|
||||
команда аналоговому выходу, а не измеренный физический ток петли.
|
||||
Для отображения физических единиц у пяти аналоговых каналов нужен
|
||||
множитель ×1,000. Сохранённые пользовательские множители восстанавливаются
|
||||
при запуске GUI; например, ×94,000 меняет только высоту кривой, не ток платы.
|
||||
|
||||
| Слова | Данные | Единицы/смысл |
|
||||
|---|---|---|
|
||||
| 0–1 | Время, младшее/старшее слово | мс записи |
|
||||
| 2 | Событие | 1 — период, 2 — CAN, 3 — I/O, 4 — RS, 5 — конец постинтервала |
|
||||
| 2, бит 8 | Событие отключения | флаг поверх причины |
|
||||
| 2, бит 9 | Усечение постинтервала | совместимость со старыми журналами; в текущем v4 равен 0 |
|
||||
| 3 | Команды пуска и сброса | только биты 7 и 6; отдельной кривой маски команд больше нет |
|
||||
| 4 | Входы OMEGA, Start_1, Res_in | биты 0, 1, 2 |
|
||||
| 5 | Выходы START_DPTB, STOP_DPTB, RES_OUT_2 | биты 0, 1, 2 |
|
||||
| 6 | Расчётное задание тока | 0,1 мА; GUI/CSV показывает мА |
|
||||
| 7–8 | Начальная/конечная уставки | целые мА |
|
||||
| 9–10 | ЗПТ1/ЗПТ2 | беззнаковые слова, масштаб 1 В/ед. |
|
||||
| 11 | Нулевой резерв | чётная длина для передачи CAN парами слов |
|
||||
|
||||
Напряжения принимаются из технологических CAN-кадров с нулевыми индексами
|
||||
305 и 8. Учитываются все три позиции и биты маски 0x8000/0x4000/0x2000.
|
||||
Они хранятся отдельно от массива modbus[0..127], обновляются и при выключенном
|
||||
логгере. Запись содержит последние принятые значения; до первого приёма — 0.
|
||||
При потере связи остаётся последнее значение: отдельного признака свежести нет.
|
||||
Клиент не преобразует напряжения в знаковые измерения. Свежесть выбранного
|
||||
ЗПТ и защита роста напряжения описаны отдельно в `UMP_VOLTAGE_PROTECTION.md`.
|
||||
При штатных 6 мА пуск сначала передаёт это задание и получает 3 секунды
|
||||
на рост ЗПТ до 30 В; после этого работает прежняя защита и лимит попыток.
|
||||
|
||||
## Протокол расширения Modbus
|
||||
|
||||
Технологические адреса 0..127 сохранены. Новая область использует полный
|
||||
16-битный адрес; исходная реализация игнорировала старший байт.
|
||||
Сначала GUI читает 16 слов 0x1000 и проверяет сигнатуру, версию, размер записи
|
||||
и тип платы. До успешной проверки расширенные записи запрещены.
|
||||
Обычный ответ расширения не содержит исторических хвостовых нулей.
|
||||
Между ответом и следующим запросом GUI выдерживает паузу RTU.
|
||||
|
||||
FC03, 0x1000, 16 слов:
|
||||
|
||||
| Смещение | Значение |
|
||||
|---|---|
|
||||
| 0,1 | 0x554D, версия 4 |
|
||||
| 2,3 | состояние и число записей выбранного источника |
|
||||
| 4,5 | 12 слов в записи, 760 записей в банке |
|
||||
| 6 | период периодических снимков, мс |
|
||||
| 7,8 | счётчик времени, младшее/старшее слово |
|
||||
| 9,10 | Desk (требуется 6 / dsk_LOAD), Mode |
|
||||
| 11 | частота временной базы, 1000 Гц |
|
||||
| 12 | поколение архива, mod 65536 |
|
||||
| 13 | число записей архива |
|
||||
| 14 | верхняя оценка оставшихся миллисекунд: число точек × период, до 65535 |
|
||||
| 15 | состояние текущего регистратора независимо от выбора источника |
|
||||
|
||||
Состояния: 0 — ещё не запущен, 1 — запись, 3 — остановлен/архив.
|
||||
|
||||
FC06:
|
||||
- 0x1000: 1 — новый текущий журнал, 0 — остановить его;
|
||||
- 0x1001: период 1..1000, менять только при остановленном журнале;
|
||||
- 0x1002: хронологический индекс первой записи окна 0..759;
|
||||
- 0x1003: источник окна, 0 — текущий остановленный банк, 1 — архив отключения.
|
||||
|
||||
FC03, 0x1010, до 120 слов: окно от установленного индекса; для целых записей v4 читать 12, 24, …, 120 слов.
|
||||
CAN допускает кратные 12 до 120 слов и прежние размеры v2/v3; RTU допускает 1..120 слов.
|
||||
Чтение текущего банка этим окном во время записи не выдаёт изменяющиеся
|
||||
данные. GUI сначала останавливает его; архив можно читать при работающем
|
||||
текущем банке. После всех блоков GUI повторно проверяет поколение архива;
|
||||
при замене во время чтения результат не подменяет предыдущий график.
|
||||
|
||||
FC03, 0x1100, ровно 124 слова: онлайн-блок. Слова 0,1 — 32-битный номер
|
||||
первой записи, 2 — число записей 0..10, 3 — поколение архива, далее до десяти
|
||||
записей по 12 слов. Неиспользованные слова равны нулю. Окно онлайн не
|
||||
зависит от курсора/выбора архива. Разделение 0x1010 и 0x1100 предотвращает
|
||||
пересечение двух окон.
|
||||
|
||||
Недопустимые диапазоны и значения возвращают исключения Modbus 2/3.
|
||||
CRC и разбор стандартного ответа GUI используют существующее общее ядро.
|
||||
SetGUI распознаёт v2 (40 слов, 800 записей), v3 (42 слова, 760 записей)
|
||||
и v4 (12 слов, 760 записей). Для v2 ЗПТ недоступны (NaN). Старые архивы
|
||||
декодируются по прежним индексам, но удалённые каналы в панели и CSV больше
|
||||
не создаются. Валидаторы RTU/CAN поддерживают компактные размеры записи.
|
||||
Исходники протокола подключаются к прошивке из templates/c/set-protocol.
|
||||
|
||||
## Проверка и запуск
|
||||
|
||||
Текущая проверенная сборка с пуском 3 секунды и сокращённым журналом:
|
||||
`Bin/StartupWait3s/UKSSTMS320F28335_startup_3s_378e06a+.bin`.
|
||||
Размер — 32180 байт; для AT25256B допустимы 32508 байт, запас — 328 байт.
|
||||
Рядом находятся OUT, MAP, манифест и SHA-256. Для чтения v4 используйте
|
||||
обновлённый SETGUI и перезапустите приложение после изменения исходников.
|
||||
|
||||
|
||||
Воспроизводимая сборка из корня проекта: `python Bin/StartupWait3s/rebuild.py`.
|
||||
Скрипт использует установленный TI C2000 22.6, ABI COFF, `-O2`,
|
||||
`--opt_for_speed=0` и секции функций. Все модули пересобираются в отдельный
|
||||
каталог; до формирования готового BIN проверяются профиль AT25256B,
|
||||
граница 32508 байт, блоки RAM и точка входа SCI8. Сохраняются паспорт и SHA-256.
|
||||
Из CCS используется та же карта памяти и настройки проекта. В include-path
|
||||
нужны каталоги общего `c/set-protocol`, его порта `ports/tms320f28335`
|
||||
и сгенерированного паспорта. Обе используемые копии библиотеки поддерживают v4:
|
||||
`../newProject/templates` и `../newProject/SETGUI/third_party/templates`.
|
||||
|
||||
При загрузке `main()` вызывает `ump_log_init()` до включения прерываний.
|
||||
Это обязательно для TI COFF: стартовый код не обнуляет неинициализированные
|
||||
переменные `.ebss`. Без явной инициализации состояние, счётчики и номера
|
||||
банков могут содержать остаточные значения RAM. Очистка `.logg` функцией
|
||||
`clear_mem()` эти переменные не затрагивает. Повторный запуск записи через
|
||||
FC06 не вызывает загрузочную инициализацию и сохраняет архив и шкалу времени.
|
||||
Регрессия `python tests/ump_logger/run_init_test.py` (GCC в PATH) проверяет
|
||||
запуск с ненулевой RAM и отрицательный контроль без инициализации;
|
||||
внешняя библиотека `templates/c/set-protocol` для этого теста не нужна.
|
||||
|
||||
Изменены исходники прошивки и SetGUI; новый образ собран в отдельном каталоге.
|
||||
Проверены TI-компиляция, линковка и формат SCI8 для AT25256B. Физические
|
||||
уровни GPIO и ток после загрузки образа проверяются на плате.
|
||||
|
||||
Автотест C в tests/ump_logger компилирует непосредственно log_to_mem.c
|
||||
с подменой GPIO/IRQ. Проверяет кольцо, граничные адреса, обе команды
|
||||
отключения, защиту триггера от переполнения, переключение банков,
|
||||
сохранность архива во время дальнейшей записи, токовое задание и оба ЗПТ.
|
||||
Это проверка алгоритма на компьютере, не проверка таймингов и 16-битной ABI
|
||||
TI. Отдельно выполнена синтаксическая проверка изменённых C-файлов Clang
|
||||
с исходными заголовками и декларациями TI-интринсиков.
|
||||
|
||||
Проверенный набор SetGUI: `tests/test_ump_logger.py`,
|
||||
`tests/test_ump_logger_can.py`, `tests/test_ump_voltage_protection.py` — 93 теста.
|
||||
Они проверяют единицы мА, битовые сигналы, временные метки, несовместимую
|
||||
прошивку, порядок команд, архив при активной записи, замену поколения,
|
||||
дубликаты/пропуски онлайн, потерю связи и флажки графиков.
|
||||
|
||||
Проверка на стенде: включить запись → подать CAN-пуск → изменить уставку →
|
||||
подать откл. → дождаться заполнения 76 точек постинтервала → прочитать
|
||||
архив и сверить задание, внешний ток и дискретные уровни; затем повторить
|
||||
с разрывом RS.
|
||||
Период 1 мс проверить отдельно под максимальной CAN-нагрузкой.
|
||||
|
||||
Исторически для сборки 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`.
|
||||
После перепрошивки требуется проверка на плате; проверка на ПК её не заменяет.
|
||||
|
||||
## Исправление ожидания EEPROM при запуске через CCS
|
||||
|
||||
В сборке CCS с O3 подтверждён перенос записей полей `readData` и `writeData`
|
||||
за цикл ожидания `spiSe2pFree()`. Указатель `msgPtr` и флаг `csr` были volatile,
|
||||
но содержимое дескриптора — нет. Timer2 получал запрос с незаполненными
|
||||
адресом, длиной и указателем буфера, поэтому `Load_params()` мог не завершиться,
|
||||
хотя UART уже принял команду. Все три поля `SE2P_DATA` теперь volatile.
|
||||
В дизассемблере исправленного OUT записи всех полей предшествуют флагу запроса.
|
||||
|
||||
Для проверки старой AT25256B подготовлен
|
||||
`Bin/EepromPublishFix/UKSSTMS320F28335_eeprom_fix.out` и одноимённый BIN с build_id.
|
||||
Сборка `python Bin/EepromPublishFix/rebuild.py` явно задаёт `EEPROM_M95M02=0`
|
||||
и O3; размер проверенного BIN — 32074 байта, запас до параметров — 434 байта.
|
||||
Проверка порядка инструкций:
|
||||
`python tests/eeprom_profiles/check_publication.py Bin/EepromPublishFix/disassembly.txt`.
|
||||
На листинге прежнего OUT эта проверка падает, на исправленном проходит для чтения
|
||||
и записи. Пройдены модели обоих профилей EEPROM и UART. Запуск на плате
|
||||
после загрузки исправленного OUT ещё требует подтверждения.
|
||||
146
Doc/UMP_VOLTAGE_PROTECTION.md
Normal file
146
Doc/UMP_VOLTAGE_PROTECTION.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Контроль роста ЗПТ при пуске УМП
|
||||
|
||||
УМП с адресом 5 (`Mode=5`) контролирует ЗПТ1 — CAN-индекс 305
|
||||
(регистр ПМ67 306). УМП 6 контролирует ЗПТ2 — CAN-индекс 8
|
||||
(регистр ПМ67 9). Масштаб исходного слова: 1 единица = 1 В.
|
||||
|
||||
## Условия и последовательность
|
||||
|
||||
Начальный безопасный код задания соответствует 4 мА по `DAC_min()`.
|
||||
Рост напряжения считается достаточным при ЗПТ **не меньше 30 В**.
|
||||
Проверяется расчётное задание ЦАП, а не измеренный выходной ток.
|
||||
Ручная калибровка не подменяет задание при активной команде пуска
|
||||
или удерживаемом STOP.
|
||||
|
||||
Если очередной шаг рампы требует **строго больше 6 мА**, а свежее
|
||||
CAN-напряжение меньше 30 В и в текущей попытке ещё не достигало порога,
|
||||
в ЦАП сначала передаётся задание **6 мА**. Положение рампы удерживается.
|
||||
УМП получает **3 секунды** на рост ЗПТ до 30 В: это 600 отправленных
|
||||
токовых кадров при 200 Гц. Отсчёт начинается с первой отправки 6 мА;
|
||||
команда инициализации ЦАП не расходует выдержку. До достижения порога
|
||||
даже начальная уставка выше 6 мА ограничивается этим током. Уставки
|
||||
ниже 6 мА сначала проходят обычный разгон до указанной границы.
|
||||
|
||||
При свежем ЗПТ **не меньше 30 В** разгон продолжается с сохранённого
|
||||
положения без нового START. После подтверждённого роста напряжения
|
||||
рабочая защита снова действует сразу: шаг выше 6 мА при ЗПТ ниже 30 В
|
||||
не передаётся в ЦАП и не получает повторной стартовой выдержки.
|
||||
|
||||
Если за 3 секунды свежего обмена ЗПТ не достигло 30 В либо напряжение
|
||||
упало после успешного пуска, вместо повышенного задания выполняется:
|
||||
|
||||
1. Снимается START, включается STOP, снимается разрешение RES_OUT_2.
|
||||
2. Положение рампы обнуляется, передаётся код 4 мА без подмены калибровкой.
|
||||
3. STOP остаётся включённым **1000 мс от момента его установки**.
|
||||
4. Когда код 4 мА отправлен, прошла секунда и есть свежее ЗПТ,
|
||||
снимается STOP, сразу выставляется START, затем разрешение.
|
||||
5. Новая рампа начинается с нулевого положения с исходными уставками
|
||||
`DAC_go`/`DAC_stop`; новая попытка получает собственные 3 секунды
|
||||
ожидания при 6 мА, если ЗПТ ещё не достигло 30 В.
|
||||
|
||||
Первый START входит в настраиваемый лимит регистра **0x7D**: по умолчанию
|
||||
**всего 5 попыток**, не 5 дополнительных. Через FC06 или штатный CAN можно
|
||||
записать **1…65535**; ноль отклоняется без изменения предыдущей настройки.
|
||||
После последней разрешённой неудачи удерживаются STOP и 4 мА, разрешение
|
||||
снято, дополнительный START не выдаётся. Ошибка снимается командой `cUMPstart=0`;
|
||||
затем можно подать новый пуск. Изменение лимита само по себе не снимает
|
||||
ошибку и не выдаёт START. Уменьшение лимита во время STOP проверяется перед
|
||||
следующей попыткой. Команда RESET имеет приоритет перед START.
|
||||
|
||||
Для задания пяти пусков используйте `FC06(0x007D, 5)` либо `FC06(0x507D, 5)`
|
||||
в GAS-профиле M95M02. Чтение `0x7D` возвращает лимит; текущий счётчик остаётся
|
||||
в слове 5 диагностического блока `FC03(0x1300, 8)`. Настройка сохраняется
|
||||
штатной командой **Save**. Ноль из старой EEPROM заменяется на 5 при запуске;
|
||||
ненулевое сохранённое значение трактуется как лимит.
|
||||
Отпускание RESET с оставшимся START=1 само по себе не перезапускает УМП.
|
||||
|
||||
Выходами и рампой управляет один обработчик Timer1 (1 мс). Основной цикл
|
||||
больше не формирует независимые фронты START/STOP. Расчёт/отправка ЦАП
|
||||
остались с периодом 5 мс. Импульс START длится до 1000 мс, но защита
|
||||
или RESET прекращают его раньше.
|
||||
|
||||
## Отсутствие CAN
|
||||
|
||||
Заводской таймаут из `Default_params` — **2000 мс**, диапазон настройки **1…60000 мс**. Если сохранённый параметр недопустим, `Setup_DAC_time` применяет **600 мс**; такой же запасной таймаут используется локально в `Load_runner`.
|
||||
Свежесть подтверждается только получением нужного ЗПТ в полном
|
||||
технологическом CAN-кадре с соответствующим битом маски. Другое
|
||||
напряжение, сервисные запросы, команды и произвольные CAN-пакеты
|
||||
таймаут не сбрасывают. До первого значения напряжение считается неизвестным.
|
||||
|
||||
При таймауте работающая рампа удерживает последнее положение и отправленный
|
||||
код. Стартовая выдержка при 6 мА также приостанавливается и возобновляется
|
||||
после нового выбранного ЗПТ. Попытка не считается неудачной, STOP по одному
|
||||
таймауту не включается.
|
||||
После свежего ЗПТ рост продолжается; если оно меньше 30 В при задании
|
||||
больше 6 мА, выполняется защитный STOP. Если обмен исчез во время
|
||||
сброса, STOP держится и после секунды — до свежего напряжения.
|
||||
Первый пуск также ждёт свежего значения.
|
||||
|
||||
Настройка хранится в технологическом регистре `0x52` платы нагрузки.
|
||||
Значение 0 в старом EEPROM заменяется на 600 мс при запуске.
|
||||
Для сохранения изменения используйте штатную команду сохранения параметров.
|
||||
|
||||
## Диагностика и эмуляция в GUI
|
||||
|
||||
Во вкладке **Логгер УМП** добавлены:
|
||||
|
||||
- **Защита ЗПТ: прочитать** — состояние защиты, число попыток, напряжение.
|
||||
- **Эмуляция: нет CAN** — получение своего ЗПТ игнорируется платой;
|
||||
после заданного таймаута рампа удерживается.
|
||||
- **Эмуляция: ЗПТ не растёт** — для проверки защиты используется 0 В,
|
||||
хотя настоящие кадры продолжают поступать. Реальные напряжения в
|
||||
журнале не подменяются. Этот режим действительно вызывает STOP/пуски.
|
||||
- **Задать таймаут** — запись значения в плату с обязательным чтением обратно.
|
||||
|
||||
Кнопки эмуляции включаются после проверки сигнатуры прошивки. Их положение
|
||||
меняется только после подтверждённого чтения обратно. Два режима можно
|
||||
включать независимо; при отсутствии свежести проверка роста приостановлена.
|
||||
Эмуляция живёт только в RAM, не сохраняется в EEPROM и выключена после
|
||||
перезагрузки. GUI показывает активную эмуляцию отдельно от реального ЗПТ.
|
||||
|
||||
При онлайн-чтении GUI опрашивает защиту каждые 500 мс и показывает
|
||||
**«НЕИСПРАВНОСТЬ: ЗПТ не достигло 30 В за 5 попыток»**.
|
||||
Старые прошивки без блока защиты продолжают обычное онлайн-чтение;
|
||||
эмуляция для них недоступна.
|
||||
|
||||
Технологический регистр `0x7C` — статус только для чтения;
|
||||
`0x7D` — записываемый сохраняемый лимит попыток. Оба включены в быстрый CAN-цикл.
|
||||
Статус: бит 0 — ошибка исчерпания настроенного лимита, бит 1 — нет свежего ЗПТ,
|
||||
бит 2 — сброс перед повтором, бит 3 — работа рампы,
|
||||
биты 4/5 — активная эмуляция отсутствия CAN/роста ЗПТ.
|
||||
|
||||
Локальный блок RTU и служебного CAN: FC03 `0x1300`, ровно 8 слов:
|
||||
|
||||
| Смещение | Значение |
|
||||
|---|---|
|
||||
| 0 | Сигнатура `0x5550` |
|
||||
| 1 | Версия 1 |
|
||||
| 2 | Эмуляция: бит 0 — нет CAN, бит 1 — нет роста |
|
||||
| 3 | Таймаут, мс |
|
||||
| 4 | Статус защиты |
|
||||
| 5 | Число попыток |
|
||||
| 6 | Последнее реальное CAN-напряжение, В |
|
||||
| 7 | Возраст значения, мс; 65535 до первого значения |
|
||||
|
||||
FC06 допускает запись только `0x1302` (0…3) и `0x1303` (1…60000).
|
||||
Диагностический обмен не обновляет возраст технологического напряжения.
|
||||
|
||||
## Проверки
|
||||
|
||||
`python tests/load_control/run_test.py` компилирует непосредственно
|
||||
`DAC.c` с подменой GPIO/IRQ. Проверяются выбор ЗПТ, маски CAN, таймаут,
|
||||
удержание кода, граница 30 В, порядок STOP/START, точная пауза 1000 мс,
|
||||
лимиты 1, 2, 5, 7 и 65535 пусков, изменение лимита во время STOP, RESET, эмуляция и невозможность подмены 4 мА калибровкой.
|
||||
Стартовые регрессии для адресов 5 и 6 проверяют отправку 6 мА вместо
|
||||
мгновенного сброса, границу выдержки 3000 мс, успешный рост ЗПТ во время
|
||||
ожидания, немедленную защиту после успешного пуска, повышенную начальную
|
||||
уставку, паузу CAN и пропуск отсчёта при инициализации ЦАП.
|
||||
|
||||
GUI: `tests/test_ump_voltage_protection.py` в SETGUI плюс регрессии логгера.
|
||||
Сборка: `build_logger.ps1 -OutputDirectory Bin/VoltageProtection
|
||||
-ImageName UKSSTMS320F28335_voltage_protection`. Размер проверяется до
|
||||
публикации BIN; для AT25256B предел — 32508 байт. В режиме оптимизации
|
||||
функции разнесены по секциям, чтобы линкер удалял неиспользуемые функции.
|
||||
|
||||
Это проверки на компьютере. Физический ток 4 мА, уровни разрешения,
|
||||
STOP и интервал 1 с нужно проверить на стенде с установленной прошивкой.
|
||||
File diff suppressed because one or more lines are too long
723
Doc/api.dox
723
Doc/api.dox
@@ -1,723 +0,0 @@
|
||||
/**
|
||||
@file api.dox
|
||||
@brief Русскоязычные Doxygen-описания интерфейсов Balsam 167.
|
||||
|
||||
@defgroup measurement Измерения и диагностика
|
||||
@brief АЦП, фильтрация, пересчёт каналов и формирование аварий.
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void setup_adc(void)
|
||||
@brief Настраивает ADC и быстрый обработчик преобразований.
|
||||
@details Конфигурирует последовательность каналов и параметры накопления,
|
||||
используемые измерительным контуром. Вызывается один раз при старте для всех
|
||||
ролей, кроме пульта EPLT.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void adc_isr(void)
|
||||
@brief Обрабатывает очередную последовательность преобразований ADC.
|
||||
@details Обновляет сырые выборки и фильтры; выполняется в контексте прерывания.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Init_sensors(void)
|
||||
@brief Выполняет первичную инициализацию измерительных каналов.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Init_sensors_more(void)
|
||||
@brief Применяет параметры изделия после загрузки сохранённых настроек.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Init_packMask(void)
|
||||
@brief Формирует маски публикуемых CAN-регистров для каждой шины.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Temper_count(int chan, int own)
|
||||
@brief Пересчитывает температурный канал и обновляет его диагностику.
|
||||
@param chan Индекс базового канала в общей модели измерений.
|
||||
@param own Признак локального либо внешнего источника температуры.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Current_count(int chan)
|
||||
@brief Вычисляет ток по паре измерительных каналов и формирует ошибки.
|
||||
@param chan Индекс канала тока.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Power_count(int chan)
|
||||
@brief Вычисляет напряжение/мощность для заданного канала.
|
||||
@param chan Индекс обрабатываемого канала.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void calc_sensor_koef(void)
|
||||
@brief Пересчитывает коэффициенты датчиков по калибровочным точкам.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void calc_volta_edge(void)
|
||||
@brief Пересчитывает пороги контроля напряжения из текущих настроек.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Is_Voltage_Hi(void)
|
||||
@brief Проверяет превышение напряжения и обновляет общий признак аварии.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void cpu_timer1_isr_SENS(void)
|
||||
@brief Периодический обработчик измерительной платы.
|
||||
@details Планирует выбор каналов, пересчёт величин, диагностику, мигание и
|
||||
циклическую передачу. Выполняется в контексте прерывания CPU Timer1.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn int er_anal(int term, unsigned int *count, long edge, int pre)
|
||||
@brief Реализует выдержку времени для появления и снятия диагностического условия.
|
||||
@param term Текущее логическое состояние диагностического условия.
|
||||
@param count Счётчик длительности условия; изменяется функцией.
|
||||
@param edge Порог счётчика, после которого условие подтверждается.
|
||||
@param pre Состояние ошибки на предыдущем шаге.
|
||||
@return Ненулевое значение, когда ошибка считается активной.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@struct FILTERBAT
|
||||
@brief Состояние рекурсивного фильтра второго порядка.
|
||||
@details Содержит три коэффициента, три входные и три выходные выборки.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn float filterbat(FILTERBAT *b, float InpVarCurr)
|
||||
@brief Пропускает одну выборку через фильтр Баттерворта.
|
||||
@param b Экземпляр фильтра с коэффициентами и историей.
|
||||
@param InpVarCurr Новая входная выборка.
|
||||
@return Отфильтрованное значение.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@struct ERROR
|
||||
@brief Шестнадцатибитное слово состояния измерительного канала.
|
||||
@details Объединяет признаки обрыва, неправильного сигнала, выхода за пределы,
|
||||
перегрева, блокировки, готовности, дискретных входов, игнорирования и bypass.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@struct FLAG
|
||||
@brief Общие признаки ошибки, аварии, нагрева и теста ламп.
|
||||
*/
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup communication Последовательный обмен и сообщения
|
||||
@brief Два канала SCI, физический режим RS-485 и прикладные команды.
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@struct RS_DATA
|
||||
@brief Контекст одного SCI/RS-485 канала.
|
||||
@details Хранит регистры SCI, указатели RX/TX, буферы, длины сообщений,
|
||||
тайм-ауты, адреса и параметры линии. Глобальные экземпляры: `rs_a` и `rs_b`.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void create_uart_vars(char size_cmd15_set)
|
||||
@brief Инициализирует контексты двух UART и таблицу длин команд.
|
||||
@param size_cmd15_set Размер payload команды 15 для текущего приложения.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void setup_uart(char commnumber, unsigned long speed_baud)
|
||||
@brief Настраивает SCI-A или SCI-B и соответствующие обработчики PIE.
|
||||
@param commnumber Номер порта: `COM_1` либо `COM_2`.
|
||||
@param speed_baud Скорость линии, бит/с.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void RS_SetLineMode(RS_DATA *rs_arr, int bit, char parity, int stop)
|
||||
@brief Задаёт длину слова, чётность и число стоп-битов.
|
||||
@param rs_arr Контекст канала.
|
||||
@param bit Число информационных битов.
|
||||
@param parity Режим контроля чётности.
|
||||
@param stop Режим стоп-битов.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void RS_SetLineSpeed(RS_DATA *rs_arr, unsigned long speed)
|
||||
@brief Изменяет скорость выбранного последовательного канала.
|
||||
@param rs_arr Контекст канала.
|
||||
@param speed Новая скорость, бит/с.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void RS_SetBitMode(RS_DATA *rs_arr, int n)
|
||||
@brief Выбирает байтовый либо упакованный режим данных SCI.
|
||||
@param rs_arr Контекст канала.
|
||||
@param n Требуемый режим представления элементов.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn int RS_Send(RS_DATA *rs_arr, unsigned int *pBuf, unsigned long len)
|
||||
@brief Запускает неблокирующую передачу массива слов.
|
||||
@param rs_arr Контекст канала.
|
||||
@param pBuf Буфер передаваемых слов.
|
||||
@param len Число слов.
|
||||
@return Признак успешного запуска передачи.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn int RS_BSend(RS_DATA *rs_arr, unsigned int *pBuf, unsigned long len)
|
||||
@brief Запускает передачу байтов, хранящихся в 16-битных ячейках C28x.
|
||||
@param rs_arr Контекст канала.
|
||||
@param pBuf Буфер данных.
|
||||
@param len Число восьмибитных элементов.
|
||||
@return Признак успешного запуска передачи.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn int get_command(RS_DATA *rs_arr)
|
||||
@brief Проверяет принятый кадр и извлекает код команды.
|
||||
@param rs_arr Контекст канала с принятым пакетом.
|
||||
@return Код команды либо `-1`, если полного корректного кадра нет.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void RSA_RX_Handler(void)
|
||||
@brief Обработчик приёма SCI-A, делегирующий работу общему RX-автомату.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void RSA_TX_Handler(void)
|
||||
@brief Обработчик передачи SCI-A.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void RSB_RX_Handler(void)
|
||||
@brief Обработчик приёма SCI-B, делегирующий работу общему RX-автомату.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void RSB_TX_Handler(void)
|
||||
@brief Обработчик передачи SCI-B.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void clear_timer_rs_live(RS_DATA *rs_arr)
|
||||
@brief Сбрасывает счётчик контроля активности последовательного канала.
|
||||
@param rs_arr Контекст канала.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void test_rs_live(RS_DATA *rs_arr)
|
||||
@brief Проверяет тайм-аут активности последовательного канала.
|
||||
@param rs_arr Контекст канала.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void ReceiveCommandModbus3(RS_DATA *rs_arr)
|
||||
@brief Обрабатывает Modbus function 3 — чтение регистров.
|
||||
@param rs_arr Канал, на котором принята команда.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void ReceiveCommandModbus6(RS_DATA *rs_arr)
|
||||
@brief Обрабатывает Modbus function 6 — запись одного регистра.
|
||||
@param rs_arr Канал, на котором принята команда.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void SendCommandModbus4(RS_DATA *rs_arr)
|
||||
@brief Формирует запрос function 4 к внешнему устройству OWEN.
|
||||
@param rs_arr Канал связи с устройством.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void ReceiveAnswerModbus4(RS_DATA *rs_arr)
|
||||
@brief Разбирает ответ OWEN на запрос входных регистров.
|
||||
@param rs_arr Канал, на котором принят ответ.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@struct CMD_TO_TMS
|
||||
@brief Формат короткой команды контроллеру.
|
||||
@details Содержит адрес, номер команды, восемь байтов данных, CRC и добавочный байт.
|
||||
*/
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup can_bus CAN
|
||||
@brief Инициализация eCAN-A, приём команд и публикация регистров.
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void InitCan(int Port, int DevNum)
|
||||
@brief Настраивает CAN-контроллер и почтовые ящики.
|
||||
@param Port Зарезервированный номер CAN-порта; текущая плата использует порт 0.
|
||||
@param DevNum Адрес/режим устройства, участвующий в конфигурации идентификаторов.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void CAN_send(int Port, int data[], int Addr)
|
||||
@brief Передаёт группу из трёх регистров общей модели.
|
||||
@param Port Номер CAN-порта.
|
||||
@param data Начало массива регистров.
|
||||
@param Addr Адрес первого публикуемого регистра.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void CANa_handler(void)
|
||||
@brief Обработчик приёма eCAN-A; переносит данные mailbox в прикладную модель.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void CANa_reset_err(void)
|
||||
@brief Обрабатывает состояние ошибки eCAN-A и восстанавливает обмен.
|
||||
*/
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup storage Параметры, EEPROM и журнал
|
||||
@brief Долговременное хранение конфигурации и диагностических выборок.
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@struct SE2P_DATA
|
||||
@brief Описание операции с последовательной EEPROM.
|
||||
@details Содержит указатель данных, размер операции и адрес EEPROM.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@struct SPISE2P_DRV
|
||||
@brief Состояние и виртуальные методы драйвера SPI EEPROM.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void InitSeeprom(void)
|
||||
@brief Настраивает SPI-A, GPIO chip-select и Timer2 для EEPROM.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Seeprom_write(unsigned int adres, unsigned int buf[], unsigned int size)
|
||||
@brief Синхронно записывает блок 16-битных слов во внешнюю EEPROM.
|
||||
@param adres Адрес слова в EEPROM.
|
||||
@param buf Буфер исходных слов.
|
||||
@param size Количество записываемых слов.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Seeprom_read(unsigned int adres, unsigned int buf[], unsigned int size)
|
||||
@brief Синхронно читает блок 16-битных слов из внешней EEPROM.
|
||||
@param adres Адрес слова в EEPROM.
|
||||
@param buf Буфер результата.
|
||||
@param size Количество читаемых слов.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Default_params(void)
|
||||
@brief Загружает заводские уставки и калибровочные значения в RAM.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Load_params(void)
|
||||
@brief Читает настройки из EEPROM и проверяет их целостность.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Save_params(void)
|
||||
@brief Записывает текущие настройки и контрольную сумму в EEPROM.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@struct LOG
|
||||
@brief Границы и текущий указатель циклического журнала во внешней памяти.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void clear_mem(void)
|
||||
@brief Инициализирует область журнала и очищает её рабочее состояние.
|
||||
*/
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup hardware Аппаратные интерфейсы
|
||||
@brief GPIO, режим платы, ЦАП и последовательная индикация.
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void get_Mode(void)
|
||||
@brief Читает конфигурационные входы и определяет `Mode` и `Desk`.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void get_Buttons(void)
|
||||
@brief Опросивает дискретные входы и обновляет биты кнопок/команд.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void setup_leds_line(void)
|
||||
@brief Временно настраивает линии двух диагностических светодиодов.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void unsetup_leds_line(void)
|
||||
@brief Возвращает мультиплексируемые линии из режима стартовой индикации.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void select_tpl_canal(int n_tpl)
|
||||
@brief Выбирает один канал мультиплексора термопар.
|
||||
@param n_tpl Номер канала термопары.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void select_tpl_255(void)
|
||||
@brief Переводит адресные линии мультиплексора в неактивное состояние.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Setup_DAC_time(void)
|
||||
@brief Вычисляет временные параметры программного обслуживания ЦАП.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Init_DAC(void)
|
||||
@brief Инициализирует GPIO последовательного интерфейса ЦАП.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Anal_output(long vrot, long maxx)
|
||||
@brief Выдаёт нормированное значение на аналоговый выход.
|
||||
@param vrot Требуемое значение.
|
||||
@param maxx Верхняя граница шкалы входного значения.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Load_runner(void)
|
||||
@brief Обновляет выход нагрузки и формирует старт/стоп импульсы.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void kanal_Send(int adr, long dat, int dot)
|
||||
@brief Передаёт число на внешний семисегментный индикатор.
|
||||
@param adr Адрес индикаторного канала.
|
||||
@param dat Отображаемое целое значение.
|
||||
@param dot Позиция десятичной точки.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void cpu_timer1_isr_PULT(void)
|
||||
@brief Периодический обработчик пульта и внешней индикации.
|
||||
*/
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup boot_protocol BIOS-протокол
|
||||
@brief Команды удалённого чтения, записи, запуска и прошивки контроллера.
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void Answer(RS_DATA *rs_arr, int n)
|
||||
@brief Формирует и отправляет ответ BIOS-протокола.
|
||||
@param rs_arr Канал ответа.
|
||||
@param n Число элементов данных ответа.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void init(RS_DATA *rs_arr)
|
||||
@brief Возвращает идентификацию работающего приложения.
|
||||
@param rs_arr Канал запроса.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void initload(RS_DATA *rs_arr)
|
||||
@brief Инициализирует сеанс загрузки программы.
|
||||
@param rs_arr Канал запроса.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void load(RS_DATA *rs_arr)
|
||||
@brief Принимает очередной блок загружаемой программы.
|
||||
@param rs_arr Канал запроса.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void run(RS_DATA *rs_arr)
|
||||
@brief Завершает загрузку и передаёт управление программе.
|
||||
@param rs_arr Канал запроса.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void peek(RS_DATA *rs_arr)
|
||||
@brief Читает участок адресного пространства контроллера.
|
||||
@param rs_arr Канал запроса и ответа.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void poke(RS_DATA *rs_arr)
|
||||
@brief Записывает данные в адресное пространство контроллера.
|
||||
@param rs_arr Канал запроса.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void upload(RS_DATA *rs_arr)
|
||||
@brief Передаёт блок памяти контроллера ведущему устройству.
|
||||
@param rs_arr Канал запроса и ответа.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void tflash(RS_DATA *rs_arr)
|
||||
@brief Выполняет команду обслуживания Flash TMS320F28335.
|
||||
@param rs_arr Канал запроса и ответа.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void xflash(RS_DATA *rs_arr)
|
||||
@brief Обрабатывает совместимую команду доступа к внешней Flash/памяти.
|
||||
@param rs_arr Канал запроса и ответа.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void extendbios(RS_DATA *rs_arr)
|
||||
@brief Обрабатывает расширенную команду BIOS-протокола.
|
||||
@param rs_arr Канал запроса и ответа.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn unsigned int read_memory(unsigned long addr)
|
||||
@brief Читает 16-битное слово по физическому адресу.
|
||||
@param addr Адрес в пространстве данных C28x.
|
||||
@return Прочитанное слово.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void write_memory(unsigned long addr, unsigned int data)
|
||||
@brief Записывает 16-битное слово по физическому адресу.
|
||||
@param addr Адрес в пространстве данных C28x.
|
||||
@param data Записываемое слово.
|
||||
*/
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup utilities Служебные функции
|
||||
@brief CRC, внешняя зона памяти и точные задержки.
|
||||
@{
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn unsigned int get_crc_ccitt(unsigned int crc, unsigned int *buf, unsigned long size)
|
||||
@brief Вычисляет CRC-CCITT для массива восьмибитных значений в словах C28x.
|
||||
@param crc Начальное значение CRC.
|
||||
@param buf Буфер входных значений.
|
||||
@param size Число элементов.
|
||||
@return Итоговое значение CRC.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn unsigned int get_crc_16(unsigned int crc, unsigned int *buf, unsigned long size)
|
||||
@brief Вычисляет основной вариант CRC-16 проекта.
|
||||
@param crc Начальное значение CRC.
|
||||
@param buf Буфер входных значений.
|
||||
@param size Число элементов.
|
||||
@return Итоговое значение CRC.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn unsigned int get_crc_16b(unsigned int crc, unsigned int *buf, unsigned long size)
|
||||
@brief Вычисляет CRC-16 с альтернативным порядком байтов.
|
||||
@param crc Начальное значение CRC.
|
||||
@param buf Буфер входных значений.
|
||||
@param size Число элементов.
|
||||
@return Итоговое значение CRC.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn int get_crc16(unsigned int *buf, int size)
|
||||
@brief Вычисляет контрольное слово пакета прикладного протокола.
|
||||
@param buf Буфер пакета.
|
||||
@param size Число обрабатываемых элементов.
|
||||
@return Шестнадцатибитное контрольное значение.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void init_zone7(void)
|
||||
@brief Настраивает зону XINTF7 для внешней памяти и периферии.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void pause_us(unsigned long t)
|
||||
@brief Выполняет программную задержку.
|
||||
@param t Длительность в микросекундах согласно частоте проекта.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void set_cntrl_addr(int cntrl_addr, int cntrl_addr_for_all)
|
||||
@brief Устанавливает индивидуальный и групповой адреса контроллера.
|
||||
@param cntrl_addr Индивидуальный адрес устройства.
|
||||
@param cntrl_addr_for_all Групповой широковещательный адрес.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void SPISE2P_DRV_init(SPISE2P_DRV *eeprom)
|
||||
@brief Инициализирует низкоуровневый автомат SPI EEPROM.
|
||||
@param eeprom Экземпляр драйвера.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void SPISE2P_DRV_tick(SPISE2P_DRV *eeprom)
|
||||
@brief Выполняет один шаг неблокирующего автомата EEPROM.
|
||||
@param eeprom Экземпляр драйвера.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void SPISE2P_DRV_csset(void)
|
||||
@brief Деактивирует линию chip-select EEPROM.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void SPISE2P_DRV_csclr(void)
|
||||
@brief Активирует линию chip-select EEPROM.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn unsigned int spiSe2pFree(SPISE2P_DRV *se2p)
|
||||
@brief Проверяет готовность автомата EEPROM к новой операции.
|
||||
@param se2p Экземпляр драйвера.
|
||||
@return Ненулевое значение, когда драйвер свободен.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void spiSe2pWrite(SPISE2P_DRV *se2p, SE2P_DATA *data)
|
||||
@brief Передаёт автомату описание операции записи.
|
||||
@param se2p Экземпляр драйвера.
|
||||
@param data Описание адреса, буфера и длины.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@fn void spiSe2pRead(SPISE2P_DRV *se2p, SE2P_DATA *data)
|
||||
@brief Передаёт автомату описание операции чтения.
|
||||
@param se2p Экземпляр драйвера.
|
||||
@param data Описание адреса, буфера и длины.
|
||||
*/
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
@@ -1,64 +0,0 @@
|
||||
@echo off
|
||||
rem Builds the local HTML overview and Doxygen API reference in Doc\build.
|
||||
rem Prefers the pinned Doc\.tools Doxygen, then falls back to a system install.
|
||||
rem If Doxygen is unavailable, installs the explanatory API placeholder instead.
|
||||
setlocal EnableExtensions
|
||||
|
||||
set "DOC_DIR=%~dp0"
|
||||
set "SOURCE=%DOC_DIR%index.html"
|
||||
set "BUILD_DIR=%DOC_DIR%build"
|
||||
set "OVERVIEW=%BUILD_DIR%\index.html"
|
||||
set "DOXYGEN_EXE=%DOC_DIR%.tools\doxygen-1.18.0\doxygen.exe"
|
||||
|
||||
echo [BALSAM 167] Building HTML documentation...
|
||||
|
||||
if not exist "%SOURCE%" (
|
||||
echo [ERROR] Source HTML not found:
|
||||
echo %SOURCE%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if not exist "%BUILD_DIR%" mkdir "%BUILD_DIR%"
|
||||
if errorlevel 1 (
|
||||
echo [ERROR] Cannot create build directory:
|
||||
echo %BUILD_DIR%
|
||||
exit /b 2
|
||||
)
|
||||
|
||||
copy /Y "%SOURCE%" "%OVERVIEW%" >nul
|
||||
if errorlevel 1 (
|
||||
echo [ERROR] Cannot build overview HTML.
|
||||
exit /b 3
|
||||
)
|
||||
|
||||
if not exist "%DOXYGEN_EXE%" (
|
||||
where doxygen >nul 2>nul
|
||||
if not errorlevel 1 set "DOXYGEN_EXE=doxygen"
|
||||
)
|
||||
|
||||
if not exist "%DOXYGEN_EXE%" if /I not "%DOXYGEN_EXE%"=="doxygen" (
|
||||
if not exist "%BUILD_DIR%\api\html" mkdir "%BUILD_DIR%\api\html"
|
||||
copy /Y "%DOC_DIR%api-unavailable.html" "%BUILD_DIR%\api\html\index.html" >nul
|
||||
echo [WARN] Doxygen is not installed; API reference was not regenerated.
|
||||
echo [OK] Overview: %OVERVIEW%
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
pushd "%DOC_DIR%"
|
||||
"%DOXYGEN_EXE%" Doxyfile
|
||||
set "DOXYGEN_RESULT=%ERRORLEVEL%"
|
||||
popd
|
||||
|
||||
if not "%DOXYGEN_RESULT%"=="0" (
|
||||
echo [ERROR] Doxygen failed with code %DOXYGEN_RESULT%.
|
||||
exit /b %DOXYGEN_RESULT%
|
||||
)
|
||||
|
||||
if not exist "%BUILD_DIR%\api\html\index.html" (
|
||||
echo [ERROR] Doxygen did not create the expected API index.
|
||||
exit /b 4
|
||||
)
|
||||
|
||||
echo [OK] Overview: %OVERVIEW%
|
||||
echo [OK] API: %BUILD_DIR%\api\html\index.html
|
||||
exit /b 0
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
@file main.c
|
||||
@brief Точка входа, запуск периферии и главный цикл приложения.
|
||||
@details Связывает все внутренние модули, выбирает ISR Timer1 по роли платы и
|
||||
обслуживает CAN, команды конфигурации, кнопки и оба последовательных канала.
|
||||
*/
|
||||
|
||||
/** @file ADC.c
|
||||
@brief Настройка ADC TMS320F28335 и обработка потока сырых измерений. */
|
||||
|
||||
/** @file measure.c
|
||||
@brief Пересчёт измерений Balsam 167, калибровка и диагностика каналов.
|
||||
@details Содержит периодический измерительный ISR и общие массивы фильтров,
|
||||
счётчиков, внешних температур, масок CAN и слов ошибок. */
|
||||
|
||||
/** @file filter_bat2.c
|
||||
@brief Реализация рекурсивного фильтра Баттерворта второго порядка. */
|
||||
|
||||
/** @file RS485.c
|
||||
@brief Драйвер SCI-A/SCI-B и автоматы приёма/передачи RS-485. */
|
||||
|
||||
/** @file bios.c
|
||||
@brief Сервисные и загрузочные команды BIOS-протокола TMS. */
|
||||
|
||||
/** @file message.c
|
||||
@brief Modbus-команды, обмен с OWEN и сохранение параметров изделия. */
|
||||
|
||||
/** @file ecan.c
|
||||
@brief Настройка eCAN-A, почтовые ящики, приём и отправка телеметрии. */
|
||||
|
||||
/** @file spise2p.c
|
||||
@brief Доступ к последовательной EEPROM через SPI-A. */
|
||||
|
||||
/** @file peripher.c
|
||||
@brief Определение аппаратной роли, таблицы GPIO и дискретные входы/выходы. */
|
||||
|
||||
/** @file DAC.c
|
||||
@brief Программный последовательный интерфейс аналогового выхода нагрузки. */
|
||||
|
||||
/** @file pulto.c
|
||||
@brief Периодическая логика панели EPLT. */
|
||||
|
||||
/** @file kanal.c
|
||||
@brief Низкоуровневая передача данных внешним семисегментным каналам. */
|
||||
|
||||
/** @file crc16.c
|
||||
@brief Варианты CRC-16, используемые транспортными и сервисными протоколами. */
|
||||
|
||||
/** @file cntrl_adr.c
|
||||
@brief Хранение и проверка индивидуального и группового адресов контроллера. */
|
||||
|
||||
/** @file log_to_mem.c
|
||||
@brief Инициализация циклического журнала во внешней памяти XINTF. */
|
||||
|
||||
/** @file tools.c
|
||||
@brief Настройка XINTF zone 7 и программные задержки. */
|
||||
|
||||
/** @file package.h
|
||||
@brief Конфигурация варианта Balsam и логическая карта массива Modbus.
|
||||
@warning Изменение смещений влияет на CAN, RS-485, EEPROM и внешнее ПО. */
|
||||
|
||||
/** @file GPIO_table.h
|
||||
@brief Направления, уровни и мультиплексирование GPIO для всех ролей платы. */
|
||||
|
||||
/** @file caliber.h
|
||||
@brief Заводские калибровочные таблицы вариантов Balsam.
|
||||
@note Заголовок содержит определения данных и намеренно исключён из разбора
|
||||
Doxygen, чтобы препроцессор не выбирал несовместимые варианты. */
|
||||
|
||||
117
Doc/index.html
117
Doc/index.html
File diff suppressed because one or more lines are too long
@@ -1,70 +0,0 @@
|
||||
# Balsam 167 Peripheral {#mainpage}
|
||||
|
||||
Прошивка периферийного контроллера **Balsam 167** для цифрового сигнального
|
||||
контроллера Texas Instruments TMS320F28335. Контроллер измеряет токи,
|
||||
напряжения и температуры, анализирует аварийные состояния, управляет
|
||||
дискретными выходами и обменивается данными по CAN и двум каналам SCI/RS-485.
|
||||
|
||||
@tableofcontents
|
||||
|
||||
## Назначение
|
||||
|
||||
Один исполняемый образ поддерживает несколько аппаратных ролей. Роль платы
|
||||
определяется входами режима при старте и хранится в `Desk`:
|
||||
|
||||
| Значение | Роль | Основная задача |
|
||||
|---|---|---|
|
||||
| `dsk_COMM` | COMM | связь и термокалибровка |
|
||||
| `dsk_BKSD` | BKSD | дискретные сигналы |
|
||||
| `dsk_BKST` | BKST | температурные каналы |
|
||||
| `dsk_EPLT` | EPLT | пульт/индикация |
|
||||
| `dsk_SHKF` | SHKF | шкафной контроллер |
|
||||
| `dsk_LOAD` | LOAD | нагрузка и аналоговый выход |
|
||||
|
||||
Конфигурация изделия выбирается макросом `BALSAM` в `package.h`. Для этого
|
||||
репозитория задано значение `167`.
|
||||
|
||||
## Выполнение программы
|
||||
|
||||
1. `main()` настраивает системную тактовую частоту, PIE, внешнюю память,
|
||||
GPIO, CAN, SCI, EEPROM и измерительные каналы.
|
||||
2. `timer_Init()` выбирает обработчик Timer1: `cpu_timer1_isr_SENS()` для
|
||||
измерительных плат или `cpu_timer1_isr_PULT()` для пульта.
|
||||
3. Быстрый контур АЦП выполняется в `adc_isr()`.
|
||||
4. Главный цикл передаёт телеметрию, обслуживает команды настройки,
|
||||
дискретные входы и протокол BIOS/Modbus.
|
||||
|
||||
## Карта модулей
|
||||
|
||||
- @ref measurement — сбор АЦП, фильтрация, пересчёт физических величин и ошибки.
|
||||
- @ref communication — SCI/RS-485, разбор команд и Modbus-пакеты.
|
||||
- @ref can_bus — CAN eCAN-A и циклическая телеметрия.
|
||||
- @ref storage — SPI EEPROM, параметры и журнал во внешней памяти.
|
||||
- @ref hardware — GPIO, дискретные выходы, ЦАП и семисегментный канал.
|
||||
- @ref boot_protocol — команды чтения, записи и запуска ПО через BIOS-протокол.
|
||||
- @ref utilities — CRC, фильтр Баттерворта, задержки и служебные функции.
|
||||
|
||||
## Общая память данных
|
||||
|
||||
Массив `modbus` — центральная модель состояния. Макросы из `package.h`
|
||||
проецируют его участки на флаги ошибок, измерения, уставки, коэффициенты
|
||||
калибровки и команды. Измерительный контур обновляет модель, а CAN/RS-485
|
||||
публикуют или изменяют её. При изменении разметки следует одновременно
|
||||
проверять адреса протокола, `ANSWER_LEN` и таблицу данных изделия в `Doc`.
|
||||
|
||||
## Сборка прошивки
|
||||
|
||||
Инструкции для Code Composer Studio 12 находятся в
|
||||
[README_CCS12.md](README_CCS12.md). Старый проект CCS 3 использует
|
||||
`UKSSTMS320F28335.pjt`; проект CCS 12 расположен в каталоге
|
||||
`UKSSTMS320F28335`.
|
||||
|
||||
## Сборка документации
|
||||
|
||||
Запустите `Doc\\build.bat`. Обзор будет помещён в `Doc\\build\\index.html`,
|
||||
а при наличии Doxygen API-справочник появится в
|
||||
`Doc\\build\\api\\html\\index.html`.
|
||||
|
||||
@warning Обработчики прерываний и функции, меняющие GPIO или регистры
|
||||
периферии, нельзя вызывать как обычные функции без понимания контекста PIE,
|
||||
частоты тактирования и выбранной роли платы.
|
||||
117
F28335.cmd
117
F28335.cmd
@@ -1,3 +1,4 @@
|
||||
/* Распределение памяти линкером и абсолютные границы загрузочного образа EEPROM. Русские пояснения сохранены в UTF-8. */
|
||||
/*
|
||||
// TI File $Revision: /main/10 $
|
||||
// Checkin $Date: July 9, 2008 13:43:56 $
|
||||
@@ -69,52 +70,74 @@
|
||||
*/
|
||||
|
||||
|
||||
/* Serial EEPROM is NOT CPU-addressable RAM/Flash. Do not add a fake MEMORY
|
||||
* region at address zero: SPI boot copies its table into the RAM areas below.
|
||||
* Export its physical layout as absolute byte/word symbols for .map/debugging.
|
||||
* The final SCI8 image size (including boot headers) is checked after hex2000. */
|
||||
/* Подключает "Source/Internal/Include/eeprom_config.h": выбор профиля физически установленной EEPROM при сборке. */
|
||||
#include "Source/Internal/Include/eeprom_config.h"
|
||||
/* Подключает "include/balsam167_eeprom_layout.h": настройки и интерфейс balsam167_eeprom_layout. */
|
||||
#include "include/balsam167_eeprom_layout.h"
|
||||
/* Записывает _EEPROM_TOTAL_BYTES значением BALSAM167_EEPROM_BYTES; данные _EEPROM_TOTAL_BYTES. */
|
||||
_EEPROM_TOTAL_BYTES = BALSAM167_EEPROM_BYTES;
|
||||
/* Записывает _EEPROM_FIRMWARE_LIMIT_BYTES значением BALSAM167_EEPROM_FIRMWARE_BYTES; данные _EEPROM_FIRMWARE_LIMIT_BYTES. */
|
||||
_EEPROM_FIRMWARE_LIMIT_BYTES = BALSAM167_EEPROM_FIRMWARE_BYTES;
|
||||
/* Записывает _EEPROM_PARAMS_START_WORD значением BALSAM167_EEPROM_PARAMS_START_WORD; EEPROM PARAMS START слово. */
|
||||
_EEPROM_PARAMS_START_WORD = BALSAM167_EEPROM_PARAMS_START_WORD;
|
||||
/* Записывает _EEPROM_PARAMS_START_BYTE значением BALSAM167_EEPROM_FIRMWARE_BYTES; данные _EEPROM_PARAMS_START_BYTE. */
|
||||
_EEPROM_PARAMS_START_BYTE = BALSAM167_EEPROM_FIRMWARE_BYTES;
|
||||
/* Записывает _EEPROM_PARAMS_END_BYTE значением BALSAM167_EEPROM_PARAMS_END_WORD * 2; данные _EEPROM_PARAMS_END_BYTE. */
|
||||
_EEPROM_PARAMS_END_BYTE = BALSAM167_EEPROM_PARAMS_END_WORD * 2;
|
||||
|
||||
/* Начинает описание физических блоков памяти для линкера. */
|
||||
MEMORY
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
PAGE 0: /* Program Memory */
|
||||
PAGE 0: /* Program Memory */ /* Выбирает страницу адресного пространства линкера: 0 — программа, 1 — данные. */
|
||||
/* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE1 for data allocation */
|
||||
|
||||
ZONE0 : origin = 0x004000, length = 0x001000 /* XINTF zone 0 */
|
||||
RAML0 : origin = 0x008000, length = 0x004000 /* on-chip RAM block L0 */
|
||||
ZONE0 : origin = 0x004000, length = 0x001000 /* XINTF zone 0 */ /* Записывает origin значением 0x004000, length = 0x001000; данные origin. */
|
||||
RAML0 : origin = 0x008000, length = 0x004000 /* on-chip RAM block L0 */ /* Записывает origin значением 0x008000, length = 0x004000; данные origin. */
|
||||
/* RAML1 : origin = 0x009000, length = 0x001000 /* on-chip RAM block L1 */
|
||||
/* RAML2 : origin = 0x00A000, length = 0x001000 /* on-chip RAM block L2 */
|
||||
// RAML3 : origin = 0x00B000, length = 0x001000 /* on-chip RAM block L3 */
|
||||
RAML4 : origin = 0x00C000, length = 0x001000 /* on-chip RAM block L1 */
|
||||
RAML4 : origin = 0x00C000, length = 0x001000 /* on-chip RAM block L1 */ /* Записывает origin значением 0x00C000, length = 0x001000; данные origin. */
|
||||
|
||||
ZONE6 : origin = 0x0100000, length = 0x100000 /* XINTF zone 6 */
|
||||
FLASHH : origin = 0x300000, length = 0x008000 /* on-chip FLASH */
|
||||
FLASHG : origin = 0x308000, length = 0x008000 /* on-chip FLASH */
|
||||
FLASHF : origin = 0x310000, length = 0x008000 /* on-chip FLASH */
|
||||
FLASHE : origin = 0x318000, length = 0x008000 /* on-chip FLASH */
|
||||
FLASHD : origin = 0x320000, length = 0x008000 /* on-chip FLASH */
|
||||
FLASHC : origin = 0x328000, length = 0x008000 /* on-chip FLASH */
|
||||
FLASHA : origin = 0x338000, length = 0x007F80 /* on-chip FLASH */
|
||||
CSM_RSVD : origin = 0x33FF80, length = 0x000076 /* Part of FLASHA. Program with all 0x0000 when CSM is in use. */
|
||||
BEGIN : origin = 0x33FFF6, length = 0x000002 /* Part of FLASHA. Used for "boot to Flash" bootloader mode. */
|
||||
CSM_PWL : origin = 0x33FFF8, length = 0x000008 /* Part of FLASHA. CSM password locations in FLASHA */
|
||||
OTP : origin = 0x380400, length = 0x000400 /* on-chip OTP */
|
||||
ADC_CAL : origin = 0x380080, length = 0x000009 /* ADC_cal function in Reserved memory */
|
||||
ZONE6 : origin = 0x0100000, length = 0x100000 /* XINTF zone 6 */ /* Записывает origin значением 0x0100000, length = 0x100000; данные origin. */
|
||||
FLASHH : origin = 0x300000, length = 0x008000 /* on-chip FLASH */ /* Записывает origin значением 0x300000, length = 0x008000; данные origin. */
|
||||
FLASHG : origin = 0x308000, length = 0x008000 /* on-chip FLASH */ /* Записывает origin значением 0x308000, length = 0x008000; данные origin. */
|
||||
FLASHF : origin = 0x310000, length = 0x008000 /* on-chip FLASH */ /* Записывает origin значением 0x310000, length = 0x008000; данные origin. */
|
||||
FLASHE : origin = 0x318000, length = 0x008000 /* on-chip FLASH */ /* Записывает origin значением 0x318000, length = 0x008000; данные origin. */
|
||||
FLASHD : origin = 0x320000, length = 0x008000 /* on-chip FLASH */ /* Записывает origin значением 0x320000, length = 0x008000; данные origin. */
|
||||
FLASHC : origin = 0x328000, length = 0x008000 /* on-chip FLASH */ /* Записывает origin значением 0x328000, length = 0x008000; данные origin. */
|
||||
FLASHA : origin = 0x338000, length = 0x007F80 /* on-chip FLASH */ /* Записывает origin значением 0x338000, length = 0x007F80; данные origin. */
|
||||
CSM_RSVD : origin = 0x33FF80, length = 0x000076 /* Part of FLASHA. Program with all 0x0000 when CSM is in use. */ /* Записывает origin значением 0x33FF80, length = 0x000076; данные origin. */
|
||||
BEGIN : origin = 0x33FFF6, length = 0x000002 /* Part of FLASHA. Used for "boot to Flash" bootloader mode. */ /* Записывает origin значением 0x33FFF6, length = 0x000002; данные origin. */
|
||||
CSM_PWL : origin = 0x33FFF8, length = 0x000008 /* Part of FLASHA. CSM password locations in FLASHA */ /* Записывает origin значением 0x33FFF8, length = 0x000008; данные origin. */
|
||||
OTP : origin = 0x380400, length = 0x000400 /* on-chip OTP */ /* Записывает origin значением 0x380400, length = 0x000400; данные origin. */
|
||||
ADC_CAL : origin = 0x380080, length = 0x000009 /* ADC_cal function in Reserved memory */ /* Записывает origin значением 0x380080, length = 0x000009; данные origin. */
|
||||
|
||||
IQTABLES : origin = 0x3FE000, length = 0x000b50 /* IQ Math Tables in Boot ROM */
|
||||
IQTABLES2 : origin = 0x3FEB50, length = 0x00008c /* IQ Math Tables in Boot ROM */
|
||||
FPUTABLES : origin = 0x3FEBDC, length = 0x0006A0 /* FPU Tables in Boot ROM */
|
||||
ROM : origin = 0x3FF27C, length = 0x000D44 /* Boot ROM */
|
||||
RESET : origin = 0x3FFFC0, length = 0x000002 /* part of boot ROM */
|
||||
VECTORS : origin = 0x3FFFC2, length = 0x00003E /* part of boot ROM */
|
||||
IQTABLES : origin = 0x3FE000, length = 0x000b50 /* IQ Math Tables in Boot ROM */ /* Записывает origin значением 0x3FE000, length = 0x000b50; данные origin. */
|
||||
IQTABLES2 : origin = 0x3FEB50, length = 0x00008c /* IQ Math Tables in Boot ROM */ /* Записывает origin значением 0x3FEB50, length = 0x00008c; данные origin. */
|
||||
FPUTABLES : origin = 0x3FEBDC, length = 0x0006A0 /* FPU Tables in Boot ROM */ /* Записывает origin значением 0x3FEBDC, length = 0x0006A0; данные origin. */
|
||||
ROM : origin = 0x3FF27C, length = 0x000D44 /* Boot ROM */ /* Записывает origin значением 0x3FF27C, length = 0x000D44; данные origin. */
|
||||
RESET : origin = 0x3FFFC0, length = 0x000002 /* part of boot ROM */ /* Записывает origin значением 0x3FFFC0, length = 0x000002; данные origin. */
|
||||
VECTORS : origin = 0x3FFFC2, length = 0x00003E /* part of boot ROM */ /* Записывает origin значением 0x3FFFC2, length = 0x00003E; данные origin. */
|
||||
|
||||
PAGE 1 : /* Data Memory */
|
||||
PAGE 1 : /* Data Memory */ /* Выбирает страницу адресного пространства линкера: 0 — программа, 1 — данные. */
|
||||
/* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE0 for program allocation */
|
||||
/* Registers remain on PAGE1 */
|
||||
|
||||
BOOT_RSVD : origin = 0x000000, length = 0x000050 /* Part of M0, BOOT rom will use this for stack */
|
||||
RAMM0 : origin = 0x000050, length = 0x0003B0 /* on-chip RAM block M0 */
|
||||
RAMM1 : origin = 0x000400, length = 0x000400 /* on-chip RAM block M1 */
|
||||
RAML5 : origin = 0x00D000, length = 0x003000 /* on-chip RAM block L1 */
|
||||
BOOT_RSVD : origin = 0x000000, length = 0x000050 /* Part of M0, BOOT rom will use this for stack */ /* Записывает origin значением 0x000000, length = 0x000050; данные origin. */
|
||||
RAMM0 : origin = 0x000050, length = 0x0003B0 /* on-chip RAM block M0 */ /* Записывает origin значением 0x000050, length = 0x0003B0; данные origin. */
|
||||
RAMM1 : origin = 0x000400, length = 0x000400 /* on-chip RAM block M1 */ /* Записывает origin значением 0x000400, length = 0x000400; данные origin. */
|
||||
RAML5 : origin = 0x00D000, length = 0x003000 /* on-chip RAM block L1 */ /* Записывает origin значением 0x00D000, length = 0x003000; данные origin. */
|
||||
/* RAML6 : origin = 0x00E000, length = 0x001000 /* on-chip RAM block L1 */
|
||||
/* RAML7 : origin = 0x00F000, length = 0x001000 /* on-chip RAM block L1 */
|
||||
ZONE7A : origin = 0x0200000, length = 0x00FC00 /* XINTF zone 7 - program space */
|
||||
ZONE7B : origin = 0x20FC00, length = 0x000400 /* XINTF zone 7 - data space */
|
||||
FLASHB : origin = 0x330000, length = 0x008000 /* on-chip FLASH */
|
||||
ZONE7A : origin = 0x0200000, length = 0x00FC00 /* XINTF zone 7 - program space */ /* Записывает origin значением 0x0200000, length = 0x00FC00; данные origin. */
|
||||
ZONE7B : origin = 0x20FC00, length = 0x000400 /* XINTF zone 7 - data space */ /* Записывает origin значением 0x20FC00, length = 0x000400; данные origin. */
|
||||
FLASHB : origin = 0x330000, length = 0x008000 /* on-chip FLASH */ /* Записывает origin значением 0x330000, length = 0x008000; данные origin. */
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/* Allocate sections to memory blocks.
|
||||
@@ -124,38 +147,60 @@ PAGE 1 : /* Data Memory */
|
||||
ramfuncs user defined section to store functions that will be copied from Flash into RAM
|
||||
*/
|
||||
|
||||
/* Начинает описание размещения секций объектных файлов для линкера. */
|
||||
SECTIONS
|
||||
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
||||
{
|
||||
|
||||
/* Allocate program areas: */
|
||||
.cinit : > RAML0 PAGE = 0
|
||||
/* Keep initialization tables out of the code RAM block. */
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
.cinit : > RAML4 PAGE = 0
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
.pinit : > RAML0 PAGE = 0
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
.text : > RAML0 PAGE = 0
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
codestart : > BEGIN PAGE = 0
|
||||
/* Записывает LOAD значением RAML4,; данные LOAD. */
|
||||
ramfuncs : LOAD = RAML4,
|
||||
/* Записывает RUN значением RAML4,; данные RUN. */
|
||||
RUN = RAML4,
|
||||
/* Вызывает LOAD_START с аргументами (_RamfuncsLoadStart), в текущей последовательности операций. */
|
||||
LOAD_START(_RamfuncsLoadStart),
|
||||
/* Вызывает LOAD_END с аргументами (_RamfuncsLoadEnd), в текущей последовательности операций. */
|
||||
LOAD_END(_RamfuncsLoadEnd),
|
||||
/* Вызывает RUN_START с аргументами (_RamfuncsRunStart), в текущей последовательности операций. */
|
||||
RUN_START(_RamfuncsRunStart),
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
PAGE = 0
|
||||
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
csmpasswds : > CSM_PWL PAGE = 0
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
csm_rsvd : > CSM_RSVD PAGE = 0
|
||||
|
||||
/* Allocate uninitalized data sections: */
|
||||
/* Записывает PAGE значением 1; данные PAGE. */
|
||||
.stack : > RAMM1 PAGE = 1
|
||||
/* Записывает PAGE значением 1; данные PAGE. */
|
||||
.ebss : > RAML5 PAGE = 1
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
.esysmem : > RAML0 PAGE = 0
|
||||
|
||||
/* Записывает PAGE значением 1; данные PAGE. */
|
||||
.logg : > ZONE7A PAGE = 1
|
||||
|
||||
/* Initalized sections go in Flash */
|
||||
/* For SDFlash to program these, they must be allocated to page 0 */
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
.econst : > RAML4 PAGE = 0
|
||||
/* Записывает PAGE значением 0; данные PAGE. */
|
||||
.switch : > RAML4 PAGE = 0
|
||||
|
||||
/* Allocate IQ math areas: */
|
||||
IQmath : > FLASHC PAGE = 0 /* Math Code */
|
||||
IQmath : > FLASHC PAGE = 0 /* Math Code */ /* Записывает PAGE значением 0; данные PAGE. */
|
||||
/* Записывает PAGE значением 0, TYPE = NOLOAD; данные PAGE. */
|
||||
IQmathTables : > IQTABLES, PAGE = 0, TYPE = NOLOAD
|
||||
|
||||
/* Uncomment the section below if calling the IQNexp() or IQexp()
|
||||
@@ -174,6 +219,7 @@ SECTIONS
|
||||
}
|
||||
*/
|
||||
|
||||
/* Записывает PAGE значением 0, TYPE = NOLOAD; данные PAGE. */
|
||||
FPUmathTables : > FPUTABLES, PAGE = 0, TYPE = NOLOAD
|
||||
|
||||
/* Allocate DMA-accessible RAM sections: * /
|
||||
@@ -183,6 +229,7 @@ SECTIONS
|
||||
DMARAML7 : > RAML7, PAGE = 1
|
||||
*/
|
||||
/* Allocate 0x400 of XINTF Zone 7 to storing data */
|
||||
/* Записывает PAGE значением 1; данные PAGE. */
|
||||
ZONE7DATA : > ZONE7B, PAGE = 1
|
||||
|
||||
/* .reset is a standard section used by the compiler. It contains the */
|
||||
@@ -190,12 +237,16 @@ SECTIONS
|
||||
/* When using the boot ROM this section and the CPU vector */
|
||||
/* table is not needed. Thus the default type is set here to */
|
||||
/* DSECT */
|
||||
/* Записывает PAGE значением 0, TYPE = DSECT; данные PAGE. */
|
||||
.reset : > RESET, PAGE = 0, TYPE = DSECT
|
||||
/* Записывает PAGE значением 0, TYPE = DSECT; данные PAGE. */
|
||||
vectors : > VECTORS PAGE = 0, TYPE = DSECT
|
||||
|
||||
/* Allocate ADC_cal function (pre-programmed by factory into TI reserved memory) */
|
||||
/* Записывает load значением ADC_CAL, PAGE = 0, TYPE = NOLOAD; данные load. */
|
||||
.adc_cal : load = ADC_CAL, PAGE = 0, TYPE = NOLOAD
|
||||
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* Поставляемое TI описание DefaultIsr для семейства C2833x. Русские пояснения сохранены в UTF-8. */
|
||||
// TI File $Revision: /main/1 $
|
||||
// Checkin $Date: August 18, 2006 13:45:37 $
|
||||
//###########################################################################
|
||||
@@ -11,11 +12,16 @@
|
||||
// $Release Date: August 1, 2008 $
|
||||
//###########################################################################
|
||||
|
||||
/* Начинает условие: DSP2833x_DEFAULT_ISR_H ещё не определён; защищает повторное включение или задаёт значение сборки. */
|
||||
#ifndef DSP2833x_DEFAULT_ISR_H
|
||||
/* Определяет защитный символ или переключатель DSP2833x_DEFAULT_ISR_H для последующей компиляции. */
|
||||
#define DSP2833x_DEFAULT_ISR_H
|
||||
|
||||
/* Включает следующий блок только при определённом символе __cplusplus. */
|
||||
#ifdef __cplusplus
|
||||
/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */
|
||||
extern "C" {
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -29,93 +35,163 @@ extern "C" {
|
||||
//
|
||||
|
||||
// Non-Peripheral Interrupts:
|
||||
/* Объявляет обработчик INT13_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void INT13_ISR(void); // XINT13 or CPU-Timer 1
|
||||
/* Объявляет обработчик INT14_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void INT14_ISR(void); // CPU-Timer2
|
||||
/* Объявляет обработчик DATALOG_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void DATALOG_ISR(void); // Datalogging interrupt
|
||||
/* Объявляет обработчик RTOSINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void RTOSINT_ISR(void); // RTOS interrupt
|
||||
/* Объявляет обработчик EMUINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EMUINT_ISR(void); // Emulation interrupt
|
||||
/* Объявляет обработчик NMI_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void NMI_ISR(void); // Non-maskable interrupt
|
||||
/* Объявляет обработчик ILLEGAL_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ILLEGAL_ISR(void); // Illegal operation TRAP
|
||||
/* Объявляет обработчик USER1_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER1_ISR(void); // User Defined trap 1
|
||||
/* Объявляет обработчик USER2_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER2_ISR(void); // User Defined trap 2
|
||||
/* Объявляет обработчик USER3_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER3_ISR(void); // User Defined trap 3
|
||||
/* Объявляет обработчик USER4_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER4_ISR(void); // User Defined trap 4
|
||||
/* Объявляет обработчик USER5_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER5_ISR(void); // User Defined trap 5
|
||||
/* Объявляет обработчик USER6_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER6_ISR(void); // User Defined trap 6
|
||||
/* Объявляет обработчик USER7_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER7_ISR(void); // User Defined trap 7
|
||||
/* Объявляет обработчик USER8_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER8_ISR(void); // User Defined trap 8
|
||||
/* Объявляет обработчик USER9_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER9_ISR(void); // User Defined trap 9
|
||||
/* Объявляет обработчик USER10_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER10_ISR(void); // User Defined trap 10
|
||||
/* Объявляет обработчик USER11_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER11_ISR(void); // User Defined trap 11
|
||||
/* Объявляет обработчик USER12_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void USER12_ISR(void); // User Defined trap 12
|
||||
|
||||
// Group 1 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик SEQ1INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SEQ1INT_ISR(void); // ADC Sequencer 1 ISR
|
||||
/* Объявляет обработчик SEQ2INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SEQ2INT_ISR(void); // ADC Sequencer 2 ISR
|
||||
/* Объявляет обработчик XINT1_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void XINT1_ISR(void); // External interrupt 1
|
||||
/* Объявляет обработчик XINT2_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void XINT2_ISR(void); // External interrupt 2
|
||||
/* Объявляет обработчик ADCINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ADCINT_ISR(void); // ADC
|
||||
/* Объявляет обработчик TINT0_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void TINT0_ISR(void); // Timer 0
|
||||
/* Объявляет обработчик WAKEINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void WAKEINT_ISR(void); // WD
|
||||
|
||||
// Group 2 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик EPWM1_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM1_TZINT_ISR(void); // EPWM-1
|
||||
/* Объявляет обработчик EPWM2_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM2_TZINT_ISR(void); // EPWM-2
|
||||
/* Объявляет обработчик EPWM3_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM3_TZINT_ISR(void); // EPWM-3
|
||||
/* Объявляет обработчик EPWM4_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM4_TZINT_ISR(void); // EPWM-4
|
||||
/* Объявляет обработчик EPWM5_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM5_TZINT_ISR(void); // EPWM-5
|
||||
/* Объявляет обработчик EPWM6_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM6_TZINT_ISR(void); // EPWM-6
|
||||
|
||||
// Group 3 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик EPWM1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM1_INT_ISR(void); // EPWM-1
|
||||
/* Объявляет обработчик EPWM2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM2_INT_ISR(void); // EPWM-2
|
||||
/* Объявляет обработчик EPWM3_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM3_INT_ISR(void); // EPWM-3
|
||||
/* Объявляет обработчик EPWM4_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM4_INT_ISR(void); // EPWM-4
|
||||
/* Объявляет обработчик EPWM5_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM5_INT_ISR(void); // EPWM-5
|
||||
/* Объявляет обработчик EPWM6_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EPWM6_INT_ISR(void); // EPWM-6
|
||||
|
||||
// Group 4 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик ECAP1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAP1_INT_ISR(void); // ECAP-1
|
||||
/* Объявляет обработчик ECAP2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAP2_INT_ISR(void); // ECAP-2
|
||||
/* Объявляет обработчик ECAP3_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAP3_INT_ISR(void); // ECAP-3
|
||||
/* Объявляет обработчик ECAP4_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAP4_INT_ISR(void); // ECAP-4
|
||||
/* Объявляет обработчик ECAP5_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAP5_INT_ISR(void); // ECAP-5
|
||||
/* Объявляет обработчик ECAP6_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAP6_INT_ISR(void); // ECAP-6
|
||||
|
||||
// Group 5 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик EQEP1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EQEP1_INT_ISR(void); // EQEP-1
|
||||
/* Объявляет обработчик EQEP2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void EQEP2_INT_ISR(void); // EQEP-2
|
||||
|
||||
// Group 6 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик SPIRXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SPIRXINTA_ISR(void); // SPI-A
|
||||
/* Объявляет обработчик SPITXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SPITXINTA_ISR(void); // SPI-A
|
||||
/* Объявляет обработчик MRINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void MRINTA_ISR(void); // McBSP-A
|
||||
/* Объявляет обработчик MXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void MXINTA_ISR(void); // McBSP-A
|
||||
/* Объявляет обработчик MRINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void MRINTB_ISR(void); // McBSP-B
|
||||
/* Объявляет обработчик MXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void MXINTB_ISR(void); // McBSP-B
|
||||
|
||||
// Group 7 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик DINTCH1_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void DINTCH1_ISR(void); // DMA-Channel 1
|
||||
/* Объявляет обработчик DINTCH2_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void DINTCH2_ISR(void); // DMA-Channel 2
|
||||
/* Объявляет обработчик DINTCH3_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void DINTCH3_ISR(void); // DMA-Channel 3
|
||||
/* Объявляет обработчик DINTCH4_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void DINTCH4_ISR(void); // DMA-Channel 4
|
||||
/* Объявляет обработчик DINTCH5_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void DINTCH5_ISR(void); // DMA-Channel 5
|
||||
/* Объявляет обработчик DINTCH6_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void DINTCH6_ISR(void); // DMA-Channel 6
|
||||
|
||||
// Group 8 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик I2CINT1A_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void I2CINT1A_ISR(void); // I2C-A
|
||||
/* Объявляет обработчик I2CINT2A_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void I2CINT2A_ISR(void); // I2C-A
|
||||
/* Объявляет обработчик SCIRXINTC_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SCIRXINTC_ISR(void); // SCI-C
|
||||
/* Объявляет обработчик SCITXINTC_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SCITXINTC_ISR(void); // SCI-C
|
||||
|
||||
// Group 9 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик SCIRXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SCIRXINTA_ISR(void); // SCI-A
|
||||
/* Объявляет обработчик SCITXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SCITXINTA_ISR(void); // SCI-A
|
||||
/* Объявляет обработчик SCIRXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SCIRXINTB_ISR(void); // SCI-B
|
||||
/* Объявляет обработчик SCITXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void SCITXINTB_ISR(void); // SCI-B
|
||||
/* Объявляет обработчик ECAN0INTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAN0INTA_ISR(void); // eCAN-A
|
||||
/* Объявляет обработчик ECAN1INTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAN1INTA_ISR(void); // eCAN-A
|
||||
/* Объявляет обработчик ECAN0INTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAN0INTB_ISR(void); // eCAN-B
|
||||
/* Объявляет обработчик ECAN1INTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void ECAN1INTB_ISR(void); // eCAN-B
|
||||
|
||||
// Group 10 PIE Interrupt Service Routines:
|
||||
@@ -123,23 +199,36 @@ interrupt void ECAN1INTB_ISR(void); // eCAN-B
|
||||
// Group 11 PIE Interrupt Service Routines:
|
||||
|
||||
// Group 12 PIE Interrupt Service Routines:
|
||||
/* Объявляет обработчик XINT3_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void XINT3_ISR(void); // External interrupt 3
|
||||
/* Объявляет обработчик XINT4_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void XINT4_ISR(void); // External interrupt 4
|
||||
/* Объявляет обработчик XINT5_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void XINT5_ISR(void); // External interrupt 5
|
||||
/* Объявляет обработчик XINT6_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void XINT6_ISR(void); // External interrupt 6
|
||||
/* Объявляет обработчик XINT7_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void XINT7_ISR(void); // External interrupt 7
|
||||
/* Объявляет обработчик LVF_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void LVF_ISR(void); // Latched overflow flag
|
||||
/* Объявляет обработчик LUF_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void LUF_ISR(void); // Latched underflow flag
|
||||
|
||||
// Catch-all for Reserved Locations For testing purposes:
|
||||
/* Объявляет интерфейс функции PIE_RESERVED; реализация вызывается через этот прототип. */
|
||||
interrupt void PIE_RESERVED(void); // Reserved for test
|
||||
/* Объявляет обработчик rsvd_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void rsvd_ISR(void); // for test
|
||||
/* Объявляет обработчик INT_NOTUSED_ISR; обслуживает источник прерывания и его аппаратные флаги. */
|
||||
interrupt void INT_NOTUSED_ISR(void); // for unused interrupts
|
||||
|
||||
/* Включает следующий блок только при определённом символе __cplusplus. */
|
||||
#ifdef __cplusplus
|
||||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||||
}
|
||||
#endif /* extern "C" */
|
||||
#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
|
||||
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
||||
#endif // end of DSP2833x_DEFAULT_ISR_H definition
|
||||
|
||||
//===========================================================================
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user