Compare commits
1 Commits
проверить-
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b15d9837a |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,2 @@
|
||||
/Debug/
|
||||
/UKSSTMS320F28335.CS_/
|
||||
/Bin/UKSSTMS320F28335_*.bin
|
||||
|
||||
Binary file not shown.
@@ -695,8 +695,8 @@
|
||||
:2056A20002FE1F767B03080604610102415608000092020A0254E6FFA8000606022BE0FF27
|
||||
:2056C20084007FD0008FC0DB9447566C0592346050D0013B9492FC9CA985A9BD120F0077BD
|
||||
:2056E20000770077007789E6000051D003E20A009492FC9CA985A9BD160F007720E80000CE
|
||||
:2057020003E20A0032E8000589E6090003E20A0003E20C0112E8010C14AD056502E8000CF8
|
||||
:2057220003E20A0094E6010014AD06628FE800E0007703E20C000192C0FF03540267030AF6
|
||||
:2057020003E20A0032E8000589E6090003E20A0003E20C01AFE20C00AFE20A0132E8000CC1
|
||||
:2057220003E20C0094E6080014AD06628FE808E0007703E20C000192C0FF03540267030AE5
|
||||
:205742000192030A035402670396AFE20A00AFE20C01C4E20103C4E2030220E709004FE879
|
||||
:2057620000604FE8096000E7180000E75100007710E74000086F0492032B90E5019CA91834
|
||||
:20578200FF0304967FD09493A892C6FF0190059604920E61A8480C6D8CE600000188013B25
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
# 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).
|
||||
|
||||
Модель ЦАП и электрическая схема не установлены. Режим выборки, назначение
|
||||
командных битов и допустимые длительности нельзя считать подтверждёнными
|
||||
до сверки с документацией конкретной микросхемы. Сборка/прошивка и стендовые
|
||||
измерения в рамках подготовки этого документа не выполнялись.
|
||||
@@ -1,119 +0,0 @@
|
||||
# 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,194 +0,0 @@
|
||||
# Логгер запуска и отключения УМП: прошивка Бальзам 167 и SetGUI
|
||||
|
||||
## Назначение и работа оператора
|
||||
|
||||
В SetGUI открыть ПМ35 → Настройки, выбрать COM, скорость (обычно 115200)
|
||||
и адрес контроллера (обычно 16). Затем открыть вкладку **Логгер УМП**.
|
||||
Подключение используется существующее: прямой RS232/RS485 Modbus RTU.
|
||||
CAN-команды от управляющего контроллера фиксируются самой платой нагрузки.
|
||||
|
||||
1. **Начать запись** включает только регистратор, не пуск УМП.
|
||||
Период снимков по умолчанию 20 мс, диапазон 1–1000 мс.
|
||||
2. Флажки выбирают отображаемые сигналы. Аналоги рисуются линиями,
|
||||
дискретные сигналы — отдельными дорожками. Выбор не меняет состав
|
||||
записи на плате: скрытую кривую можно включить после захвата.
|
||||
3. **Онлайн** подключает график к уже идущей записи, в том числе после
|
||||
восстановления соединения. Тайм-аут не посылает плате команду останова.
|
||||
4. Фронт `cUMPreset` (бит 6 команды 0x7F) или спад `cUMPstart` (бит 7)
|
||||
запускает фиксацию отключения. Ещё через 1000 тиков таймера / 1 секунду
|
||||
банк становится архивом. Повторные команды внутри этой секунды
|
||||
не продлевают интервал. Другие изменения команд не служат триггером.
|
||||
5. **Прочитать отключение** загружает архив, не останавливая запись на плате.
|
||||
На время чтения и просмотра архива онлайн-график приостанавливается;
|
||||
вернуться к нему можно кнопкой **Онлайн**.
|
||||
6. **Остановить и прочитать** останавливает только регистратор и читает
|
||||
текущий банк. При этом существующий архив отключения остаётся доступным.
|
||||
7. **Сохранить CSV** сохраняет все поля загруженного/онлайн-буфера,
|
||||
включая невидимые кривые, время и код события. История GUI ограничена
|
||||
800 последними точками; это не непрерывная запись на диск.
|
||||
|
||||
При разрыве связи журнал на плате продолжает работать. Архив хранится в ОЗУ
|
||||
до следующей фиксации отключения либо перезагрузки/пропадания питания.
|
||||
EEPROM не используется: под отключением в этой задаче понимается команда
|
||||
управляющего контроллера, а не потеря питания.
|
||||
|
||||
## Память и точность
|
||||
|
||||
Использована существующая секция `.logg` по адресу 0x200000: 64000
|
||||
16-битных слов. Два банка по 760 записей × 42 слова занимают 63840 слов (160 слов свободны).
|
||||
Текущий банк кольцевой. При триггере сохраняются последние до 379 записей,
|
||||
добавляется событие отключения, оставшаяся половина банка отведена
|
||||
постинтервалу. При 20 мс это до примерно 7.6 секунды до отключения и 1 секунды
|
||||
после. Дополнительные события CAN и дискретов сокращают временную глубину.
|
||||
|
||||
При интенсивном потоке событий или периоде 1 мс постинтервал может заполнить
|
||||
свои места раньше секунды. Последнее место зарезервировано под конечный
|
||||
снимок; он помечается `event & 0x200`, и GUI сообщает об усечении.
|
||||
Событие отключения и предыстория при этом не вытесняются.
|
||||
|
||||
Время — 32-битный счётчик миллисекунд записи. Он идёт только при включённом
|
||||
регистраторе и не является абсолютным временем. События в одном тике имеют
|
||||
одинаковую отметку; порядок сохраняется порядком записей. На перезапуске
|
||||
регистратора счётчик продолжает прежнюю шкалу, при перезагрузке платы — 0.
|
||||
|
||||
Онлайн-опрос возвращает две последние записи каждые 40 мс. Он не гарантирует
|
||||
передачу каждого события при высоком CAN-трафике, медленном UART или паузах
|
||||
GUI. Номера записей позволяют убрать дубликаты и явно показать пропуски.
|
||||
Полный сохранившийся фрагмент следует читать кнопкой архива. Частота 20 мс
|
||||
выбрана с учётом размера кадра; на низких скоростях нужна большая пауза
|
||||
снимков и подходящий тайм-аут RS.
|
||||
|
||||
Все писатели и чтение одного Modbus-блока используют короткие критические
|
||||
секции с восстановлением прежнего состояния IRQ. Внутри нет ожидания UART,
|
||||
EEPROM, выделения памяти или копирования целого банка. Реальную задержку
|
||||
прерываний и длительность критических секций нужно измерить на F28335.
|
||||
|
||||
## Состав записи v3: 42 слова
|
||||
|
||||
| Слова | Данные | Единицы/смысл |
|
||||
|---|---|---|
|
||||
| 0–1 | Время, младшее/старшее слово | мс записи |
|
||||
| 2 | Событие | 1 период, 2 CAN RX, 3 изменение I/O, 4 RS-команда, 5 конец постинтервала |
|
||||
| 2, бит 8 | Триггер отключения | флаг поверх причины события |
|
||||
| 2, бит 9 | Усечён постинтервал | установлен в конечном снимке |
|
||||
| 3 | Commands / modbus[0x7F] | все 16 бит, в том числе пуск, сброс, инициализация и калибровка ЦАП |
|
||||
| 4 | Входы OMEGA, Start_1, Res_in | биты 0,1,2, активный уровень приведён к 1 |
|
||||
| 5 | START_DPTB, STOP_DPTB, RES_OUT_2 | биты 0,1,2, активный уровень приведён к 1 |
|
||||
| 6 | IMPowse | остаток импульса, мс |
|
||||
| 7 | WAKEpowse | остаток инициализации, тики DAC_FREQ |
|
||||
| 8 | modbus[0x7B] | 12-битный код, переданный функцией dSEND в ЦАП |
|
||||
| 9 | modbus[0x1C] | расчётное задание в 0.1 мА; GUI/CSV переводит в мА |
|
||||
| 10–13 | sens_data[0..3] | измеренные сигналы, знаковое 16-битное значение в исходном масштабе |
|
||||
| 14–17 | modbus[0..3] | маски ошибок измерений |
|
||||
| 18 | CAN заголовок | адрес регистра в младших 13 битах и маска трёх слов в старших |
|
||||
| 19–21 | Три слова последнего принятого CAN-кадра | без преобразования |
|
||||
| 22 | Счётчик записанных CAN RX | младшие 16 бит |
|
||||
| 23 | CanTimeOutErrorTR | младшие 16 бит счётчика тайм-аутов CAN TX |
|
||||
| 24–25 | DAC_go, DAC_stop | исходные начальная/конечная уставки, мА |
|
||||
| 26–28 | DAC_min(), DAC_max(), DAC_cal() | коды калибровки и ручного задания ЦАП |
|
||||
| 29–30 | DAC_04, DAC_20 | значения соответствующих регистров |
|
||||
| 31–32 | count_load, time_dac | положение и длительность разгона в тиках |
|
||||
| 33–34 | эффективные dac_go/dac_stop + 4 | 0.1 мА после ограничений алгоритма; GUI переводит в мА |
|
||||
| 35 | kod | целочисленное положение, используемое Anal_output |
|
||||
| 36–39 | ADC_table[0..3] | значения таблицы АЦП в исходном масштабе прошивки |
|
||||
| 40 | ЗПТ1: U1 + U2, ПМ67 регистр 306 / индекс 305 | исходное 16-битное слово без пересчёта |
|
||||
| 41 | ЗПТ2: U3 + U4, ПМ67 регистр 9 / индекс 8 | исходное 16-битное слово без пересчёта |
|
||||
|
||||
Напряжения принимаются из технологических CAN-кадров с нулевыми индексами
|
||||
305 и 8. Учитываются все три позиции и биты маски 0x8000/0x4000/0x2000.
|
||||
Они хранятся отдельно от массива modbus[0..127], обновляются и при выключенном
|
||||
логгере. Запись содержит последние принятые значения; до первого приёма — 0.
|
||||
При потере связи остаётся последнее значение: отдельного признака свежести нет.
|
||||
Масштаб и знаковость физического напряжения не заданы исходной таблицей;
|
||||
SetGUI показывает исходное беззнаковое слово, коэффициент задаётся в интерфейсе.
|
||||
|
||||
**Отправленный код ЦАП не является измеренным током выхода.** В этом проекте
|
||||
не установлено, какой вход аппаратно измеряет ток ЦАП. При включённом
|
||||
`cCalibrDac` отправляется `DAC_cal()`, а расчётное задание 0x1C остаётся
|
||||
результатом алгоритма разгона. Для диагностики это различие сохранено.
|
||||
ADC_table также уже обрабатывается существующим измерительным кодом;
|
||||
это не обязательно необработанный регистр ADCRESULT.
|
||||
|
||||
Управляющая логика не исправлялась. Например, существующая строка
|
||||
`if(dac_stop>16) dac_go=16;` в Load_runner сохранена; журнал показывает
|
||||
фактически получившиеся эффективные уставки, чтобы выявить такое поведение.
|
||||
|
||||
## Протокол расширения Modbus
|
||||
|
||||
Технологические адреса 0..127 сохранены. Новая область использует полный
|
||||
16-битный адрес; исходная реализация игнорировала старший байт.
|
||||
Сначала GUI читает 16 слов 0x1000 и проверяет сигнатуру, версию, размер записи
|
||||
и тип платы. До успешной проверки расширенные записи запрещены.
|
||||
Обычный ответ расширения не содержит исторических хвостовых нулей.
|
||||
Между ответом и следующим запросом GUI выдерживает паузу RTU.
|
||||
|
||||
FC03, 0x1000, 16 слов:
|
||||
|
||||
| Смещение | Значение |
|
||||
|---|---|
|
||||
| 0,1 | 0x554D, версия 3 |
|
||||
| 2,3 | состояние и число записей выбранного источника |
|
||||
| 4,5 | 42 слова в записи, 760 записей в банке |
|
||||
| 6 | период периодических снимков, мс |
|
||||
| 7,8 | счётчик времени, младшее/старшее слово |
|
||||
| 9,10 | Desk (требуется 6 / dsk_LOAD), Mode |
|
||||
| 11 | частота временной базы, 1000 Гц |
|
||||
| 12 | поколение архива, mod 65536 |
|
||||
| 13 | число записей архива |
|
||||
| 14 | оставшиеся миллисекунды постинтервала |
|
||||
| 15 | состояние текущего регистратора независимо от выбора источника |
|
||||
|
||||
Состояния: 0 — ещё не запущен, 1 — запись, 3 — остановлен/архив.
|
||||
|
||||
FC06:
|
||||
- 0x1000: 1 — новый текущий журнал, 0 — остановить его;
|
||||
- 0x1001: период 1..1000, менять только при остановленном журнале;
|
||||
- 0x1002: хронологический индекс первой записи окна 0..759;
|
||||
- 0x1003: источник окна, 0 — текущий остановленный банк, 1 — архив отключения.
|
||||
|
||||
FC03, 0x1010, до 120 слов: окно от установленного индекса; для целых записей v3 читать 42 или 84 слова.
|
||||
CAN допускает 42/84 и прежние размеры 40/80/120; RTU допускает 1..120 слов.
|
||||
Чтение текущего банка этим окном во время записи не выдаёт изменяющиеся
|
||||
данные. GUI сначала останавливает его; архив можно читать при работающем
|
||||
текущем банке. После всех блоков GUI повторно проверяет поколение архива;
|
||||
при замене во время чтения результат не подменяет предыдущий график.
|
||||
|
||||
FC03, 0x1100, ровно 124 слова: онлайн-блок. Слова 0,1 — 32-битный номер
|
||||
первой записи, 2 — число записей 0..2, 3 — поколение архива, далее до двух
|
||||
записей по 42 слова. Неиспользованные слова равны нулю. Окно онлайн не
|
||||
зависит от курсора/выбора архива. Разделение 0x1010 и 0x1100 предотвращает
|
||||
пересечение двух окон.
|
||||
|
||||
Недопустимые диапазоны и значения возвращают исключения Modbus 2/3.
|
||||
CRC и разбор стандартного ответа GUI используют существующее общее ядро.
|
||||
SetGUI распознаёт v2 (40 слов, 800 записей) и v3 (42 слова, 760 записей).
|
||||
Для v2 новые напряжения недоступны (NaN), для v3 доступны графики и CSV.
|
||||
CAN-валидация общей библиотеки расширена размерами 42/84 слова.
|
||||
Исходники протокола подключаются к прошивке из templates/c/set-protocol.
|
||||
|
||||
## Проверка и запуск
|
||||
|
||||
Изменены исходники прошивки и SetGUI. Готовый образ в Bin не обновлялся.
|
||||
Для платы необходима сборка штатным TI C2000/CCS, проверка размещения .text,
|
||||
.stack, .ebss и .logg по MAP, прошивка и испытание на стенде.
|
||||
|
||||
Автотест C в tests/ump_logger компилирует непосредственно log_to_mem.c
|
||||
с подменой GPIO/IRQ. Проверяет кольцо, граничные адреса, обе команды
|
||||
отключения, защиту триггера от переполнения, переключение банков,
|
||||
сохранность архива во время дальнейшей записи и контрольные поля CAN/ЦАП.
|
||||
Это проверка алгоритма на компьютере, не проверка таймингов и 16-битной ABI
|
||||
TI. Отдельно выполнена синтаксическая проверка изменённых C-файлов Clang
|
||||
с исходными заголовками и декларациями TI-интринсиков.
|
||||
|
||||
Тесты SetGUI: tests/test_ump_logger.py и tests/test_periph28335_tab.py.
|
||||
Они проверяют единицы мА, битовые сигналы, временные метки, несовместимую
|
||||
прошивку, порядок команд, архив при активной записи, замену поколения,
|
||||
дубликаты/пропуски онлайн, потерю связи и флажки графиков.
|
||||
|
||||
Проверка на стенде: включить запись → подать CAN-пуск → изменить уставку →
|
||||
подать откл. → через секунду прочитать архив → сверить код ЦАП, ток внешним
|
||||
измерителем и физические входы/выходы; затем повторить с разрывом RS.
|
||||
Период 1 мс проверить отдельно под максимальной CAN-нагрузкой.
|
||||
|
||||
Для сборки v3 нужен templates/main начиная с коммита c0ee7c4
|
||||
(поддержка CAN-чтения 42/84 слов и порт TMS320F28335).
|
||||
@@ -136,12 +136,8 @@ void Load_runner()
|
||||
dac_stop=DAC_stop-4;
|
||||
if(dac_go<0) dac_go=0;
|
||||
if(dac_go>5) dac_go=5;
|
||||
if(dac_stop>16) dac_go=16;
|
||||
if(dac_stop>16) dac_stop=16;
|
||||
if(dac_stop<=dac_go) dac_stop=dac_go+1;
|
||||
/* Для лога сохраняем реальные ограниченные уставки:
|
||||
* внутренние dac_go/stop отсчитываются от 4 мА. */
|
||||
ump_dac_go10 = (unsigned int)((dac_go + 4.0) * 10.0);
|
||||
ump_dac_stop10 = (unsigned int)((dac_stop + 4.0) * 10.0);
|
||||
}
|
||||
|
||||
if(count_load > (time_dac/2))count_load++;
|
||||
@@ -158,11 +154,6 @@ void Load_runner()
|
||||
x = (x+1)&0x3FF;
|
||||
}
|
||||
|
||||
/* Снимок стадии разгона для сопоставления команды CAN,
|
||||
* ожидаемого тока и кода, действительно отправленного ЦАП. */
|
||||
ump_dac_ramp = count_load;
|
||||
ump_dac_duration = time_dac;
|
||||
ump_dac_position = (unsigned int)sinus;
|
||||
preStart = cUMPstart;
|
||||
|
||||
if(!x || cInitDac)
|
||||
|
||||
@@ -3,6 +3,5 @@ void Anal_output(long vrot, long maxx);
|
||||
void Init_DAC(void);
|
||||
void Setup_DAC_time(void);
|
||||
|
||||
/* Счётчик пускового импульса и выдержки инициализации доступны логгеру. */
|
||||
extern unsigned long IMPowse, WAKEpowse;
|
||||
extern unsigned long IMPowse;
|
||||
extern unsigned int period_dac, time_dac;
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
RS485.h
|
||||
****************************************************************
|
||||
* Процедуры работы с UART *
|
||||
****************************************************************/
|
||||
#ifndef _RS485
|
||||
#define _RS485
|
||||
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, ÊËÀÈÍ, ÊËÂÑÏ ====== */
|
||||
/* ÖÍÈÈ ÑÝÒ (ñ) 1998-2000 ã. */
|
||||
/****************************************************************/
|
||||
/* Bios_dsp.h */
|
||||
/****************************************************************/
|
||||
/* Îñíîâíûå êîììàíäû BIOS */
|
||||
/****************************************************************/
|
||||
#ifndef _BIOS_DSP
|
||||
#define _BIOS_DSP
|
||||
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
cntrl_adr.h
|
||||
****************************************************************
|
||||
* Адрес контроллера *
|
||||
****************************************************************/
|
||||
|
||||
#ifndef _CNTRL_ADR
|
||||
#define _CNTRL_ADR
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
void InitCan(int Port, int DevNum);
|
||||
void CAN_send(int Port, int data[], int Addr);
|
||||
extern int CAN_input_data[];
|
||||
|
||||
/* Íåáëîêèðóþùàÿ ïåðåäà÷à îòâåòîâ ëîããåðà îòäåëüíûì CAN mailbox. */
|
||||
void UMP_CAN_service(void);
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2001г. */
|
||||
/****************************************************************/
|
||||
/* log_to_mem.h
|
||||
****************************************************************
|
||||
* Запись логов в памyть *
|
||||
****************************************************************/
|
||||
|
||||
#ifndef _LOG_TO_MEM
|
||||
#define _LOG_TO_MEM
|
||||
|
||||
@@ -32,23 +42,6 @@ extern LOG Log;
|
||||
/* Î÷èñòêà ïàìàòè (îáíóëåíèå) */
|
||||
void clear_mem();
|
||||
|
||||
/* Ëîããåð ÓÌÏ: îòäåëüíîå àäðåñíîå ïðîñòðàíñòâî Modbus, áåç èçìåíåíèÿ
|
||||
* 128 òåõíîëîãè÷åñêèõ ðåãèñòðîâ. Äâà áàíêà ïî 760 çàïèñåé:
|
||||
* òåêóùèé êîëüöåâîé æóðíàë è çàôèêñèðîâàííûé ôðàãìåíò îòêëþ÷åíèÿ. */
|
||||
#define UMP_LOG_BASE 0x1000U
|
||||
#define UMP_LOG_DATA 0x1010U
|
||||
#define UMP_LOG_WORDS 42U
|
||||
#define UMP_LOG_CAPACITY 760U
|
||||
#define UMP_LOG_LIVE_RECORDS (120U / UMP_LOG_WORDS)
|
||||
#define UMP_LOG_LIVE 0x1100U
|
||||
extern unsigned int ump_dac_ramp, ump_dac_duration, ump_dac_go10, ump_dac_stop10, ump_dac_position;
|
||||
void ump_log_tick(void);
|
||||
void ump_log_io(void);
|
||||
void ump_log_can(unsigned int header, unsigned int a, unsigned int b, unsigned int c);
|
||||
void ump_log_rs(void);
|
||||
unsigned int ump_log_read(unsigned int address);
|
||||
int ump_log_write(unsigned int address, unsigned int value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// <20><><E2>
|
||||
#ifndef _MEASURE
|
||||
#define _MEASURE
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*=====================================================================
|
||||
File name : SPISE2P.H
|
||||
|
||||
Originator : Settu Duraisamy
|
||||
C2000 Applications Team
|
||||
Texas Instruments
|
||||
|
||||
Description :
|
||||
Header file containing object definitions, proto type
|
||||
declaration and default object initializers for
|
||||
SPI Serial EEPROM driver using VSPI
|
||||
|
||||
Date : 30/6/2003 (DD/MM/YYYY)
|
||||
=======================================================================*/
|
||||
|
||||
#ifndef __SPISE2P_H__
|
||||
|
||||
#define __SPISE2P_H__
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/* Shared logger protocol; application owns IRQ protection and CAN scheduling. */
|
||||
#ifndef UMP_CAN_PROTOCOL_H
|
||||
#define UMP_CAN_PROTOCOL_H
|
||||
#include "log_to_mem.h"
|
||||
#include "../../../../../templates/c/set-protocol/ports/tms320f28335/ump_tms28335.h"
|
||||
#define UMP_CAN_MARKER UMP_MARKER
|
||||
#define UMP_CAN_MAX_WORDS UMP_MAX_WORDS
|
||||
#define ump_can_prepare ump_tms28335_prepare
|
||||
#endif
|
||||
@@ -1,3 +1,13 @@
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
RS485.с
|
||||
****************************************************************
|
||||
* Процедуры работы с UART *
|
||||
****************************************************************/
|
||||
|
||||
//#include "big_dsp_module.h"
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
Bios.c
|
||||
**************************************************************
|
||||
Основные комманды BIOS *
|
||||
дла работы с RS232
|
||||
****************************************************************/
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
#include "RS485.h"
|
||||
#include "bios_dsp.h"
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
cntrl_adr.c
|
||||
****************************************************************
|
||||
* Адрес контроллера *
|
||||
****************************************************************/
|
||||
|
||||
#include "cntrl_adr.h"
|
||||
|
||||
#define ADDR_FOR_ALL_DEF 10
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#include "RS485.h"
|
||||
#include "message.h"
|
||||
#include "peripher.h"
|
||||
#include "log_to_mem.h"
|
||||
#include "ump_can_protocol.h"
|
||||
|
||||
|
||||
// Prototype statements for functions found within this file.
|
||||
@@ -32,16 +30,6 @@ int CanTimeOutErrorTR = 0;
|
||||
|
||||
int wait=0;
|
||||
|
||||
/* MBOX2 âûäåëåí ïîä îòâåòû ðåãèñòðàòîðà; øòàòíûé MBOX0 ïðîäîëæàåò
|
||||
* ïåðåäàâàòü òåõíîëîãè÷åñêèå äàííûå íåçàâèñèìî. ISR òîëüêî ñòàâèò çàïðîñ,
|
||||
* à ñíèìîê è îòïðàâêà êîðîòêèìè øàãàìè âûïîëíÿþòñÿ â îñíîâíîì öèêëå. */
|
||||
static volatile unsigned int ump_can_pending;
|
||||
static volatile unsigned int ump_can_tag, ump_can_address, ump_can_value;
|
||||
static unsigned int ump_can_reply[UMP_CAN_MAX_WORDS];
|
||||
static unsigned int ump_can_length, ump_can_index, ump_can_reply_tag;
|
||||
static unsigned int ump_can_waiting;
|
||||
static unsigned long ump_can_sent_at;
|
||||
|
||||
void InitCan(int Port, int DevNum)
|
||||
{
|
||||
struct ECAN_REGS ECanShadow;
|
||||
@@ -73,7 +61,6 @@ void InitCan(int Port, int DevNum)
|
||||
// Specify that 8 bits will be sent/received
|
||||
ECanMboxes->MBOX0.MSGCTRL.all = 0x00000008;
|
||||
ECanMboxes->MBOX1.MSGCTRL.all = 0x00000008;
|
||||
ECanMboxes->MBOX2.MSGCTRL.all = 0x00000008;
|
||||
|
||||
// Disable all Mailboxes
|
||||
// Required before writing the MSGIDs
|
||||
@@ -85,12 +72,11 @@ void InitCan(int Port, int DevNum)
|
||||
// çàäàåì àäðåñ 1 àùèêa íà ïðèåì
|
||||
ECanMboxes->MBOX1.MSGID.all = id + DevNum; //ïîìåíàòü!!!! 1 è 0!!!
|
||||
|
||||
// MBOX0 è MBOX2 ïåðåäàþò äàííûå; MBOX1 ïðèíèìàåò êîìàíäû.
|
||||
ECanMboxes->MBOX2.MSGID.all = id + 0x20 + DevNum;
|
||||
ECanRegs->CANMD.all = 0xFFFFFFFA;
|
||||
// задаем режимы работы ащикa 0 на передачу, остальные на прием
|
||||
ECanRegs->CANMD.all = 0xFFFFFFFE;
|
||||
|
||||
// Âêëþ÷àåì òðè mailbox: òåëåìåòðèÿ, êîìàíäû è îòâåòû ëîããåðà.
|
||||
ECanRegs->CANME.all = 0x00000007;
|
||||
// выбираем только 2 ащикa дла работы, остальные запрещаем
|
||||
ECanRegs->CANME.all = 0x00000003;
|
||||
|
||||
// Clear all TAn bits
|
||||
ECanRegs->CANTA.all = 0xFFFFFFFF;
|
||||
@@ -210,18 +196,6 @@ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
|
||||
hiword = ECanMboxes->MBOX1.MDH.all;
|
||||
loword = ECanMboxes->MBOX1.MDL.all;
|
||||
|
||||
/* Ñëóæåáíûé çàïðîñ ëîããåðà íå ÿâëÿåòñÿ êîìàíäîé ÓÌÏ è ñàì íå äîëæåí
|
||||
* çàïîëíÿòü æóðíàë CAN-ñîáûòèÿìè ïðè îíëàéí-÷òåíèè. Êîðîòêèå êàäðû
|
||||
* îòáðàñûâàþòñÿ: íåçàïîëíåííûå áàéòû mailbox ìîãëè îñòàòüñÿ îò ïðîøëîãî. */
|
||||
if ((unsigned int)(hiword >> 16) == UMP_CAN_MARKER) {
|
||||
if (ECanMboxes->MBOX1.MSGCTRL.bit.DLC == 8 && (hiword & 0xFF00UL)) {
|
||||
ump_can_tag = (unsigned int)hiword;
|
||||
ump_can_address = (unsigned int)(loword >> 16);
|
||||
ump_can_value = (unsigned int)loword;
|
||||
ump_can_pending = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
adr = (hiword >> 16);
|
||||
|
||||
bit[0] = adr & 0x8000;
|
||||
@@ -238,8 +212,6 @@ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
|
||||
if(bit[1]) if(adr < ANSWER_LEN) modbus[adr] = Data[1]; adr++;
|
||||
if(bit[2]) if(adr < ANSWER_LEN) modbus[adr] = Data[2];
|
||||
|
||||
/* Ôèêñèðóåì ïðèìåí¸ííóþ êîìàíäó äî âûõîäà èç îáðàáîò÷èêà CAN. */
|
||||
ump_log_can((unsigned int)(hiword >> 16), Data[0], Data[1], Data[2]);
|
||||
led2_toggle();
|
||||
}
|
||||
|
||||
@@ -285,55 +257,3 @@ interrupt void CANa_reset_err(void)
|
||||
//===========================================================================
|
||||
// No more.
|
||||
//===========================================================================
|
||||
|
||||
|
||||
/* Îäèí âûçîâ îáñëóæèâàåò ìàêñèìóì îäèí êàäð è íèêîãäà íå æä¸ò ACK â öèêëå.
|
||||
* Ñíèìîê ôèêñèðóåòñÿ îäèí ðàç íà çàïðîñ: CAN-ôðàãìåíòû íå ñìåøèâàþò
|
||||
* çíà÷åíèÿ äî/ïîñëå ïåðåêëþ÷åíèÿ êîëüöåâîãî áàíêà. Íîâûå çàïðîñû çàáèðàåì
|
||||
* ïîñëå çàâåðøåíèÿ ïðåäûäóùåãî îòâåòà. GUI äåðæèò òîëüêî îäèí çàïðîñ. */
|
||||
void UMP_CAN_service(void)
|
||||
{
|
||||
unsigned int saved, tag, address, value, error;
|
||||
uint32_t hiword, loword;
|
||||
if (ump_can_waiting) {
|
||||
if (ECanaRegs.CANTA.all & 4UL) {
|
||||
ECanaRegs.CANTA.all = 4UL;
|
||||
ump_can_waiting = 0;
|
||||
} else if ((ECanaRegs.CANAA.all & 4UL) ||
|
||||
((unsigned long)CpuTimer1.InterruptCount - ump_can_sent_at > 250UL)) {
|
||||
/* Íåò ïîäòâåðæäåíèÿ øèíû: îòìåíÿåì òîëüêî ñëóæåáíûé mailbox.
|
||||
* GUI îáíàðóæèò íåïîëíûé îòâåò ïî òàéì-àóòó; óïðàâëåíèå MBOX0
|
||||
* è ïðè¸ì êîìàíä MBOX1 ïðîäîëæàþòñÿ. */
|
||||
ECanaRegs.CANTRR.all = 4UL;
|
||||
/* Äî ôàêòè÷åñêîãî çàâåðøåíèÿ îòìåíû mailbox íå ïåðåèñïîëüçóåì. */
|
||||
if (!(ECanaRegs.CANAA.all & 4UL)) return;
|
||||
ECanaRegs.CANAA.all = 4UL;
|
||||
ump_can_waiting = 0;
|
||||
ump_can_length = 0;
|
||||
} else return;
|
||||
}
|
||||
if (ump_can_index >= ump_can_length && ump_can_pending) {
|
||||
saved = __disable_interrupts();
|
||||
tag = ump_can_tag; address = ump_can_address; value = ump_can_value;
|
||||
ump_can_pending = 0;
|
||||
ump_can_length = ump_can_prepare(tag & 0xFF, address, value, ump_can_reply, &error);
|
||||
ump_can_reply_tag = (tag & 0xFF00) | error;
|
||||
ump_can_index = 0;
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
if (ump_can_index >= ump_can_length) return;
|
||||
/* Ïåðåä ñëåäóþùèì ôðàãìåíòîì óñòóïàåì øòàòíîé òåëåìåòðèè MBOX0. */
|
||||
if (ECanaRegs.CANTRS.all & 1UL) return;
|
||||
if (!ump_tms28335_fragment(ump_can_reply, ump_can_length, ump_can_index/2,
|
||||
ump_can_reply_tag >> 8, ump_can_reply_tag & 255U, &loword, &hiword)) {
|
||||
ump_can_length = 0;
|
||||
return;
|
||||
}
|
||||
ECanaRegs.CANTA.all = 4UL; ECanaRegs.CANAA.all = 4UL;
|
||||
ECanaMboxes.MBOX2.MDH.all = hiword;
|
||||
ECanaMboxes.MBOX2.MDL.all = loword;
|
||||
ump_can_sent_at = CpuTimer1.InterruptCount;
|
||||
ECanaRegs.CANTRS.all = 4UL;
|
||||
ump_can_waiting = 1;
|
||||
ump_can_index += 2;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include "DSP2833x_Device.h"
|
||||
#include "filter_bat2.h"
|
||||
#include "measure.h"
|
||||
#include "package.h"
|
||||
#include "RS485.h"
|
||||
#include "message.h"
|
||||
#include "peripher.h"
|
||||
#include "DAC.h"
|
||||
#include "ADC.h"
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2001г. */
|
||||
/****************************************************************/
|
||||
/* log_to_mem.c
|
||||
****************************************************************
|
||||
* Запись логов в памyть *
|
||||
****************************************************************/
|
||||
|
||||
#include "log_to_mem.h"
|
||||
|
||||
int no_write = 0,
|
||||
@@ -31,249 +32,3 @@ void clear_mem()
|
||||
for (i=Log.Start; i<Log.Finis; i++)
|
||||
*(volatile int *)i = 0;
|
||||
}
|
||||
/* Äâà áàíêà èñïîëüçóþò óæå âûäåëåííóþ âíåøíþþ RAM .logg (64000 ñëîâ).
|
||||
* Àêòèâíûé áàíê êîëüöåâîé. ×åðåç 1000 ìñ ïîñëå êîìàíäû îòêëþ÷åíèÿ îí
|
||||
* ñòàíîâèòñÿ àðõèâîì, à çàïèñü ïðîäîëæàåòñÿ âî âòîðîì áàíêå. Ïåðåêëþ÷åíèå
|
||||
* çàíèìàåò ïîñòîÿííîå âðåìÿ: êîïèðîâàíèÿ 30 òûñÿ÷ ñëîâ ïîä çàïðåòîì IRQ íåò.
|
||||
* Àðõèâ ïåðåæèâàåò ðàçðûâ RS-ñâÿçè, íî ÍÅ èñ÷åçíîâåíèå ïèòàíèÿ ïëàòû. */
|
||||
static volatile unsigned int ump_state, ump_count, ump_cursor, ump_next;
|
||||
static volatile unsigned int ump_period = 20, ump_divider;
|
||||
static volatile unsigned long ump_time, ump_sequence;
|
||||
static unsigned int ump_bank, ump_archive_bank = 1;
|
||||
static unsigned int ump_archive_count, ump_archive_next, ump_generation;
|
||||
static unsigned int ump_source, ump_post, ump_post_dropped;
|
||||
static unsigned int ump_can_header, ump_can_data[3], ump_can_count;
|
||||
/* Latest PM67 sums: register 306 (index 305), register 9 (index 8). */
|
||||
static unsigned int ump_pm67_voltage[2];
|
||||
static unsigned int ump_prev_commands, ump_prev_inputs, ump_prev_outputs;
|
||||
extern int CanTimeOutErrorTR;
|
||||
/* Äèàãíîñòèêà âíóòðåííèõ ïåðåìåííûõ ðàçãîíà. Îáíîâëÿåòñÿ ñàìèì Load_runner,
|
||||
* íå ïåðåñ÷èòûâàåò è íå èçìåíÿåò óïðàâëÿþùèé àëãîðèòì. */
|
||||
unsigned int ump_dac_ramp, ump_dac_duration, ump_dac_go10, ump_dac_stop10, ump_dac_position;
|
||||
|
||||
/* Ëîãè÷åñêèå óðîâíè âõîäîâ ïëàòû íàãðóçêè: ôèçè÷åñêèé íîëü îçíà÷àåò 1.
|
||||
* ×òåíèå GPIO íåïîñðåäñòâåííî çäåñü ïîçâîëÿåò çàïèñàòü âõîä äî ñëåäóþùåãî
|
||||
* îáíîâëåíèÿ ðåãèñòðà Inputs â îñíîâíîì öèêëå. */
|
||||
static unsigned int ump_inputs(void)
|
||||
{
|
||||
return (!GpioDataRegs.GPADAT.bit.GPIO6) |
|
||||
((!GpioDataRegs.GPADAT.bit.GPIO8) << 1) |
|
||||
((!GpioDataRegs.GPADAT.bit.GPIO11) << 2);
|
||||
}
|
||||
|
||||
/* START/STOP àêòèâíû åäèíèöåé; RES_OUT_2 àêòèâåí ôèçè÷åñêèì íóë¸ì. */
|
||||
static unsigned int ump_outputs(void)
|
||||
{
|
||||
return GpioDataRegs.GPBDAT.bit.GPIO62 |
|
||||
(GpioDataRegs.GPBDAT.bit.GPIO58 << 1) |
|
||||
((!GpioDataRegs.GPADAT.bit.GPIO3) << 2);
|
||||
}
|
||||
|
||||
/* Âûçûâàåòñÿ òîëüêî âíóòðè êîðîòêîé êðèòè÷åñêîé ñåêöèè. Âñå òðè èñòî÷íèêà
|
||||
* çàïèñåé (main, CAN ISR, timer ISR) èñïîëüçóþò îäíó áëîêèðîâêó IRQ ñ
|
||||
* âîññòàíîâëåíèåì ïðåæíåãî ñîñòîÿíèÿ, âêëþ÷àÿ âûçîâû èç ïðåðûâàíèÿ. */
|
||||
static void ump_capture(unsigned int reason)
|
||||
{
|
||||
volatile unsigned int *p;
|
||||
unsigned int i, commands;
|
||||
if (ump_state != 1 || Desk != dsk_LOAD || !READY) return;
|
||||
if (no_write || never_write) { ump_state = 3; return; }
|
||||
commands = Commands;
|
||||
/* Îòêëþ÷åíèå: ôðîíò cUMPreset (áèò 6) ëèáî ñïàä cUMPstart (áèò 7).
|
||||
* Ïîâòîðíûå êîìàíäû íå ñäâèãàþò êîíåö óæå íà÷àòîãî ïîñòèíòåðâàëà. */
|
||||
if (!ump_post && (((commands & 0x40) && !(ump_prev_commands & 0x40)) ||
|
||||
(!(commands & 0x80) && (ump_prev_commands & 0x80)))) {
|
||||
/* Ïîëîâèíó áàíêà ðåçåðâèðóåì ïîä ïîñòèíòåðâàë. Äàæå ïðè ïåðèîäå
|
||||
* 1 ìñ èëè øêâàëå CAN ñîáûòèå îòêëþ÷åíèÿ íå âûòåñíÿåòñÿ êîëüöîì. */
|
||||
if (ump_count >= UMP_LOG_CAPACITY/2) ump_count = UMP_LOG_CAPACITY/2-1;
|
||||
ump_post_dropped = 0;
|
||||
ump_post = 1000;
|
||||
reason |= 0x100;
|
||||
}
|
||||
/* Ïîñëåäíåå ìåñòî îñòàâëÿåì äëÿ ñíèìêà êîíöà ïîñòèíòåðâàëà. Ïðè
|
||||
* ïåðåïîëíåíèè ÷åñòíî îòìå÷àåì óñå÷åíèå áèòîì 0x200 â êîíå÷íîé çàïèñè. */
|
||||
if (ump_post && ump_count >= UMP_LOG_CAPACITY-1) {
|
||||
ump_post_dropped = 1;
|
||||
return;
|
||||
}
|
||||
if (reason == 5 && ump_post_dropped) reason |= 0x200;
|
||||
p = logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS;
|
||||
p[0] = (unsigned int)ump_time; p[1] = (unsigned int)(ump_time >> 16);
|
||||
p[2] = reason; p[3] = commands;
|
||||
p[4] = ump_inputs(); p[5] = ump_outputs();
|
||||
p[6] = (unsigned int)IMPowse; p[7] = (unsigned int)WAKEpowse;
|
||||
p[8] = modbus[0x7B]; p[9] = modbus[0x1C];
|
||||
for (i = 0; i < 4; i++) { p[10+i] = sens_data[i]; p[14+i] = modbus[i]; }
|
||||
p[18] = ump_can_header;
|
||||
p[19] = ump_can_data[0]; p[20] = ump_can_data[1]; p[21] = ump_can_data[2];
|
||||
p[22] = ump_can_count; p[23] = CanTimeOutErrorTR;
|
||||
/* Èñõîäíûå óñòàâêè — ìÀ; ýôôåêòèâíûå óñòàâêè ïîñëå îãðàíè÷åíèé — 0.1 ìÀ.
|
||||
* p[8] — îòïðàâëåííûé êîä, à p[9] — ðàñ÷¸òíîå çàäàíèå, ÍÅ èçìåðåíèå òîêà. */
|
||||
p[24] = DAC_go; p[25] = DAC_stop;
|
||||
p[26] = DAC_min(); p[27] = DAC_max(); p[28] = DAC_cal();
|
||||
p[29] = DAC_04; p[30] = DAC_20;
|
||||
p[31] = ump_dac_ramp; p[32] = ump_dac_duration;
|
||||
p[33] = ump_dac_go10; p[34] = ump_dac_stop10; p[35] = ump_dac_position;
|
||||
for (i = 0; i < 4; i++) p[36+i] = ADC_table[i];
|
||||
p[40] = ump_pm67_voltage[0]; p[41] = ump_pm67_voltage[1];
|
||||
ump_prev_commands = commands; ump_prev_inputs = p[4]; ump_prev_outputs = p[5];
|
||||
ump_next++;
|
||||
if (ump_next == UMP_LOG_CAPACITY) ump_next = 0;
|
||||
if (ump_count < UMP_LOG_CAPACITY) ump_count++;
|
||||
ump_sequence++;
|
||||
}
|
||||
|
||||
/* Çàâåðø¸ííûé áàíê áîëüøå íå èçìåíÿåòñÿ äî ñëåäóþùåãî îòêëþ÷åíèÿ.
|
||||
* Íîìåð ïîêîëåíèÿ ïîçâîëÿåò GUI îáíàðóæèòü çàìåíó àðõèâà âî âðåìÿ ÷òåíèÿ. */
|
||||
static void ump_freeze(void)
|
||||
{
|
||||
ump_archive_bank = ump_bank;
|
||||
ump_archive_count = ump_count; ump_archive_next = ump_next;
|
||||
ump_generation++;
|
||||
ump_bank ^= 1;
|
||||
ump_count = 0; ump_next = 0; ump_post = 0;
|
||||
}
|
||||
|
||||
void ump_log_tick(void)
|
||||
{
|
||||
unsigned int saved = __disable_interrupts();
|
||||
if (ump_state == 1) {
|
||||
ump_time++;
|
||||
if (++ump_divider >= ump_period) { ump_divider = 0; ump_capture(1); }
|
||||
if (ump_post && --ump_post == 0) {
|
||||
ump_capture(5);
|
||||
ump_freeze();
|
||||
}
|
||||
}
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
|
||||
/* Äîïîëíèòåëüíûé ñíèìîê òîëüêî ïðè èçìåíåíèè êîìàíä, âõîäîâ èëè âûõîäîâ.
|
||||
* Ýòî íå çàìåíÿåò ïåðèîäè÷åñêóþ çàïèñü àíàëîãîâûõ âåëè÷èí â òàéìåðå. */
|
||||
void ump_log_io(void)
|
||||
{
|
||||
unsigned int saved;
|
||||
if (ump_state != 1 || Desk != dsk_LOAD) return;
|
||||
saved = __disable_interrupts();
|
||||
if (Commands != ump_prev_commands || ump_inputs() != ump_prev_inputs ||
|
||||
ump_outputs() != ump_prev_outputs) ump_capture(3);
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
|
||||
/* Âûçûâàåòñÿ ïîñëå ïðèìåíåíèÿ ñëîâ ïðèíÿòîãî CAN-êàäðà: ñíèìîê ñîäåðæèò
|
||||
* íîâûå êîìàíäû, à òàêæå èñõîäíûé àäðåñ/ìàñêó è âñå òðè ñëîâà êàäðà. */
|
||||
void ump_log_can(unsigned int header, unsigned int a, unsigned int b, unsigned int c)
|
||||
{
|
||||
unsigned int saved, i, address, mask, data[3];
|
||||
if (Desk != dsk_LOAD) return;
|
||||
saved = __disable_interrupts();
|
||||
data[0] = a; data[1] = b; data[2] = c;
|
||||
address = header & 0x1FFFU;
|
||||
mask = 0x8000U;
|
||||
/* Track reception even while recording is stopped. Each mask bit
|
||||
* refers to its own address, including disabled words in between. */
|
||||
for (i = 0; i < 3; i++, address++, mask >>= 1) {
|
||||
if (!(header & mask)) continue;
|
||||
if (address == 305U) ump_pm67_voltage[0] = data[i];
|
||||
if (address == 8U) ump_pm67_voltage[1] = data[i];
|
||||
}
|
||||
if (ump_state != 1) { __restore_interrupts(saved); return; }
|
||||
ump_can_header = header;
|
||||
ump_can_data[0] = a; ump_can_data[1] = b; ump_can_data[2] = c;
|
||||
ump_can_count++;
|
||||
ump_capture(2);
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
|
||||
void ump_log_rs(void)
|
||||
{
|
||||
unsigned int saved = __disable_interrupts();
|
||||
ump_capture(4);
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
|
||||
/* Óïðàâëåíèå æóðíàëîì îòäåëåíî îò òåõíîëîãè÷åñêèõ êîìàíä: íà÷àëî çàïèñè
|
||||
* ÍÅ çàïóñêàåò ÓÌÏ. Âûáîð àðõèâà íå îñòàíàâëèâàåò òåêóùóþ çàïèñü. */
|
||||
int ump_log_write(unsigned int address, unsigned int value)
|
||||
{
|
||||
unsigned int saved, valid = 1;
|
||||
saved = __disable_interrupts();
|
||||
if (address == UMP_LOG_BASE && value == 0) {
|
||||
ump_state = 3; ump_post = 0;
|
||||
} else if (address == UMP_LOG_BASE && value == 1 && Desk == dsk_LOAD && READY && ump_state != 1) {
|
||||
ump_count = 0; ump_next = 0; ump_cursor = 0; ump_divider = 0; ump_post = 0;
|
||||
ump_source = 0;
|
||||
ump_prev_commands = Commands;
|
||||
no_write = 0; never_write = 0;
|
||||
ump_state = 1;
|
||||
ump_capture(1);
|
||||
}
|
||||
else if (address == UMP_LOG_BASE+1 && ump_state != 1 && value >= 1 && value <= 1000)
|
||||
ump_period = value;
|
||||
else if (address == UMP_LOG_BASE+2 && value < UMP_LOG_CAPACITY)
|
||||
ump_cursor = value;
|
||||
else if (address == UMP_LOG_BASE+3 && value <= 1) ump_source = value;
|
||||
else valid = 0;
|
||||
__restore_interrupts(saved);
|
||||
return valid;
|
||||
}
|
||||
|
||||
/* Ïðåîáðàçîâàíèå õðîíîëîãè÷åñêîãî èíäåêñà â ôèçè÷åñêóþ ïîçèöèþ êîëüöà.
|
||||
* Äëÿ àðõèâà ñîõðàíåíû ñîáñòâåííûå count/next, íåçàâèñèìûå îò æèâîãî áàíêà. */
|
||||
static unsigned int ump_word(unsigned int archived, unsigned int record, unsigned int word)
|
||||
{
|
||||
unsigned int count = archived ? ump_archive_count : ump_count;
|
||||
unsigned int next = archived ? ump_archive_next : ump_next;
|
||||
unsigned int bank = archived ? ump_archive_bank : ump_bank;
|
||||
unsigned int slot;
|
||||
if (record >= count) return 0;
|
||||
slot = next + UMP_LOG_CAPACITY - count + record;
|
||||
while (slot >= UMP_LOG_CAPACITY) slot -= UMP_LOG_CAPACITY;
|
||||
return logs_block[((unsigned long)bank * UMP_LOG_CAPACITY + slot) * UMP_LOG_WORDS + word];
|
||||
}
|
||||
|
||||
/* Âåñü Modbus-áëîê ÷èòàåòñÿ âûçûâàþùèì êîäîì ïîä îäíîé áëîêèðîâêîé IRQ.
|
||||
* Ïîýòîìó timestamp/äàííûå è çàãîëîâîê îíëàéí-áëîêà îòíîñÿòñÿ ê îäíîìó
|
||||
* ñîñòîÿíèþ êîëüöà, äàæå åñëè â ýòîò ìîìåíò ïðèõîäèò íîâàÿ CAN-êîìàíäà. */
|
||||
unsigned int ump_log_read(unsigned int address)
|
||||
{
|
||||
unsigned int offset, count;
|
||||
unsigned long first;
|
||||
switch (address) {
|
||||
case UMP_LOG_BASE: return 0x554D;
|
||||
case UMP_LOG_BASE+1: return 3;
|
||||
case UMP_LOG_BASE+2: return ump_source ? 3 : ump_state;
|
||||
case UMP_LOG_BASE+3: return ump_source ? ump_archive_count : ump_count;
|
||||
case UMP_LOG_BASE+4: return UMP_LOG_WORDS;
|
||||
case UMP_LOG_BASE+5: return UMP_LOG_CAPACITY;
|
||||
case UMP_LOG_BASE+6: return ump_period;
|
||||
case UMP_LOG_BASE+7: return (unsigned int)ump_time;
|
||||
case UMP_LOG_BASE+8: return (unsigned int)(ump_time >> 16);
|
||||
case UMP_LOG_BASE+9: return Desk;
|
||||
case UMP_LOG_BASE+10: return Mode;
|
||||
case UMP_LOG_BASE+11: return (unsigned int)READY_FREQ;
|
||||
case UMP_LOG_BASE+12: return ump_generation;
|
||||
case UMP_LOG_BASE+13: return ump_archive_count;
|
||||
case UMP_LOG_BASE+14: return ump_post;
|
||||
case UMP_LOG_BASE+15: return ump_state;
|
||||
}
|
||||
if (address >= UMP_LOG_DATA && address < UMP_LOG_DATA+120 && (ump_source || ump_state != 1)) {
|
||||
offset = address - UMP_LOG_DATA;
|
||||
return ump_word(ump_source, ump_cursor + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS);
|
||||
}
|
||||
/* Ïîñëåäíèå òðè çàïèñè äëÿ îíëàéí-ãðàôèêà, áåç îñòàíîâêè è áåç
|
||||
* èçìåíåíèÿ êóðñîðà àðõèâíîãî ÷òåíèÿ. Ïåðâûå äâà ñëîâà — èõ íîìåð. */
|
||||
if (address >= UMP_LOG_LIVE && address < UMP_LOG_LIVE+124) {
|
||||
count = ump_count < UMP_LOG_LIVE_RECORDS ? ump_count : UMP_LOG_LIVE_RECORDS;
|
||||
first = ump_sequence - count;
|
||||
offset = address - UMP_LOG_LIVE;
|
||||
if (offset == 0) return (unsigned int)first;
|
||||
if (offset == 1) return (unsigned int)(first >> 16);
|
||||
if (offset == 2) return count;
|
||||
if (offset == 3) return ump_generation;
|
||||
offset -= 4;
|
||||
if (offset / UMP_LOG_WORDS < count)
|
||||
return ump_word(0, ump_count - count + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -109,8 +109,6 @@ void main()
|
||||
|
||||
while(1)
|
||||
{
|
||||
/* Чтение логгера по CAN не блокирует цикл управления. */
|
||||
UMP_CAN_service();
|
||||
if(CanGO)
|
||||
{
|
||||
CanGO=0;
|
||||
@@ -199,9 +197,6 @@ void main()
|
||||
if(!IMPowse) { clear_START_DPTB(); clear_STOP_DPTB(); }
|
||||
}
|
||||
|
||||
/* Снимок после обновления входов и формирования пусковых выходов. */
|
||||
ump_log_io();
|
||||
|
||||
for(i=0;i<2;i++)
|
||||
{
|
||||
if(i) rs = &rs_a;
|
||||
|
||||
@@ -151,8 +151,6 @@ interrupt void cpu_timer1_isr_SENS(void)
|
||||
if(Desk==dsk_LOAD)
|
||||
{
|
||||
Load_runner();
|
||||
/* База времени 1 мс; снимок содержит результат текущего шага ЦАП. */
|
||||
ump_log_tick();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#include "spise2p.h"
|
||||
|
||||
#include "caliber.h"
|
||||
#include "log_to_mem.h"
|
||||
#include "../../../../templates/c/set-protocol/ports/tms320f28335/ump_tms28335.h"
|
||||
|
||||
int modbus[ANSWER_LEN+1];
|
||||
unsigned int param[ANSWER_LEN+1];
|
||||
@@ -184,52 +182,15 @@ void Save_params()
|
||||
/***************************************************************/
|
||||
/***************************************************************/
|
||||
|
||||
static void modbus_exception(RS_DATA *rs_arr, unsigned int function, unsigned int error)
|
||||
{
|
||||
unsigned int crc;
|
||||
rs_arr->buffer[0] = CNTRL_ADDR;
|
||||
rs_arr->buffer[1] = function | 0x80;
|
||||
rs_arr->buffer[2] = error;
|
||||
crc = get_crc_16(0xFFFF, rs_arr->buffer, 3);
|
||||
rs_arr->buffer[3] = LOBYTE(crc); rs_arr->buffer[4] = HIBYTE(crc);
|
||||
rs_arr->flag_TIMEOUT_to_Send = true;
|
||||
RS_Send(rs_arr, rs_arr->buffer, 5);
|
||||
}
|
||||
|
||||
/* UART parser has already validated CRC and accepted the device address. */
|
||||
static int receive_ump(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned int address, value, saved, length, count, error;
|
||||
uint16_t words[UMP_MAX_WORDS];
|
||||
address = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3];
|
||||
if (address < UMP_BASE) return 0;
|
||||
value = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5];
|
||||
saved = __disable_interrupts();
|
||||
count = ump_tms28335_capture(rs_arr->RS_Header[1], address, value, words, &error);
|
||||
__restore_interrupts(saved);
|
||||
length = ump_rtu_encode(CNTRL_ADDR, rs_arr->RS_Header[1], error,
|
||||
words, count, rs_arr->buffer, MAX_SEND_LENGTH);
|
||||
if (length) {
|
||||
rs_arr->flag_TIMEOUT_to_Send = true;
|
||||
RS_Send(rs_arr, rs_arr->buffer, length);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ReceiveCommandModbus3(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned int crc, Address_MB, Length_MB, i, value;
|
||||
if (receive_ump(rs_arr)) return;
|
||||
unsigned int crc, Address_MB, Length_MB, i;
|
||||
|
||||
// ïîëó÷èëè íà÷àëüíûé àäðåñ ÷òåíèà
|
||||
Address_MB = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3];
|
||||
Address_MB =/*(rs_arr->RS_Header[2] << 8) |*/ rs_arr->RS_Header[3];
|
||||
|
||||
// ïîëó÷èëè êîëè÷åñòâî ñëîâ äàííûõ
|
||||
Length_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5];
|
||||
if (!Length_MB || Length_MB > 125 ||
|
||||
!(Address_MB < ANSWER_LEN && Length_MB <= ANSWER_LEN-Address_MB)) {
|
||||
modbus_exception(rs_arr, CMD_MODBUS_3, 2); return;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Îòñûëêà
|
||||
@@ -239,13 +200,10 @@ void ReceiveCommandModbus3(RS_DATA *rs_arr)
|
||||
rs_arr->buffer[1] = CMD_MODBUS_3;
|
||||
rs_arr->buffer[2] = Length_MB*2;
|
||||
|
||||
/* Çàùèùàåì öåëîñòíîñòü îäíîãî ñíèìêà/áëîêà; ïåðåäà÷à UART èä¸ò óæå
|
||||
* ñ ðàçðåø¸ííûìè ïðåðûâàíèÿìè è íå çàäåðæèâàåò èçìåðåíèå/óïðàâëåíèå. */
|
||||
for (i=0;i<Length_MB;i++)
|
||||
{
|
||||
value = modbus[Address_MB+i];
|
||||
rs_arr->buffer[3+i*2] = (value >> 8) & 0xFF;
|
||||
rs_arr->buffer[3+i*2+1] = value & 0xFF;
|
||||
rs_arr->buffer[3+i*2 ]=(Modbus[Address_MB+i].byt.byte_hi);
|
||||
rs_arr->buffer[3+i*2+1]=(Modbus[Address_MB+i].byt.byte_lo);
|
||||
}
|
||||
|
||||
crc = 0xffff;
|
||||
@@ -260,10 +218,7 @@ void ReceiveCommandModbus3(RS_DATA *rs_arr)
|
||||
rs_arr->buffer[Length_MB*2+8] = 0;
|
||||
|
||||
rs_arr->flag_TIMEOUT_to_Send=true;
|
||||
/* Ðàñøèðåíèå ëîããåðà îòâå÷àåò òî÷íûì êàäðîì Modbus áåç õâîñòîâûõ
|
||||
* íóëåé: îíè èíà÷å ïîïàëè áû â íà÷àëî îòâåòà ñëåäóþùåãî áëîêà GUI.
|
||||
* Èñòîðè÷åñêèé ôîðìàò òåõíîëîãè÷åñêèõ ðåãèñòðîâ îñòàâëåí ïðåæíèì. */
|
||||
RS_Send(rs_arr, rs_arr->buffer, Length_MB*2+8);
|
||||
RS_Send(rs_arr, rs_arr->buffer, Length_MB*2+8);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -271,7 +226,6 @@ void ReceiveCommandModbus3(RS_DATA *rs_arr)
|
||||
void ReceiveCommandModbus6(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned int Address_MB, Data_MB, i;
|
||||
if (receive_ump(rs_arr)) return;
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Îòñûëêà
|
||||
@@ -282,15 +236,12 @@ void ReceiveCommandModbus6(RS_DATA *rs_arr)
|
||||
|
||||
|
||||
// ïîëó÷èëè íà÷àëüíûé àäðåñ çàïèñè
|
||||
Address_MB = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3];
|
||||
Address_MB = (/*(rs_arr->RS_Header[2] << 8) | */rs_arr->RS_Header[3]);
|
||||
|
||||
// ïîëó÷èëè ñëîâî äàííûõ
|
||||
Data_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5];
|
||||
|
||||
if (Address_MB < ANSWER_LEN) {
|
||||
Modbus[Address_MB].all = Data_MB;
|
||||
if (Address_MB == 127) ump_log_rs();
|
||||
} else { modbus_exception(rs_arr, CMD_MODBUS_6, 2); return; }
|
||||
Modbus[Address_MB].all = Data_MB;
|
||||
|
||||
rs_arr->flag_TIMEOUT_to_Send=true;
|
||||
RS_Send(rs_arr, rs_arr->buffer, 10);
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
/* Build the canonical sources directly; do not copy their implementations. */
|
||||
#include "../../../../templates/c/set-protocol/src/ump_protocol.c"
|
||||
#include "../../../../templates/c/set-protocol/ports/tms320f28335/ump_tms28335.c"
|
||||
@@ -1,3 +1,16 @@
|
||||
/*=================================================================
|
||||
File name : SPISE2PD.C
|
||||
|
||||
Originator : Settu Duraisamy
|
||||
C2000 Applications Team
|
||||
Texas Instruments
|
||||
|
||||
Description : This file contains the SPI bus Serial EEPROM driver
|
||||
implemented using Virtual SPI driver
|
||||
|
||||
Date : 6/30/2003 (DD/MM/YYYY)
|
||||
====================================================================*/
|
||||
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
|
||||
#include "spise2p.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
******************************************************************************
|
||||
TMS320C2000 Linker PC v22.6.1
|
||||
******************************************************************************
|
||||
>> Linked Fri Sep 18 22:12:13 2026
|
||||
>> Linked Tue Sep 22 07:49:31 2026
|
||||
|
||||
OUTPUT FILE NAME: <C:/Dima/Project/Balsam_167/UKSSTMS320F28335/../bin/UKSSTMS320F28335.out>
|
||||
ENTRY POINT SYMBOL: "_c_int00" address: 0000b198
|
||||
|
||||
@@ -40,13 +40,12 @@ Source="Source\Internal\pulto.c"
|
||||
Source="Source\Internal\RS485.c"
|
||||
Source="Source\Internal\spise2p.c"
|
||||
Source="Source\Internal\tools.c"
|
||||
Source="Source\Internal\shared_ump.c"
|
||||
Source="F28335.cmd"
|
||||
Source="Source\External\v120\DSP2833x_headers\cmd\DSP2833x_Headers_nonBIOS.cmd"
|
||||
|
||||
["Debug" Settings]
|
||||
FinalBuildCmd=$(Proj_dir)\bin\hex2000.exe $(Proj_dir)\bin\UKSSTMS320F28335.out -boot -sci8 -map $(Proj_dir)\bin\UKSSTMS320F28335.map -o $(Proj_dir)\bin\UKSSTMS320F28335.hex -i
|
||||
FinalBuildCmd=cmd /c ""$(Proj_dir)\build_bin.bat""
|
||||
FinalBuildCmd=$(Proj_dir)\bin\hex2000.exe $(Proj_dir)\bin\UKSSTMS320F28335.out -boot -sci8 -map $(Proj_dir)\bin\UKSSTMS320F28335.map -o $(Proj_dir)\bin\UKSSTMS320F28335.bin -b
|
||||
|
||||
["Compiler" Settings: "Debug"]
|
||||
Options=-g -pdsw225 -o1 -fr"$(Proj_dir)\Debug" -fs"$(Proj_dir)\Asm" -i"$(Proj_dir)\Source\External\v120\DSP2833x_headers\include" -i"$(Proj_dir)\Source\Internal\Include" -i"$(Proj_dir)\Source\External\v120\DSP2833x_common\include" -d"_DEBUG" -d"LARGE_MODEL" -md -ml -v28 --float_support=fpu32
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
# Результаты сборки
|
||||
|
||||
После сборки Debug в `Bin` создаётся файл
|
||||
`UKSSTMS320F28335_<commit>.bin`, где `<commit>` — короткий хеш текущего
|
||||
коммита Git (не менее 8 символов). HEX сохраняет прежнее имя.
|
||||
|
||||
BIN создаётся скриптом `build_bin.bat`; Git должен быть доступен в `PATH`
|
||||
процесса CCS. Если определить коммит не удалось, сборка завершается ошибкой.
|
||||
При наличии незакоммиченных правок хеш обозначает HEAD и не описывает эти правки.
|
||||
@@ -23,11 +23,12 @@ shift
|
||||
goto process_arg
|
||||
:end_process_arg
|
||||
|
||||
pushd "%SRC_ROOT%\Bin" || exit /b 1
|
||||
hex2000.exe UKSSTMS320F28335.out -boot -sci8 -map UKSSTMS320F28335.map -o UKSSTMS320F28335.hex -i
|
||||
set "BUILD_RESULT=%errorlevel%"
|
||||
popd
|
||||
if not "%BUILD_RESULT%"=="0" exit /b %BUILD_RESULT%
|
||||
echo. > temp_postBuildStep_Debug.bat
|
||||
|
||||
call "%SRC_ROOT%\build_bin.bat"
|
||||
exit /b %errorlevel%
|
||||
echo "%SRC_ROOT%\Bin\hex2000.exe" "%SRC_ROOT%\Bin\UKSSTMS320F28335.out" -boot -sci8 -map "%SRC_ROOT%\Bin\UKSSTMS320F28335.map" -o "%SRC_ROOT%\Bin\UKSSTMS320F28335.hex" -i >> temp_postBuildStep_Debug.bat
|
||||
echo "%SRC_ROOT%\Bin\hex2000.exe" "%SRC_ROOT%\Bin\UKSSTMS320F28335.out" -boot -sci8 -map "%SRC_ROOT%\Bin\UKSSTMS320F28335.map" -o "%SRC_ROOT%\Bin\UKSSTMS320F28335.bin" -b >> temp_postBuildStep_Debug.bat
|
||||
|
||||
call temp_postBuildStep_Debug.bat
|
||||
del temp_postBuildStep_Debug.bat
|
||||
|
||||
endlocal
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set "SRC_ROOT=%~dp0"
|
||||
set "GIT_COMMIT="
|
||||
|
||||
for /f "delims=" %%H in ('git -C "%SRC_ROOT%." rev-parse --short^=8 HEAD') do set "GIT_COMMIT=%%H"
|
||||
if not defined GIT_COMMIT (
|
||||
echo ERROR: Cannot determine the Git commit. Make Git available in PATH. 1>&2
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
pushd "%SRC_ROOT%Bin" || exit /b 1
|
||||
hex2000.exe UKSSTMS320F28335.out -boot -sci8 -map UKSSTMS320F28335.map -o UKSSTMS320F28335_%GIT_COMMIT%.bin -b
|
||||
set "BUILD_RESULT=%errorlevel%"
|
||||
popd
|
||||
exit /b %BUILD_RESULT%
|
||||
@@ -1,112 +0,0 @@
|
||||
#include "../../Source/Internal/log_to_mem.c"
|
||||
#include "../../Source/Internal/Include/ump_can_protocol.h"
|
||||
struct mock_gpio GpioDataRegs;
|
||||
int READY = 1, Desk = 6, Mode = 5;
|
||||
int modbus[128];
|
||||
int CanTimeOutErrorTR;
|
||||
unsigned long IMPowse, WAKEpowse;
|
||||
unsigned int ADC_table[4];
|
||||
#define CHECK(x) if (!(x)) return __LINE__
|
||||
|
||||
/* Возвращаем номер строки при ошибке, ноль при успехе; CRT не требуется. */
|
||||
__declspec(dllexport) int run_tests(void)
|
||||
{
|
||||
unsigned int i, generation, archived, error, length;
|
||||
uint16_t reply[UMP_CAN_MAX_WORDS];
|
||||
unsigned long sequence;
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE+1, 0));
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE+1, 1001));
|
||||
CHECK(ump_log_write(UMP_LOG_BASE+1, 1));
|
||||
modbus[127] = 0x80;
|
||||
modbus[0x50] = 6; modbus[0x51] = 16;
|
||||
modbus[0x7B] = 1234; modbus[0x1C] = 160;
|
||||
/* PM67 reception is independent of recording; all three CAN slots work. */
|
||||
ump_log_can(0x8000U | 305U, 0xFEDCU, 0, 0);
|
||||
ump_log_can(0x4000U | 7U, 0, 456, 0);
|
||||
CHECK(ump_pm67_voltage[0] == 0xFEDCU && ump_pm67_voltage[1] == 456);
|
||||
ump_log_can(305U, 1, 2, 3); /* Masked-out word must not overwrite. */
|
||||
ump_log_can(0x2000U | 303U, 0, 0, 123);
|
||||
ump_log_can(0x2000U | 6U, 0, 0, 789);
|
||||
CHECK(ump_pm67_voltage[0] == 123 && ump_pm67_voltage[1] == 789);
|
||||
ump_log_can(0x8000U | 306U, 999, 0, 0); /* Not a one-based CAN address. */
|
||||
CHECK(ump_log_write(UMP_LOG_BASE, 1));
|
||||
CHECK(ump_word(0, 0, 40) == 123 && ump_word(0, 0, 41) == 789);
|
||||
CHECK(2UL * UMP_LOG_CAPACITY * UMP_LOG_WORDS <= LOG_PAGE_LEN);
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE, 1));
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE+1, 20));
|
||||
for (i=0; i<900; i++) ump_log_tick();
|
||||
CHECK(ump_count == UMP_LOG_CAPACITY);
|
||||
CHECK(ump_word(0, 0, 0) == 901-UMP_LOG_CAPACITY);
|
||||
CHECK(ump_word(0, UMP_LOG_CAPACITY-1, 0) == 900);
|
||||
CHECK(ump_word(0, 0, 8) == 1234);
|
||||
CHECK(ump_word(0, 0, 24) == 6);
|
||||
/* Короткая CAN-команда должна остаться отдельным событием. */
|
||||
modbus[127] = 0x40;
|
||||
ump_log_can(0x807F, 0x40, 0, 0);
|
||||
CHECK(ump_post == 1000);
|
||||
CHECK(ump_word(0, ump_count-1, 2) == 0x102);
|
||||
CHECK(ump_word(0, ump_count-1, 18) == 0x807F);
|
||||
for (i=0; i<999; i++) ump_log_tick();
|
||||
CHECK(ump_generation == 0);
|
||||
ump_log_tick();
|
||||
CHECK(ump_generation == 1);
|
||||
CHECK(ump_archive_count == UMP_LOG_CAPACITY);
|
||||
CHECK(ump_word(1, UMP_LOG_CAPACITY/2-1, 2) == 0x102);
|
||||
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 2) == 0x205);
|
||||
CHECK(ump_count == 0 && ump_state == 1);
|
||||
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 40) == 123);
|
||||
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 41) == 789);
|
||||
ump_log_can(0x8000U | 305U, 999, 0, 0);
|
||||
CHECK(ump_word(0, ump_count-1, 40) == 999);
|
||||
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 40) == 123);
|
||||
generation = ump_generation;
|
||||
archived = ump_word(1, UMP_LOG_CAPACITY-1, 0);
|
||||
sequence = ump_sequence;
|
||||
for (i=0; i<200; i++) ump_log_tick();
|
||||
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 0) == archived);
|
||||
CHECK(ump_generation == generation);
|
||||
CHECK(ump_sequence == sequence + 200);
|
||||
CHECK(ump_log_read(UMP_LOG_LIVE+2) == UMP_LOG_LIVE_RECORDS);
|
||||
CHECK(ump_log_read(UMP_LOG_LIVE+4) == ump_time-(UMP_LOG_LIVE_RECORDS-1));
|
||||
CHECK(ump_log_write(UMP_LOG_BASE+3, 1));
|
||||
CHECK(ump_log_write(UMP_LOG_BASE+2, UMP_LOG_CAPACITY-1));
|
||||
CHECK(ump_log_read(UMP_LOG_DATA) == archived);
|
||||
CHECK(ump_log_read(UMP_LOG_DATA+UMP_LOG_WORDS) == 0);
|
||||
CHECK(!ump_log_write(UMP_LOG_BASE+2, UMP_LOG_CAPACITY));
|
||||
CHECK(ump_log_write(UMP_LOG_BASE, 0));
|
||||
sequence = ump_sequence;
|
||||
ump_log_tick(); ump_log_io(); ump_log_can(1,2,3,4);
|
||||
CHECK(sequence == ump_sequence);
|
||||
CHECK(ump_log_write(UMP_LOG_BASE, 1));
|
||||
CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 0) == archived);
|
||||
/* Новый пуск и спад start без reset также фиксируют отключение. */
|
||||
modbus[127] = 0x80; ump_log_rs();
|
||||
modbus[127] = 0; ump_log_rs();
|
||||
CHECK(ump_post == 1000);
|
||||
for (i=0; i<1000; i++) ump_log_tick();
|
||||
CHECK(ump_generation == generation+1);
|
||||
/* CAN читает те же регистры и формирует цельный снимок из 124 слов.
|
||||
* Запись по старым технологическим адресам через сервис запрещена. */
|
||||
length = ump_can_prepare(3, UMP_LOG_BASE, 16, reply, &error);
|
||||
CHECK(!error && length == 16 && reply[0] == 0x554D && reply[1] == 3);
|
||||
length = ump_can_prepare(3, UMP_LOG_LIVE, 124, reply, &error);
|
||||
CHECK(!error && length == 124);
|
||||
CHECK(reply[2] <= UMP_LOG_LIVE_RECORDS);
|
||||
for (i=4+reply[2]*UMP_LOG_WORDS; i<124; i++) CHECK(reply[i] == 0);
|
||||
length = ump_can_prepare(3, UMP_LOG_DATA, 84, reply, &error);
|
||||
CHECK(!error && length == 84);
|
||||
length = ump_can_prepare(3, UMP_LOG_DATA, 42, reply, &error);
|
||||
CHECK(!error && length == 42);
|
||||
ump_can_prepare(3, UMP_LOG_LIVE, 126, reply, &error);
|
||||
CHECK(error == 2);
|
||||
ump_can_prepare(6, 127, 0x80, reply, &error);
|
||||
CHECK(error == 2 && modbus[127] == 0);
|
||||
length = ump_can_prepare(6, UMP_LOG_BASE, 0, reply, &error);
|
||||
CHECK(!error && length == 2 && reply[0] == UMP_LOG_BASE && reply[1] == 0);
|
||||
CHECK(ump_state == 3);
|
||||
ump_can_prepare(6, UMP_LOG_BASE+1, 0, reply, &error);
|
||||
CHECK(error == 3);
|
||||
ump_can_prepare(99, UMP_LOG_BASE, 16, reply, &error);
|
||||
CHECK(error == 1);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
"""Сборка и запуск исходного регистратора с подменой GPIO/IRQ на Windows.
|
||||
|
||||
Нужны Clang и lld-link в PATH. Проверяется алгоритм, но не ABI и тайминги TI.
|
||||
DLL создаётся во временной папке; исходные .out/.hex прошивки не затрагиваются.
|
||||
"""
|
||||
import ctypes
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
root = Path(__file__).resolve().parents[2]
|
||||
with tempfile.TemporaryDirectory(prefix='ump-recorder-') as directory:
|
||||
library = Path(directory) / 'recorder_test.dll'
|
||||
subprocess.run([
|
||||
'clang', '-shared', '-nostdlib', '-fuse-ld=lld',
|
||||
'-Wl,/noentry,/nodefaultlib', '-Wno-unknown-pragmas', '-Wno-int-to-pointer-cast',
|
||||
'-Itests/ump_logger/stubs', '-ISource/Internal/Include',
|
||||
'tests/ump_logger/recorder_test.c', 'Source/Internal/shared_ump.c', '-o', str(library),
|
||||
], cwd=root, check=True)
|
||||
# Отдельный процесс освобождает DLL до удаления временной папки Windows.
|
||||
subprocess.run([
|
||||
os.sys.executable, '-c',
|
||||
'import ctypes,sys; r=ctypes.CDLL(sys.argv[1]).run_tests(); '
|
||||
'print("PASS" if r==0 else f"FAIL: C line {r}"); sys.exit(bool(r))',
|
||||
str(library),
|
||||
], check=True)
|
||||
@@ -1 +0,0 @@
|
||||
extern unsigned int ADC_table[4];
|
||||
@@ -1 +0,0 @@
|
||||
extern unsigned long IMPowse, WAKEpowse;
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef UMP_TEST_DEVICE_H
|
||||
#define UMP_TEST_DEVICE_H
|
||||
struct mock_bits { unsigned int GPIO3, GPIO6, GPIO8, GPIO11, GPIO58, GPIO62; };
|
||||
struct mock_reg { struct mock_bits bit; };
|
||||
struct mock_gpio { struct mock_reg GPADAT, GPBDAT; };
|
||||
extern struct mock_gpio GpioDataRegs;
|
||||
static unsigned int __disable_interrupts(void) { return 0; }
|
||||
static void __restore_interrupts(unsigned int saved) { (void)saved; }
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
/* Подмена зависимостей для проверки регистратора без платы. */
|
||||
@@ -1 +0,0 @@
|
||||
/* Подмена зависимостей для проверки регистратора без платы. */
|
||||
@@ -1,2 +0,0 @@
|
||||
extern int READY, Desk, Mode;
|
||||
#define READY_FREQ 1000
|
||||
@@ -1 +0,0 @@
|
||||
/* Подмена зависимостей для проверки регистратора без платы. */
|
||||
@@ -1,11 +0,0 @@
|
||||
extern int modbus[128];
|
||||
#define dsk_LOAD 6
|
||||
#define Commands modbus[127]
|
||||
#define sens_data (modbus+24)
|
||||
#define DAC_go modbus[0x50]
|
||||
#define DAC_stop modbus[0x51]
|
||||
#define DAC_min() modbus[0x79]
|
||||
#define DAC_max() modbus[0x78]
|
||||
#define DAC_cal() modbus[0x7A]
|
||||
#define DAC_04 modbus[0x6F]
|
||||
#define DAC_20 modbus[0x6E]
|
||||
@@ -1 +0,0 @@
|
||||
/* Подмена зависимостей для проверки регистратора без платы. */
|
||||
@@ -1,3 +0,0 @@
|
||||
/* Декларации TI-интринсиков только для проверки синтаксиса на компьютере. */
|
||||
unsigned int __disable_interrupts(void);
|
||||
void __restore_interrupts(unsigned int saved);
|
||||
Reference in New Issue
Block a user