Update CCS12 peripheral firmware and documentation
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
/Debug/
|
||||
/Release/
|
||||
/UKSSTMS320F28335.CS_/
|
||||
/Doc/build/
|
||||
/Doc/.tools/
|
||||
|
||||
167
CAN_ADDRESS_MAP.md
Normal file
167
CAN_ADDRESS_MAP.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# Карта 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 основного проекта частично не совпадают с текущими
|
||||
константами устройств, поэтому менять адреса только по комментариям нельзя.
|
||||
|
||||
67
Doc/Doxyfile
Normal file
67
Doc/Doxyfile
Normal file
@@ -0,0 +1,67 @@
|
||||
# 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
|
||||
337
Doc/PHASE_BREAK_ERROR_FLOW.md
Normal file
337
Doc/PHASE_BREAK_ERROR_FLOW.md
Normal file
@@ -0,0 +1,337 @@
|
||||
@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,3 +1,5 @@
|
||||
@page phase_comparison_balsam Сравнение фазовой части Balsam 165 и Balsam 167
|
||||
|
||||
# Сравнение фазовой части Balsam 165 и Balsam 167
|
||||
|
||||
## Область сравнения
|
||||
@@ -1,3 +1,5 @@
|
||||
@page phase_voltage_calculation Расчёт входных фаз, диагностика обрыва и уровни напряжения
|
||||
|
||||
# Расчёт входных фаз, диагностика обрыва и уровни напряжения
|
||||
|
||||
Документ составлен по исходникам прошивки Balsam 167 и карте регистров
|
||||
@@ -1,3 +1,5 @@
|
||||
@page phase_voltage_weak_points Слабые места расчёта фаз и контроля напряжения
|
||||
|
||||
# Слабые места расчёта фаз и контроля напряжения
|
||||
|
||||
Документ относится к алгоритмам из `Source/Internal/measure.c`, структуре
|
||||
16
Doc/README.md
Normal file
16
Doc/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Документация 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
|
||||
```
|
||||
@@ -25,5 +25,29 @@
|
||||
- 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`;
|
||||
перенос репозитория в другой каталог не требует изменения настроек.
|
||||
10
Doc/api-unavailable.html
Normal file
10
Doc/api-unavailable.html
Normal file
File diff suppressed because one or more lines are too long
723
Doc/api.dox
Normal file
723
Doc/api.dox
Normal file
@@ -0,0 +1,723 @@
|
||||
/**
|
||||
@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 Описание адреса, буфера и длины.
|
||||
*/
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
64
Doc/build.bat
Normal file
64
Doc/build.bat
Normal file
@@ -0,0 +1,64 @@
|
||||
@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
|
||||
69
Doc/files.dox
Normal file
69
Doc/files.dox
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
@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
Normal file
117
Doc/index.html
Normal file
File diff suppressed because one or more lines are too long
70
Doc/mainpage.md
Normal file
70
Doc/mainpage.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# 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,
|
||||
частоты тактирования и выбранной роли платы.
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @file ADC.c
|
||||
* @brief Сбор аналоговых отсчётов и первичная обработка измерительных каналов.
|
||||
*
|
||||
* Модуль настраивает АЦП TMS320F28335 и обслуживает прерывание окончания
|
||||
* преобразования. Отсчёты накапливаются в ADC_table и adc_table_lem, после
|
||||
* чего передаются измерительному контуру. Обработчик работает в контексте
|
||||
* прерывания, поэтому его время выполнения ограничено частотой дискретизации,
|
||||
* а разделяемые таблицы должны читаться основным циклом согласованно.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||||
#include "DSP2833x_Examples.h" // DSP281x Examples Include File
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
@@ -14,20 +24,37 @@
|
||||
|
||||
#include "peripher.h"
|
||||
|
||||
/** @brief Сырые отсчёты четырёх силовых каналов, передаваемые Current_count(). */
|
||||
Uint16 adc_table_lem[4];
|
||||
Uint16 ADC_table[28]; // Ïîòîìó ÷òî +4 êàëèáð
|
||||
/** @brief Фильтрованные значения всех рабочих и калибровочных каналов. */
|
||||
Uint16 ADC_table[28]; // Потому что +4 калибр
|
||||
/** @brief Число допустимых отсчётов прошлого окна для контроля выбросов. */
|
||||
Uint16 prev_ok[28];
|
||||
|
||||
/** @brief Параметры временного мультиплексирования термоканалов в тиках АЦП. */
|
||||
unsigned int COUNT_ONE_CANAL;
|
||||
unsigned int COUNT_DISCHARGE;
|
||||
unsigned int COUNT_TRANSICIA;
|
||||
unsigned int FILTER_CLIP;
|
||||
|
||||
/** @brief Счётчик прогрева измерений и его начальная длительность. */
|
||||
long WAKE, WAKE_TIME;
|
||||
|
||||
// Prototype statements for functions found within this file.
|
||||
/** @brief ISR конца последовательности ADC SEQ1. */
|
||||
interrupt void adc_isr(void);
|
||||
|
||||
/**
|
||||
* @brief Полностью настраивает АЦП, ePWM-триггер и расписание каналов платы.
|
||||
*
|
||||
* @details По Desk выбирается физическая последовательность входов ADCINA/B.
|
||||
* ePWM1 затем запускает SEQ1 с частотой ADC_FREQ. Для мультиплексированных
|
||||
* термоканалов рассчитываются интервалы разряда, переходного процесса и окна
|
||||
* накопления; WAKE подавляет использование неустановившихся фильтров при старте.
|
||||
*
|
||||
* @pre Desk и признаки TermoAD/TermoSW определены функцией get_Mode().
|
||||
* @post ADCINT подключён к adc_isr(), SEQ1 и ePWM1 запущены.
|
||||
*/
|
||||
void setup_adc()
|
||||
{
|
||||
long CLKdiv,HSPCLKdiv,Rate;
|
||||
@@ -59,21 +86,23 @@ void setup_adc()
|
||||
// EINT; // Enable Global interrupt INTM
|
||||
// ERTM; // Enable Global realtime interrupt DBGM
|
||||
|
||||
/* Исключаем использование остаточных данных до первого полного цикла АЦП. */
|
||||
for(i=0;i<28;i++)
|
||||
ADC_table[i]=
|
||||
prev_ok[i] = 0;
|
||||
|
||||
/* Каждая роль платы имеет собственную разводку входов и длину sequencer. */
|
||||
// Configure ADC
|
||||
if(Desk==dsk_LOAD)
|
||||
{
|
||||
AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x0005; // Setup 2 conv's on SEQ1
|
||||
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x3; // òåìïåðàòóðà (êîòîðîé íåò)
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // îìåãà
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x5; // íàïðóãà 1
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x4; // íàïðóãà 2
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x7; // òîê 1
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x2; // òîê 2
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x3; // температура (которой нет)
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // омега
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x5; // напруга 1
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x4; // напруга 2
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x7; // ток 1
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x2; // ток 2
|
||||
}
|
||||
|
||||
if(Desk==dsk_BKST)
|
||||
@@ -87,7 +116,7 @@ void setup_adc()
|
||||
if(Desk==dsk_COMM)
|
||||
{
|
||||
AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x0006; // Setup 2 conv's on SEQ1
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x5; // ñíà÷àëà òîæå áóäóò òåìïåðàòóðû
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x5; // сначала тоже будут температуры
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x4; // Setup ADCINA2 as 2nd SEQ1 conv.
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x7; // Setup ADCINA2 as 2nd SEQ1 conv.
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x2; // Setup ADCINA2 as 2nd SEQ1 conv.
|
||||
@@ -105,23 +134,23 @@ void setup_adc()
|
||||
if(Desk==dsk_SHKF)
|
||||
{
|
||||
AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x000F; // Setup 2 conv's on SEQ1
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x2; // 380Â Ô1
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x3; // 380Â Ô2
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x6; // 31Â Ô1
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0xC; // 31Â Ô2 ?
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0xA; // 31Â UC1
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0xB; // 31Â UC2
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x7; // 24Â ÏÓ
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x4; // 24Â ÏÓ
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x2; // 380В Ф1
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x3; // 380В Ф2
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x6; // 31В Ф1
|
||||
AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0xC; // 31В Ф2 ?
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0xA; // 31В UC1
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0xB; // 31В UC2
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x7; // 24В ПУ
|
||||
AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x4; // 24В ПУ
|
||||
|
||||
AdcRegs.ADCCHSELSEQ3.bit.CONV08 = 0x5; // 24Â ÏÊ áûëî 5
|
||||
AdcRegs.ADCCHSELSEQ3.bit.CONV09 = 0x1; // 15Â Äð
|
||||
AdcRegs.ADCCHSELSEQ3.bit.CONV10 = 0xE; // +24Â Äò
|
||||
AdcRegs.ADCCHSELSEQ3.bit.CONV11 = 0x0; // +24Â Äò
|
||||
AdcRegs.ADCCHSELSEQ4.bit.CONV12 = 0x8; // -24Â Äò áûëî 8
|
||||
AdcRegs.ADCCHSELSEQ3.bit.CONV08 = 0x5; // 24В ПК было 5
|
||||
AdcRegs.ADCCHSELSEQ3.bit.CONV09 = 0x1; // 15В Др
|
||||
AdcRegs.ADCCHSELSEQ3.bit.CONV10 = 0xE; // +24В Дт
|
||||
AdcRegs.ADCCHSELSEQ3.bit.CONV11 = 0x0; // +24В Дт
|
||||
AdcRegs.ADCCHSELSEQ4.bit.CONV12 = 0x8; // -24В Дт было 8
|
||||
|
||||
AdcRegs.ADCCHSELSEQ4.bit.CONV13 = 0xF;//0xF; // ÄÒ° 1
|
||||
AdcRegs.ADCCHSELSEQ4.bit.CONV14 = 0xD;//0xD; // ÄÒ° 2
|
||||
AdcRegs.ADCCHSELSEQ4.bit.CONV13 = 0xF;//0xF; // ДТ° 1
|
||||
AdcRegs.ADCCHSELSEQ4.bit.CONV14 = 0xD;//0xD; // ДТ° 2
|
||||
AdcRegs.ADCCHSELSEQ4.bit.CONV15 = 0x9;//0x9;
|
||||
}
|
||||
|
||||
@@ -152,6 +181,7 @@ void setup_adc()
|
||||
if(EPwm1Regs.TBCTL.bit.HSPCLKDIV) HSPCLKdiv = 2*EPwm1Regs.TBCTL.bit.HSPCLKDIV;
|
||||
else HSPCLKdiv = 1;
|
||||
|
||||
/* Период ePWM получается из реальной частоты TBCLK после обоих делителей. */
|
||||
Rate = (SYSCLKOUT/(HSPCLKdiv*CLKdiv))/ADC_FREQ;
|
||||
|
||||
EPwm1Regs.TBPRD = Rate; // Set period for ePWM1
|
||||
@@ -195,6 +225,18 @@ void setup_adc()
|
||||
WAKE = WAKE_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Забирает результаты SEQ1, фильтрует их и запускает расчёт величин.
|
||||
*
|
||||
* @details Сначала разрешает вложенные прерывания согласно программному
|
||||
* приоритету PIE. В зависимости от аппаратной роли обрабатывает силовые каналы,
|
||||
* нагрузочный аналоговый вход, шкафные каналы либо мультиплексированные
|
||||
* термодатчики. Выброс принимается только при прохождении FILTER_CLIP; во время
|
||||
* WAKE фильтр обучается, но наружу выдаётся непосредственный отсчёт.
|
||||
*
|
||||
* @note На общем выходе fin всегда сбрасывает SEQ1, подтверждает PIE и
|
||||
* восстанавливает сохранённую маску PIEIER1, включая путь раннего выхода.
|
||||
*/
|
||||
interrupt void adc_isr(void)
|
||||
{
|
||||
static int cownt_one_canal=0;
|
||||
@@ -214,6 +256,7 @@ interrupt void adc_isr(void)
|
||||
PieCtrlRegs.PIEACK.all = 0xFFFF; // Enable PIE interrupts
|
||||
EINT;
|
||||
|
||||
/* До READY обслуживается только обязательное завершение аппаратного цикла. */
|
||||
if(WAKE) WAKE--;
|
||||
if(!READY) goto fin;
|
||||
|
||||
@@ -246,7 +289,7 @@ interrupt void adc_isr(void)
|
||||
{
|
||||
if (++cownt_cans>=tpl_cans) cownt_cans=0;
|
||||
|
||||
// Èìåííî çäåñü íåò äûð
|
||||
// Именно здесь нет дыр
|
||||
// if(sens_type[cownt_cans])
|
||||
{
|
||||
i++;
|
||||
@@ -256,6 +299,7 @@ interrupt void adc_isr(void)
|
||||
else Power_count(cownt_cans);
|
||||
} } }
|
||||
|
||||
/* Программный мультиплексор: переключение, выдержка, накопление и расчёт. */
|
||||
if(TermoSW)
|
||||
{
|
||||
if(cownt_one_canal==COUNT_DISCHARGE)
|
||||
@@ -265,11 +309,12 @@ interrupt void adc_isr(void)
|
||||
if(TermoAD)
|
||||
{
|
||||
if(cownt_cans == TPL_CANS ) code_tpl_canal = TERMOPAIR-1;
|
||||
if(cownt_cans == TPL_CANS+1) code_tpl_canal = TERMOPAIR-2; // ïîòîìó ÷òî 300 è 400 íàîáîðîò
|
||||
if(cownt_cans == TPL_CANS+1) code_tpl_canal = TERMOPAIR-2; // потому что 300 и 400 наоборот
|
||||
}
|
||||
select_tpl_canal(code_tpl_canal);
|
||||
}
|
||||
|
||||
/* Отсчёты до окончания переходного процесса намеренно отбрасываются. */
|
||||
if(cownt_one_canal > COUNT_TRANSICIA)
|
||||
for(i=0;i<TermoSW;i++)
|
||||
{
|
||||
@@ -277,6 +322,7 @@ interrupt void adc_isr(void)
|
||||
|
||||
Temper = *(&AdcRegs.ADCRESULT0 + i) >>4;
|
||||
|
||||
/* Ограничитель защищает рекурсивный фильтр от одиночного выброса. */
|
||||
ok = abs(ADC_table[n]-Temper) < FILTER_CLIP;
|
||||
|
||||
if(ok) cwnt_ok[i]++;
|
||||
@@ -325,6 +371,7 @@ for(i=0;i<1;i++)
|
||||
|
||||
fin:
|
||||
|
||||
/* Единая эпилоговая секция обязательна и после goto при READY == 0. */
|
||||
// Reinitialize for next ADC sequence
|
||||
AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // Reset SEQ1
|
||||
AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; // Clear INT SEQ1 bit
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @file DAC.c
|
||||
* @brief Управление внешним ЦАП и формирование аналогового задания нагрузки.
|
||||
*
|
||||
* Формирует последовательный поток через GPIO, рассчитывает временные интервалы
|
||||
* относительно READY_FREQ и выдаёт нормированное значение Anal_output().
|
||||
* Линии CLK/CS/DATA управляются непосредственно, поэтому порядок переключений
|
||||
* и программные задержки являются частью аппаратного протокола и не должны
|
||||
* переставляться без проверки осциллографом.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
#include "filter_bat2.h"
|
||||
@@ -21,6 +31,10 @@ unsigned long WAKEpowse;
|
||||
unsigned long IMPowse;
|
||||
unsigned int period_dac, time_dac;
|
||||
|
||||
/**
|
||||
* @brief Переводит физические интервалы профиля нагрузки в тики READY_FREQ.
|
||||
* @post Обновлены WAKEpowse, period_dac и time_dac.
|
||||
*/
|
||||
void Setup_DAC_time(void)
|
||||
{
|
||||
WAKEpowse = 3L * DAC_FREQ +1;
|
||||
@@ -29,12 +43,14 @@ void Setup_DAC_time(void)
|
||||
time_dac = LOAD_TIME * DAC_FREQ;
|
||||
}
|
||||
|
||||
/** @brief Устанавливает логический уровень последовательной линии DATA ЦАП. */
|
||||
void dOUT(int x)
|
||||
{
|
||||
if(x) GpioDataRegs.GPBSET.bit.GPIO60=1;
|
||||
else GpioDataRegs.GPBCLEAR.bit.GPIO60=1;
|
||||
}
|
||||
|
||||
/** @brief Формирует короткую аппаратно-зависимую задержку между фронтами GPIO. */
|
||||
void wast()
|
||||
{
|
||||
int i;
|
||||
@@ -42,6 +58,11 @@ void wast()
|
||||
for(i=0;i<25;i++);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Последовательно передаёт одно управляющее слово во внешний ЦАП.
|
||||
* @param word Слово протокола, выдаваемое по DATA синхронно с CLK.
|
||||
* @note CS и CLK переключаются программно; порядок фронтов менять нельзя.
|
||||
*/
|
||||
void dSEND(unsigned int word)
|
||||
{
|
||||
int i;
|
||||
@@ -57,12 +78,20 @@ void dSEND(unsigned int word)
|
||||
dCS_1();
|
||||
}
|
||||
|
||||
/** @brief Устанавливает CS, CLK и DATA в безопасные уровни ожидания. */
|
||||
void Init_DAC(void)
|
||||
{
|
||||
dSEND(0x9002|0x0000);
|
||||
toggle_RES_OUT_1();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Масштабирует прикладное задание и отправляет код во внешний ЦАП.
|
||||
* @param vrot Требуемое значение в прикладных единицах.
|
||||
* @param maxx Значение полной шкалы; должно быть больше нуля.
|
||||
* @details Результат ограничивается аппаратным диапазоном перед формированием
|
||||
* управляющего слова, поэтому выход не переполняется при завышенном задании.
|
||||
*/
|
||||
void Anal_output(long vrot, long maxx)
|
||||
{
|
||||
long out;
|
||||
@@ -70,7 +99,7 @@ void Anal_output(long vrot, long maxx)
|
||||
|
||||
out = DAC_min() + vrot * DAC_max() / maxx - vrot * DAC_min() / maxx ;
|
||||
|
||||
x=0;// !x; тщетно бытие
|
||||
x=0;// !x; тщетно бытие
|
||||
|
||||
if(cCalibrDac) out=DAC_cal();
|
||||
|
||||
@@ -99,6 +128,11 @@ Log_to_mem(modbus[0x1D]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Выполняет очередной шаг временного профиля аналоговой нагрузки.
|
||||
* @details Использует IMPowse как фазу профиля и на границах интервалов
|
||||
* выбирает новое задание, передаваемое через Anal_output().
|
||||
*/
|
||||
void Load_runner()
|
||||
{
|
||||
static unsigned int count_dac=0, count_load=0, x=1;
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
/**
|
||||
* @file ADC.h
|
||||
* @brief Публичный интерфейс подсистемы АЦП.
|
||||
*
|
||||
* Экспортирует таблицы последних/накопленных отсчётов и временные признаки,
|
||||
* обновляемые ADC.c. Размеры массивов определены реализацией и аппаратной
|
||||
* разводкой; потребители должны использовать только известные индексы каналов.
|
||||
*/
|
||||
|
||||
extern Uint16 adc_table_lem[];
|
||||
extern Uint16 ADC_table[];
|
||||
|
||||
/** Инициализирует тактирование, последовательность каналов и прерывание АЦП. */
|
||||
void setup_adc(void);
|
||||
|
||||
/** Счётчик активности и его порог, используемые для контроля измерительного цикла. */
|
||||
extern long WAKE,WAKE_TIME;
|
||||
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
/**
|
||||
* @file DAC.h
|
||||
* @brief Интерфейс внешнего ЦАП и генератора задания нагрузки.
|
||||
*
|
||||
* Перед первым выводом требуется Init_DAC() и Setup_DAC_time(). Значение
|
||||
* Anal_output() масштабируется относительно maxx; maxx должен быть положительным.
|
||||
*/
|
||||
/** Выполняет очередной шаг временного профиля аналогового выхода нагрузки. */
|
||||
void Load_runner(void);
|
||||
/**
|
||||
* Выдаёт нормированное значение на ЦАП.
|
||||
* @param vrot Требуемая величина выхода.
|
||||
* @param maxx Полная шкала; должна быть больше нуля.
|
||||
*/
|
||||
void Anal_output(long vrot, long maxx);
|
||||
/** Переводит линии внешнего ЦАП в исходное состояние. */
|
||||
void Init_DAC(void);
|
||||
/** Пересчитывает интервалы ЦАП из READY_FREQ, DAC_FREQ и LOAD_TIME. */
|
||||
void Setup_DAC_time(void);
|
||||
|
||||
/** Внутренние счётчики профиля, обновляемые DAC.c. */
|
||||
extern unsigned long IMPowse;
|
||||
extern unsigned int period_dac, time_dac;
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file GPIO_table.h
|
||||
* @brief Таблицы направления и мультиплексирования GPIO для вариантов плат.
|
||||
*
|
||||
* Макросы сгруппированы по аппаратным исполнениям и напрямую соответствуют
|
||||
* выводам разъёмов. Значения 0/1 кодируют вход/выход либо выбранную функцию MUX.
|
||||
* Любое изменение требует сверки со схемой конкретной платы и package.h;
|
||||
* этот заголовок содержит конфигурацию, а не переносимую логику GPIO.
|
||||
*/
|
||||
#define COMM_gpio00_dir 0UL
|
||||
#define COMM_gpio01_dir 0UL
|
||||
#define COMM_gpio02_dir 0UL
|
||||
@@ -11,7 +20,7 @@
|
||||
#define COMM_gpio10_dir 0UL
|
||||
#define COMM_gpio11_dir 0UL
|
||||
|
||||
#define COMM_gpio19_dir 1UL // 63 — SPI
|
||||
#define COMM_gpio19_dir 1UL // 63 — SPI
|
||||
#define COMM_gpio20_dir 0UL // 64 2:9B mode 2
|
||||
#define COMM_gpio21_dir 0UL // 65 2:9A mode 4
|
||||
#define COMM_gpio22_dir 0UL // 66 2:12C mode 1
|
||||
@@ -23,7 +32,7 @@
|
||||
|
||||
#define COMM_gpio32_dir 1UL // 74 2:10B DIOD green
|
||||
#define COMM_gpio33_dir 0UL
|
||||
#define COMM_gpio34_dir 1UL // 142 — SCI
|
||||
#define COMM_gpio34_dir 1UL // 142 — SCI
|
||||
|
||||
#define COMM_gpio48_dir 1UL // 88 2:14C DIOD red
|
||||
#define COMM_gpio49_dir 1UL // 89 2:14B select
|
||||
@@ -54,7 +63,7 @@
|
||||
#define BKSD_gpio10_dir 0UL // 19 2:6C oil
|
||||
#define BKSD_gpio11_dir 1UL // 20 2:3C select
|
||||
|
||||
#define BKSD_gpio19_dir 1UL // 63 — SPI
|
||||
#define BKSD_gpio19_dir 1UL // 63 — SPI
|
||||
#define BKSD_gpio20_dir 0UL // 64 2:9B mode 2
|
||||
#define BKSD_gpio21_dir 0UL // 65 2:9A mode 4
|
||||
#define BKSD_gpio22_dir 0UL // 66 2:12C mode 1
|
||||
@@ -66,7 +75,7 @@
|
||||
|
||||
#define BKSD_gpio32_dir 1UL // 74 2:10B DIOD green
|
||||
#define BKSD_gpio33_dir 0UL
|
||||
#define BKSD_gpio34_dir 1UL // 142 — SCI
|
||||
#define BKSD_gpio34_dir 1UL // 142 — SCI
|
||||
|
||||
#define BKSD_gpio48_dir 1UL // 88 2:14C DIOD red
|
||||
#define BKSD_gpio49_dir 0UL // 89 2:14B input 2
|
||||
@@ -97,7 +106,7 @@
|
||||
#define BKST_gpio10_dir 0UL
|
||||
#define BKST_gpio11_dir 1UL // 20 2:3C select
|
||||
|
||||
#define BKST_gpio19_dir 1UL // 63 — SPI
|
||||
#define BKST_gpio19_dir 1UL // 63 — SPI
|
||||
#define BKST_gpio20_dir 0UL // 64 2:9B mode 2
|
||||
#define BKST_gpio21_dir 0UL // 65 2:9A mode 4
|
||||
#define BKST_gpio22_dir 0UL // 66 2:12C mode 1
|
||||
@@ -109,7 +118,7 @@
|
||||
|
||||
#define BKST_gpio32_dir 1UL // 74 2:10B DIOD green
|
||||
#define BKST_gpio33_dir 0UL
|
||||
#define BKST_gpio34_dir 1UL // 142 — SCI
|
||||
#define BKST_gpio34_dir 1UL // 142 — SCI
|
||||
|
||||
#define BKST_gpio48_dir 1UL // 88 2:14C DIOD red
|
||||
#define BKST_gpio49_dir 0UL
|
||||
@@ -140,7 +149,7 @@
|
||||
#define PULT_gpio10_dir 0UL
|
||||
#define PULT_gpio11_dir 0UL
|
||||
|
||||
#define PULT_gpio19_dir 1UL // 63 — SPI
|
||||
#define PULT_gpio19_dir 1UL // 63 — SPI
|
||||
#define PULT_gpio20_dir 0UL // 64 2:9B mode 2
|
||||
#define PULT_gpio21_dir 0UL // 65 2:9A mode 4
|
||||
#define PULT_gpio22_dir 0UL // 66 2:12C mode 1
|
||||
@@ -152,7 +161,7 @@
|
||||
|
||||
#define PULT_gpio32_dir 1UL // 74 2:10B DIOD green
|
||||
#define PULT_gpio33_dir 0UL
|
||||
#define PULT_gpio34_dir 1UL // 142 — SCI
|
||||
#define PULT_gpio34_dir 1UL // 142 — SCI
|
||||
|
||||
#define PULT_gpio48_dir 1UL // 88 2:14C DIOD red
|
||||
#define PULT_gpio49_dir 0UL // 89 2:14B button
|
||||
@@ -183,7 +192,7 @@
|
||||
#define PLT2_gpio10_dir 0UL
|
||||
#define PLT2_gpio11_dir 0UL
|
||||
|
||||
#define PLT2_gpio19_dir 1UL // 63 × SPI
|
||||
#define PLT2_gpio19_dir 1UL // 63 Ч SPI
|
||||
#define PLT2_gpio20_dir 0UL // 64 2:9B mode 2
|
||||
#define PLT2_gpio21_dir 0UL // 65 2:9A mode 4
|
||||
#define PLT2_gpio22_dir 0UL // 66 2:12C mode 1
|
||||
@@ -195,7 +204,7 @@
|
||||
|
||||
#define PLT2_gpio32_dir 1UL // 74 2:10B DIOD green
|
||||
#define PLT2_gpio33_dir 0UL // 75 2:10C button
|
||||
#define PLT2_gpio34_dir 1UL // 142 × SCI
|
||||
#define PLT2_gpio34_dir 1UL // 142 Ч SCI
|
||||
|
||||
#define PLT2_gpio48_dir 0UL // 88 2:14C button
|
||||
#define PLT2_gpio49_dir 0UL // 89 2:14B button
|
||||
@@ -226,7 +235,7 @@
|
||||
#define SHKF_gpio10_dir 0UL // 19 2:6C input
|
||||
#define SHKF_gpio11_dir 0UL // 20 2:3C input
|
||||
|
||||
#define SHKF_gpio19_dir 1UL // 63 — SPI
|
||||
#define SHKF_gpio19_dir 1UL // 63 — SPI
|
||||
#define SHKF_gpio20_dir 0UL // 64 2:9B mode 2
|
||||
#define SHKF_gpio21_dir 0UL // 65 2:9A mode 4
|
||||
#define SHKF_gpio22_dir 0UL // 66 2:12C mode 1
|
||||
@@ -238,7 +247,7 @@
|
||||
|
||||
#define SHKF_gpio32_dir 0UL // 74 2:10B input
|
||||
#define SHKF_gpio33_dir 0UL // 75 2:10C input
|
||||
#define SHKF_gpio34_dir 1UL // 142 — SCI
|
||||
#define SHKF_gpio34_dir 1UL // 142 — SCI
|
||||
|
||||
#define SHKF_gpio48_dir 1UL // 88 2:14C DIOD red
|
||||
#define SHKF_gpio49_dir 0UL // 89 2:14B input
|
||||
@@ -269,7 +278,7 @@
|
||||
#define LOAD_gpio10_dir 0UL
|
||||
#define LOAD_gpio11_dir 0UL // 20 2:3C res_in 0
|
||||
|
||||
#define LOAD_gpio19_dir 1UL // 63 — SPI
|
||||
#define LOAD_gpio19_dir 1UL // 63 — SPI
|
||||
#define LOAD_gpio20_dir 0UL // 64 2:9B mode 2
|
||||
#define LOAD_gpio21_dir 0UL // 65 2:9A mode 4
|
||||
#define LOAD_gpio22_dir 0UL // 66 2:12C mode 1
|
||||
@@ -281,7 +290,7 @@
|
||||
|
||||
#define LOAD_gpio32_dir 1UL // 74 2:10B DIOD green
|
||||
#define LOAD_gpio33_dir 0UL
|
||||
#define LOAD_gpio34_dir 1UL // 142 — SCI
|
||||
#define LOAD_gpio34_dir 1UL // 142 — SCI
|
||||
|
||||
#define LOAD_gpio48_dir 1UL // 88 2:14C DIOD red
|
||||
#define LOAD_gpio49_dir 0UL
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
/**
|
||||
* @file RS485.h
|
||||
* @brief Состояние портов SCI/RS-485, ограничения буферов и API обмена.
|
||||
*
|
||||
* RS_DATA объединяет регистры SCI, буферы, счётчики и состояние конечного
|
||||
* автомата. Память буферов принадлежит вызывающему коду и должна оставаться
|
||||
* доступной до завершения операции. MAX_RECEIVE_LENGTH/MAX_SEND_LENGTH задают
|
||||
* жёсткую границу, которую необходимо проверить до помещения данных в буфер.
|
||||
*/
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
RS485.h
|
||||
****************************************************************
|
||||
* Процедуры работы с UART *
|
||||
* Процедуры работы с UART *
|
||||
****************************************************************/
|
||||
#ifndef _RS485
|
||||
#define _RS485
|
||||
@@ -38,30 +47,30 @@ typedef struct
|
||||
{
|
||||
volatile struct SCI_REGS *SciRegs;
|
||||
|
||||
unsigned int commnumber; // Номер порта
|
||||
unsigned long RS_Length; // Длина пакета
|
||||
unsigned int commnumber; // Номер порта
|
||||
unsigned long RS_Length; // Длина пакета
|
||||
|
||||
unsigned int *pRS_RecvPtr; // Буфер приема
|
||||
unsigned int *pRS_SendPtr; // Буфер посылки
|
||||
unsigned int *pRS_RecvPtr; // Буфер приема
|
||||
unsigned int *pRS_SendPtr; // Буфер посылки
|
||||
unsigned int *pRecvPtr;
|
||||
|
||||
unsigned int RS_PrevCmd; // Предыдущаа комманда
|
||||
unsigned int RS_Cmd; // Текущаа комманда
|
||||
unsigned int RS_Header[MAX_RECEIVE_LENGTH]; // Заголовок
|
||||
unsigned int flag_TIMEOUT_to_Send; // Флаг ожиданиа таймаута на отсылку
|
||||
unsigned int flag_TIMEOUT_to_Receive; // Флаг ожиданиа таймаута на прием
|
||||
unsigned int RS_DataReady; // Флаг готовности RS данных
|
||||
unsigned int buffer[MAX_SEND_LENGTH]; // Буфер дла отсылки по RS
|
||||
unsigned int RS_PrevCmd; // Предыдущаа комманда
|
||||
unsigned int RS_Cmd; // Текущаа комманда
|
||||
unsigned int RS_Header[MAX_RECEIVE_LENGTH]; // Заголовок
|
||||
unsigned int flag_TIMEOUT_to_Send; // Флаг ожиданиа таймаута на отсылку
|
||||
unsigned int flag_TIMEOUT_to_Receive; // Флаг ожиданиа таймаута на прием
|
||||
unsigned int RS_DataReady; // Флаг готовности RS данных
|
||||
unsigned int buffer[MAX_SEND_LENGTH]; // Буфер дла отсылки по RS
|
||||
|
||||
unsigned int addr_answer; // адрес куда отвечать в режиме ведущего
|
||||
unsigned int addr_recive; // адрес по которому нас запросили
|
||||
unsigned int flag_LEADING; // Флаг режима контроллера (по умолчанию ведомый)
|
||||
unsigned int addr_answer; // адрес куда отвечать в режиме ведущего
|
||||
unsigned int addr_recive; // адрес по которому нас запросили
|
||||
unsigned int flag_LEADING; // Флаг режима контроллера (по умолчанию ведомый)
|
||||
unsigned long RS_RecvLen;
|
||||
unsigned long RS_SLength; // Длина пакета дла посылки
|
||||
unsigned long RS_SendLen; // Количество байт уже передали
|
||||
char RS_SendBlockMode; // Режим передачи
|
||||
char RS_Flag9bit; // дла RS485????????
|
||||
int BS_LoadOK; // Флаг успешности приема блока
|
||||
unsigned long RS_SLength; // Длина пакета дла посылки
|
||||
unsigned long RS_SendLen; // Количество байт уже передали
|
||||
char RS_SendBlockMode; // Режим передачи
|
||||
char RS_Flag9bit; // дла RS485????????
|
||||
int BS_LoadOK; // Флаг успешности приема блока
|
||||
int RS_FlagBegin;
|
||||
int RS_HeaderCnt;
|
||||
int RS_FlagSkiping;
|
||||
@@ -73,61 +82,72 @@ typedef struct
|
||||
extern RS_DATA rs_a,rs_b;
|
||||
|
||||
extern unsigned int
|
||||
RS_Len[70]; /* Действительнаа длина команды (отладочной) + 1 */
|
||||
RS_Len[70]; /* Действительнаа длина команды (отладочной) + 1 */
|
||||
|
||||
/** ISR приёма и передачи SCI-A/SCI-B; вызывают общий автомат соответствующего порта. */
|
||||
interrupt void RSA_RX_Handler(void);
|
||||
interrupt void RSA_TX_Handler(void);
|
||||
interrupt void RSB_RX_Handler(void);
|
||||
interrupt void RSB_TX_Handler(void);
|
||||
|
||||
/* иницилизациа переменных rs_a,rs_b*/
|
||||
/* иницилизациа переменных rs_a,rs_b*/
|
||||
/** Создаёт исходное состояние обоих RS_DATA и задаёт размер команды 15. */
|
||||
void create_uart_vars(char size_cmd15);
|
||||
|
||||
/** Повторнаа инициализациа последовательного порта, используетса после подвиса */
|
||||
/** Настройка режима приема/передачи */
|
||||
/** Повторнаа инициализациа последовательного порта, используетса после подвиса */
|
||||
/** Настройка режима приема/передачи */
|
||||
void RS_SetBitMode(RS_DATA *rs_arr, int n);
|
||||
|
||||
/** Посылка блока байтов.
|
||||
Посылает массива 32-битных целых чисел старшие биты должны быть 0.
|
||||
@precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR
|
||||
@param buf адрес массива
|
||||
@param len количество байт
|
||||
/** Посылка блока байтов.
|
||||
Посылает массива 32-битных целых чисел старшие биты должны быть 0.
|
||||
@precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR
|
||||
@param rs_arr Состояние выбранного порта.
|
||||
@param pBuf Адрес массива слов, каждое из которых содержит один байт.
|
||||
@param len количество байт
|
||||
@return Ненулевое значение, если передача принята драйвером.
|
||||
@see RS_BSend, RS_TRANSMIT_INTR
|
||||
*/
|
||||
int RS_Send(RS_DATA *rs_arr,unsigned int *pBuf, unsigned long len);
|
||||
|
||||
/** Посылка блока упакованных байтов.
|
||||
@precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR
|
||||
@param buf адрес массива
|
||||
@param len количество 8-битных байт
|
||||
/** Посылка блока упакованных байтов.
|
||||
@precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR
|
||||
@param rs_arr Состояние выбранного порта.
|
||||
@param pBuf Адрес массива с упакованными байтами.
|
||||
@param len количество 8-битных байт
|
||||
@return Ненулевое значение, если передача принята драйвером.
|
||||
@see RS_Send, RS_TRANSMIT_INTR
|
||||
*/
|
||||
int RS_BSend(RS_DATA *rs_arr,unsigned int *pBuf, unsigned long len);
|
||||
|
||||
/** Инициализациа последовательного порта */
|
||||
void setup_uart(char commnumber,unsigned long speed_baud); /* speed_baud - скорость линии в бодах */
|
||||
/** Инициализациа последовательного порта */
|
||||
/** @param commnumber COM_1 или COM_2. @param speed_baud Скорость линии в бодах. */
|
||||
void setup_uart(char commnumber,unsigned long speed_baud); /* speed_baud - скорость линии в бодах */
|
||||
|
||||
/** Настраивает число бит данных, чётность и число стоп-битов выбранного SCI. */
|
||||
void RS_SetLineMode(RS_DATA *rs_arr, int bit, char parity, int stop);
|
||||
/** Меняет скорость уже созданного порта и обновляет curr_baud. */
|
||||
void RS_SetLineSpeed(RS_DATA *rs_arr, unsigned long speed);
|
||||
|
||||
// Transmit a character from the SCI'
|
||||
#define SCI_send(x,y) x->SciRegs->SCITXBUF=(unsigned char)(y)
|
||||
|
||||
// Ожидание завершениа передачи UART
|
||||
// Ожидание завершениа передачи UART
|
||||
// wait for TRDY =1 for empty state
|
||||
#define RS_Wait4OK(x) while(!(x->SciRegs->SCICTL2.bit.TXEMPTY))
|
||||
|
||||
/** Переключение линии на прием */
|
||||
/** Переключение линии на прием */
|
||||
#define RS_Line_to_receive(x) if(x->commnumber==COM_2) GpioDataRegs.GPBDAT.bit.GPIO34 = 1;
|
||||
|
||||
/** Переключение линии на передачу */
|
||||
/** Переключение линии на передачу */
|
||||
#define RS_Line_to_send(x) if(x->commnumber==COM_2) GpioDataRegs.GPBDAT.bit.GPIO34 = 0;
|
||||
|
||||
/** Разрешение прерываний по получению символа и ошибкам от UART */
|
||||
/** Разрешение прерываний по получению символа и ошибкам от UART */
|
||||
#define enableUARTInt(x) x->SciRegs->SCICTL2.all=2
|
||||
#define enableUARTIntW(x) x->SciRegs->SCICTL2.all=1
|
||||
|
||||
/** Сбрасывает таймер контроля активности после корректного обмена. */
|
||||
void clear_timer_rs_live(RS_DATA *rs_arr);
|
||||
/** Обновляет признак потери связи по тайм-ауту RS_TIME_OUT. */
|
||||
void test_rs_live(RS_DATA *rs_arr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
/**
|
||||
* @file bios_dsp.h
|
||||
* @brief Команды сервисного BIOS и API удалённой работы с памятью.
|
||||
*
|
||||
* Объявляет номера команд загрузчика и обработчики, работающие с RS_DATA.
|
||||
* Интерфейс предоставляет прямые операции с адресным пространством DSP и
|
||||
* предназначен только для доверенных, уже проверенных протокольных запросов.
|
||||
*/
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************/
|
||||
/* Bios_dsp.h */
|
||||
/****************************************************************/
|
||||
/* Основные комманды BIOS */
|
||||
/* Основные комманды BIOS */
|
||||
/****************************************************************/
|
||||
#ifndef _BIOS_DSP
|
||||
#define _BIOS_DSP
|
||||
@@ -42,71 +50,85 @@ enum {
|
||||
|
||||
CMD_VECTOR=61,
|
||||
CMD_IMPULSE,
|
||||
/* стандартные команды */
|
||||
/* стандартные команды */
|
||||
CMD_STD=65, CMD_STD_ANS
|
||||
};
|
||||
|
||||
enum {false=0, true};
|
||||
|
||||
|
||||
/** Возвращает номер комманды, если есть или -1 если транзакций не было */
|
||||
/** Возвращает номер комманды, если есть или -1 если транзакций не было */
|
||||
/** Проверяет кадр и выполняет содержащуюся в нём сервисную команду. */
|
||||
int get_command(RS_DATA *rs_arr);
|
||||
|
||||
/** Стандартный ответ, без параметров */
|
||||
/** Стандартный ответ, без параметров */
|
||||
/** Формирует и отправляет ответ длиной n слов через заданный порт. */
|
||||
void Answer(RS_DATA *rs_arr,int n);
|
||||
|
||||
/* начальные установки (не работает)*/
|
||||
/* начальные установки (не работает)*/
|
||||
/** Сбрасывает состояние текущей сессии загрузчика. */
|
||||
void init(RS_DATA *rs_arr);
|
||||
|
||||
/**@name Комманды
|
||||
* Комманды, вызываемые через последовательный канал*/
|
||||
/**@name Комманды
|
||||
* Комманды, вызываемые через последовательный канал*/
|
||||
//@{
|
||||
|
||||
/** Инициировать загрузку блока.
|
||||
Настраивает прием блока данных */
|
||||
/** Инициировать загрузку блока.
|
||||
Настраивает прием блока данных */
|
||||
/** Подготавливает диапазон памяти к приёму нового образа. */
|
||||
void initload(RS_DATA *rs_arr);
|
||||
|
||||
/** Загрузка блока.
|
||||
Вызываетса после загрузки блока через RS */
|
||||
/** Загрузка блока.
|
||||
Вызываетса после загрузки блока через RS */
|
||||
/** Записывает очередной проверенный блок образа в память. */
|
||||
void load(RS_DATA *rs_arr);
|
||||
|
||||
/** Выполнить программу в формате Serial Boot.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес программы беретса из заголовка и
|
||||
сравниваетса с переменной RecvPtr, заполнаемой в ф-ции load
|
||||
/** Выполнить программу в формате Serial Boot.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес программы беретса из заголовка и
|
||||
сравниваетса с переменной RecvPtr, заполнаемой в ф-ции load
|
||||
@see load */
|
||||
/** Передаёт управление по адресу, заданному сервисной командой. */
|
||||
void run (RS_DATA *rs_arr);
|
||||
|
||||
/** Прочитать ачейку памати */
|
||||
/** Прочитать ачейку памати */
|
||||
/** Читает запрошенный диапазон памяти и возвращает его ведущему узлу. */
|
||||
void peek(RS_DATA *rs_arr);
|
||||
|
||||
/** Записать в ачейку памати */
|
||||
/** Записать в ачейку памати */
|
||||
/** Записывает одно или несколько слов по адресу из команды. */
|
||||
void poke(RS_DATA *rs_arr);
|
||||
|
||||
/** Передать блок памати */
|
||||
/** Передать блок памати */
|
||||
/** Передаёт ведущему узлу очередной блок содержимого памяти. */
|
||||
void upload(RS_DATA *rs_arr);
|
||||
|
||||
/** Прошить XILINX.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load,
|
||||
так же смотрит магическое слово в начале прошивки
|
||||
/** Прошить XILINX.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load,
|
||||
так же смотрит магическое слово в начале прошивки
|
||||
@see load */
|
||||
/** Обрабатывает команду доступа к внешней Flash-памяти. */
|
||||
void xflash(RS_DATA *rs_arr);
|
||||
|
||||
/** Прошить TMS.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
|
||||
/** Прошить TMS.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
|
||||
@see load */
|
||||
/** Обрабатывает команду доступа к целевой Flash-памяти. */
|
||||
void tflash(RS_DATA *rs_arr);
|
||||
|
||||
|
||||
/* расширенные команды дла биоса */
|
||||
/* расширенные команды дла биоса */
|
||||
/** Обрабатывает расширенную сервисную команду BIOS. */
|
||||
void extendbios(RS_DATA *rs_arr);
|
||||
|
||||
|
||||
/** Записывает слово по физическому адресу; адрес обязан быть допустимым. */
|
||||
void write_memory(unsigned long addr, unsigned int data);
|
||||
/** Читает слово по физическому адресу; адрес обязан быть допустимым. */
|
||||
unsigned int read_memory(unsigned long addr);
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +1,31 @@
|
||||
/**
|
||||
* @file caliber.h
|
||||
* @brief Заводские калибровочные таблицы для вариантов семейства Balsam.
|
||||
*
|
||||
* Ровно одна таблица def_cal включается по значению BALSAM. Строки и столбцы
|
||||
* имеют фиксированный смысл для измерительных каналов и диапазонов; их порядок
|
||||
* согласован с message.c и внешней методикой калибровки. Файл определяет данные,
|
||||
* поэтому должен подключаться только одним модулем реализации.
|
||||
*/
|
||||
#if BALSAM == 167 //-------------------------------------------------------------
|
||||
int def_cal[][8] = {
|
||||
|
||||
// ÁÊÑÑ òðàíñ 100 1 100 2 150 1 150 2
|
||||
0, 0, 0, 0, 455, 441, 2459, 2392, // Áîðò 0
|
||||
0, 0, 0, 0, 462, 439, 2442, 2400, // Áîðò 1
|
||||
// БКСС транс 100 1 100 2 150 1 150 2
|
||||
0, 0, 0, 0, 455, 441, 2459, 2392, // Борт 0
|
||||
0, 0, 0, 0, 462, 439, 2442, 2400, // Борт 1
|
||||
|
||||
// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
4936, 4877, 4972, 4857, 1886, 1898, 2517, 2535, // Áîðò 0
|
||||
4876, 5005, 4876, 4847, 1898, 1873, 2535, 2502, // Áîðò 1
|
||||
// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
4936, 4877, 4972, 4857, 1886, 1898, 2517, 2535, // Борт 0
|
||||
4876, 5005, 4876, 4847, 1898, 1873, 2535, 2502, // Борт 1
|
||||
|
||||
// ÓÌÏ UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3820, 3790, 3505, 3380, 1736, 683, 854, 14, // Áîðò 0 1062 1980
|
||||
3835, 3785, 3522, 3332, 1745, 689, 860, 17, // Áîðò 1 1720 2405
|
||||
// УМП UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3820, 3790, 3505, 3380, 1736, 683, 854, 14, // Борт 0 1062 1980
|
||||
3835, 3785, 3522, 3332, 1745, 689, 860, 17, // Борт 1 1720 2405
|
||||
|
||||
// ÁÊÑÑÄ 100 Ohm 150 Ohm
|
||||
// БКССД 100 Ohm 150 Ohm
|
||||
1281, 1272, 0, 0, 622, 2263, 0, 0,
|
||||
|
||||
// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2
|
||||
// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2
|
||||
1290, 1285, 0, 0, 2045, 2045, 2725, 2725 };
|
||||
#endif //---------------------------------------------------------------------
|
||||
|
||||
@@ -24,45 +33,45 @@
|
||||
#if BALSAM == 166 //-------------------------------------------------------------
|
||||
int def_cal[][8] = {
|
||||
|
||||
// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
4936, 4877, 4972, 4857, 1960, 1920, 2610, 2570, // Áîðò 0
|
||||
4876, 5005, 4876, 4847, 1950, 1965, 2600, 2615, // Áîðò 1
|
||||
// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
4936, 4877, 4972, 4857, 1960, 1920, 2610, 2570, // Борт 0
|
||||
4876, 5005, 4876, 4847, 1950, 1965, 2600, 2615, // Борт 1
|
||||
|
||||
// ÓÌÏ UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3820, 3790, 3505, 3380, 1718, 673, 854, 14, // Áîðò 0
|
||||
3835, 3785, 3522, 3332, 1697, 653, 860, 17, // Áîðò 1
|
||||
// УМП UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3820, 3790, 3505, 3380, 1718, 673, 854, 14, // Борт 0
|
||||
3835, 3785, 3522, 3332, 1697, 653, 860, 17, // Борт 1
|
||||
|
||||
// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2
|
||||
// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2
|
||||
1281, 1272, 0, 0, 2049, 2050, 2749, 2750 };
|
||||
#endif //---------------------------------------------------------------------
|
||||
|
||||
#if BALSAM == 165 //-------------------------------------------------------------
|
||||
int def_cal[][8] = {
|
||||
|
||||
// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
5130, 4960, 4925, 5070, 1881, 1881, 2506, 2516, // Áîðò 0
|
||||
5020, 5040, 4950, 5030, 1871, 1879, 2507, 2514, // Áîðò 1
|
||||
// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
5130, 4960, 4925, 5070, 1881, 1881, 2506, 2516, // Борт 0
|
||||
5020, 5040, 4950, 5030, 1871, 1879, 2507, 2514, // Борт 1
|
||||
|
||||
// ÓÌÏ UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3890, 3865, 5100, 4850, 1730, 675, 854, 14, // Áîðò 0
|
||||
3845, 3800, 3250, 3100, 1044, 0, 860, 17, // Áîðò 1
|
||||
// УМП UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3890, 3865, 5100, 4850, 1730, 675, 854, 14, // Борт 0
|
||||
3845, 3800, 3250, 3100, 1044, 0, 860, 17, // Борт 1
|
||||
|
||||
// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2
|
||||
// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2
|
||||
1289, 1280, 0, 0, 2073, 2071, 2773, 2771 };
|
||||
#endif //---------------------------------------------------------------------
|
||||
|
||||
#if BALSAM == 164 //-------------------------------------------------------------
|
||||
int def_cal[][8] = {
|
||||
|
||||
// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
7573, 7573, 7573, 7573, 1979, 1888, 2592, 2513, // Áîðò 0
|
||||
7573, 7573, 7573, 7573, 1970, 1907, 2584, 2558, // Áîðò 1
|
||||
// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
7573, 7573, 7573, 7573, 1979, 1888, 2592, 2513, // Борт 0
|
||||
7573, 7573, 7573, 7573, 1970, 1907, 2584, 2558, // Борт 1
|
||||
|
||||
// ÓÌÏ UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3920, 3905, 3300, 3220, 1015, 0, 854, 14, // Áîðò 0
|
||||
3835, 3785, 5100, 4600, 1750, 680, 860, 17, // Áîðò 1
|
||||
// УМП UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3920, 3905, 3300, 3220, 1015, 0, 854, 14, // Борт 0
|
||||
3835, 3785, 5100, 4600, 1750, 680, 860, 17, // Борт 1
|
||||
|
||||
// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2
|
||||
// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2
|
||||
1266, 1267, 0, 0, 2063, 2040, 2678, 2655 };
|
||||
#endif //---------------------------------------------------------------------
|
||||
|
||||
@@ -71,15 +80,15 @@
|
||||
#if PXXXXX == 1 //-------------------------------------------------------------
|
||||
int def_cal[][6] = {
|
||||
|
||||
// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
0400, 0400, 0400, 0400, 1950, 1950, 2600, 2600, // Áîðò 0
|
||||
0400, 0400, 0400, 0400, 1950, 1950, 2600, 2600, // Áîðò 1
|
||||
// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2
|
||||
0400, 0400, 0400, 0400, 1950, 1950, 2600, 2600, // Борт 0
|
||||
0400, 0400, 0400, 0400, 1950, 1950, 2600, 2600, // Борт 1
|
||||
|
||||
// ÓÌÏ UA UC IA IC 20mA 4mA
|
||||
0400, 0400, 4800, 4800, 0, 0, 0, 0, // Áîðò 0
|
||||
0400, 0400, 4800, 4800, 0, 0, 0, 0, // Áîðò 1
|
||||
// УМП UA UC IA IC 20mA 4mA
|
||||
0400, 0400, 4800, 4800, 0, 0, 0, 0, // Борт 0
|
||||
0400, 0400, 4800, 4800, 0, 0, 0, 0, // Борт 1
|
||||
|
||||
// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2
|
||||
// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2
|
||||
1270, 1270, 0, 0, 1950, 1950, 2600, 2600 };
|
||||
#endif //---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
/**
|
||||
* @file cntrl_adr.h
|
||||
* @brief Адреса узла в сервисном протоколе и функция их установки.
|
||||
*
|
||||
* Константные адреса задают специальные роли, CNTRL_ADDR и ADDR_FOR_ALL могут
|
||||
* меняться во время настройки. Заголовок не выполняет валидацию диапазонов.
|
||||
*/
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
cntrl_adr.h
|
||||
****************************************************************
|
||||
* Адрес контроллера *
|
||||
* Адрес контроллера *
|
||||
****************************************************************/
|
||||
|
||||
#ifndef _CNTRL_ADR
|
||||
@@ -15,22 +22,26 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** адрес контроллера дла посылки всем АИНам */
|
||||
/** адрес контроллера дла посылки всем АИНам */
|
||||
extern int ADDR_FOR_ALL;
|
||||
|
||||
/** адрес контроллера дла посылки ответа */
|
||||
/** адрес контроллера дла посылки ответа */
|
||||
extern const int ADDR_ANSWER;
|
||||
|
||||
/** адреса терминала дла посылки ответа */
|
||||
/** адреса терминала дла посылки ответа */
|
||||
extern const int ADDR_TERMINAL;
|
||||
|
||||
/* Адрес контроллера */
|
||||
/* Адрес контроллера */
|
||||
extern int CNTRL_ADDR;
|
||||
|
||||
/* Универсальный адрес контроллера */
|
||||
/* Универсальный адрес контроллера */
|
||||
extern const int CNTRL_ADDR_UNIVERSAL;
|
||||
|
||||
/** Установка адреса контроллера дла прошивки */
|
||||
/** Установка адреса контроллера дла прошивки */
|
||||
/**
|
||||
* @param cntrl_addr Новый индивидуальный адрес узла.
|
||||
* @param cntrl_addr_for_all Новый адрес групповых команд.
|
||||
*/
|
||||
void set_cntrl_addr (int cntrl_addr,int cntrl_addr_for_all);
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
/**
|
||||
* @file crc16.h
|
||||
* @brief Интерфейс алгоритмов CRC, используемых коммуникационными модулями.
|
||||
*
|
||||
* Буфер представлен словами целевого DSP; параметр size трактуется реализацией
|
||||
* как число обрабатываемых элементов. Вызывающий код выбирает вариант CRC и
|
||||
* передаёт требуемое протоколом начальное значение.
|
||||
*/
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned char byte;
|
||||
|
||||
|
||||
/** Вычисляет CRC-CCITT для size слов, продолжая переданное значение crc. */
|
||||
unsigned int get_crc_ccitt(unsigned int crc, unsigned int *buf, unsigned long size );
|
||||
/** Вычисляет табличный CRC-16 (полином 0xA001) для size слов. */
|
||||
unsigned int get_crc_16(unsigned int crc,unsigned int *buf,unsigned long size );
|
||||
/** Вычисляет побитовый вариант CRC-16 для проверки табличной реализации. */
|
||||
unsigned int get_crc_16b(unsigned int crc,unsigned int *buf,unsigned long size );
|
||||
/** Возвращает CRC-16 кадра с принятым в проекте начальным значением. */
|
||||
int get_crc16(unsigned int *buf, int size );
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
/**
|
||||
* @file ecan.h
|
||||
* @brief Минимальный публичный интерфейс обмена по CAN.
|
||||
*
|
||||
* Port выбирает аппаратный контроллер, DevNum/Addr определяют логический узел.
|
||||
* Массив данных должен содержать формат кадра, ожидаемый реализацией ecan.c.
|
||||
*/
|
||||
/**
|
||||
* Настраивает CAN-порт и почтовые ящики логического устройства.
|
||||
* @param Port Номер аппаратного CAN-контроллера.
|
||||
* @param DevNum Номер узла; реализация ограничивает его диапазоном 1..16.
|
||||
*/
|
||||
void InitCan(int Port, int DevNum);
|
||||
/**
|
||||
* Ставит прикладные данные в передающий mailbox.
|
||||
* @param Port Номер аппаратного CAN-контроллера.
|
||||
* @param data Массив слов кадра в формате проекта.
|
||||
* @param Addr Адрес получателя.
|
||||
*/
|
||||
void CAN_send(int Port, int data[], int Addr);
|
||||
/** Последние прикладные слова, принятые обработчиком CAN. */
|
||||
extern int CAN_input_data[];
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
/**
|
||||
* @file filter_bat2.h
|
||||
* @brief Коэффициенты и состояние рекурсивного НЧ-фильтра второго порядка.
|
||||
*
|
||||
* Наборы K*_FILTER_BATTER2_* рассчитаны для заданных частот среза при штатной
|
||||
* частоте дискретизации. DEF_FILTERBAT создаёт нулевое состояние для 3 Гц;
|
||||
* один экземпляр FILTERBAT нельзя одновременно использовать для разных каналов.
|
||||
*/
|
||||
#ifndef _FILTER_BAT2
|
||||
#define _FILTER_BAT2
|
||||
|
||||
@@ -38,6 +46,12 @@ typedef struct { float k_0;
|
||||
K3_FILTER_BATTER2_3HZ, \
|
||||
0,0,0,0,0,0}
|
||||
|
||||
/**
|
||||
* Выполняет один шаг фильтра и обновляет его историю на месте.
|
||||
* @param b Уникальное состояние фильтра конкретного канала.
|
||||
* @param InpVarCurr Текущий входной отсчёт.
|
||||
* @return Новый фильтрованный отсчёт.
|
||||
*/
|
||||
float filterbat(FILTERBAT *b, float InpVarCurr);
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
/**
|
||||
* @file kanal.h
|
||||
* @brief Интерфейс вывода значения на адресуемый канальный индикатор.
|
||||
*
|
||||
* adr выбирает индикатор, dat содержит отображаемое число, dot — позицию точки.
|
||||
*/
|
||||
/**
|
||||
* Передаёт число адресуемому индикатору.
|
||||
* @param adr Аппаратный адрес канала.
|
||||
* @param dat Отображаемое целое значение.
|
||||
* @param dot Позиция десятичной точки в протокольном формате индикатора.
|
||||
*/
|
||||
void kanal_Send(int adr, long dat, int dot);
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
/**
|
||||
* @file log_to_mem.h
|
||||
* @brief Разметка внешней памяти и состояние кольцевого журнала.
|
||||
*
|
||||
* LOG_PAGE_START и LOG_PAGE_LEN обязаны совпадать с картой линковщика. Флаги
|
||||
* no_write/never_write запрещают запись на разных уровнях, а clear_mem()
|
||||
* полностью обнуляет область и потому является длительной операцией.
|
||||
*/
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2001г. */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2001г. */
|
||||
/****************************************************************/
|
||||
/* log_to_mem.h
|
||||
****************************************************************
|
||||
* Запись логов в памyть *
|
||||
* Запись логов в памyть *
|
||||
****************************************************************/
|
||||
|
||||
#ifndef _LOG_TO_MEM
|
||||
@@ -15,11 +23,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Определениa длa работы логгера */
|
||||
/* Определениa длa работы логгера */
|
||||
#define LOG_PAGE_START 0x0200000
|
||||
#define LOG_PAGE_LEN 0xFA00
|
||||
|
||||
extern int no_write, never_write; // Флаги, чтобы не писать (если что)
|
||||
extern int no_write, never_write; // Флаги, чтобы не писать (если что)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -32,14 +40,15 @@ typedef struct
|
||||
|
||||
extern LOG Log;
|
||||
|
||||
/* Запись словa в памать, где логи лежат */
|
||||
/* Запись словa в памать, где логи лежат */
|
||||
#define Log_to_mem(x) *(int *)(Log.Adres++) = x
|
||||
|
||||
/* Проверка границы памати дла логов */
|
||||
/* Проверка границы памати дла логов */
|
||||
//#define Test_mem_limit(x) if(Log.Adres > (Log.Finis - (x))) Log.Adres = Log.Start
|
||||
#define Test_mem_limit(x) if(Log.Adres > (Log.Finis - (x))) Log.Adres -=(x)
|
||||
|
||||
/* Очистка памати (обнуление) */
|
||||
/* Очистка памати (обнуление) */
|
||||
/** Полностью обнуляет область журнала и возвращает указатель записи в начало. */
|
||||
void clear_mem();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,19 +1,41 @@
|
||||
// âãâ
|
||||
// вгв
|
||||
#ifndef _MEASURE
|
||||
#define _MEASURE
|
||||
/**
|
||||
* @file measure.h
|
||||
* @brief Общие типы, состояния и API измерительно-диагностической подсистемы.
|
||||
*
|
||||
* Объявляет этапы обработки каналов, битовые флаги ошибок и разделяемые данные,
|
||||
* используемые ISR, протоколом и главным циклом. Номера каналов и позиции битов
|
||||
* являются частью внешнего формата сообщений; менять их независимо нельзя.
|
||||
*/
|
||||
|
||||
/** ISR Timer1 для периодического запуска измерительных и диагностических этапов. */
|
||||
interrupt void cpu_timer1_isr_SENS(void);
|
||||
|
||||
/** Инициализирует основные структуры, фильтры и состояния датчиков. */
|
||||
void Init_sensors(void);
|
||||
/** Выполняет дополнительную инициализацию, зависящую от типа платы. */
|
||||
void Init_sensors_more(void);
|
||||
/** Строит маски упаковки каналов для внешних сообщений. */
|
||||
void Init_packMask(void);
|
||||
/** Рассчитывает температуру канала; ovn выбирает источник/режим измерения. */
|
||||
void Temper_count(int chan, int ovn);
|
||||
/** Рассчитывает ток и обновляет диагностику заданного канала. */
|
||||
void Current_count(int chan);
|
||||
/** Рассчитывает электрическую мощность заданного канала. */
|
||||
void Power_count(int chan);
|
||||
/** Пересчитывает масштабные коэффициенты из калибровочных параметров. */
|
||||
void calc_sensor_koef(void);
|
||||
/** Обновляет признаки превышения допустимого напряжения. */
|
||||
void Is_Voltage_Hi(void);
|
||||
/** Пересчитывает пороги напряжения для текущего режима изделия. */
|
||||
void calc_volta_edge(void);
|
||||
|
||||
/**
|
||||
* Выполняет временную проверку порога ошибки.
|
||||
* @return Ненулевое значение после требуемого числа последовательных нарушений.
|
||||
*/
|
||||
int er_anal(int term, unsigned int * count, long edge, int pre);
|
||||
|
||||
typedef union
|
||||
@@ -64,14 +86,14 @@ typedef union
|
||||
#define NOER 0xE000//C
|
||||
#define EROR 0x01FF
|
||||
|
||||
#define READY_FREQ (500.0 * 2)// Ãö
|
||||
#define BLINK_FREQ 2 // Ãö
|
||||
#define READY_FREQ (500.0 * 2)// Гц
|
||||
#define BLINK_FREQ 2 // Гц
|
||||
#define BLINK_TIME (READY_FREQ / BLINK_FREQ)
|
||||
|
||||
#define CANPOWSE 20
|
||||
|
||||
#define ADC_FREQ 3750 //3885.0//777//2000//20000 //777 //3885 // Ãö (777*5)
|
||||
#define DAC_FREQ 200//5 // Ãö
|
||||
#define ADC_FREQ 3750 //3885.0//777//2000//20000 //777 //3885 // Гц (777*5)
|
||||
#define DAC_FREQ 200//5 // Гц
|
||||
|
||||
#define LOAD_TIME 30//15 // sec
|
||||
|
||||
@@ -86,23 +108,23 @@ extern unsigned int Caliber_time;
|
||||
|
||||
#define ZERO 27
|
||||
|
||||
#define Cooling 5 // (°Ñ) Ãèñòåðåçèñ ïî ñíàòèþ ïåðåãðåâà
|
||||
#define Cooling 5 // (°С) Гистерезис по снатию перегрева
|
||||
|
||||
#define COSPi6 0.86602540378443864676372317075294
|
||||
|
||||
#define RADIX2 1.4142135623730950488016887242097
|
||||
|
||||
#define POWER_380 0 // ïèòàíèå 380Â
|
||||
#define POWER_38O 1 // ïèòàíèå 380Â
|
||||
#define CURRENT 2 // òîê
|
||||
#define VOLTAGE 3 // íàïðàæåíèå
|
||||
#define POWER_31 4 // ïèòàíèå 31Â
|
||||
#define POWER_27 5 // ïèòàíèå 24Â
|
||||
#define POWER_24 6 // ïèòàíèå 24Â
|
||||
#define POWER_15 7 // ïèòàíèå 15Â
|
||||
#define TERMO_AD 8 // òåðìîäàò÷èê ìåëêîñõåìà
|
||||
#define TERMO_RS 9 // òåðìîðåçèñòîð
|
||||
#define TRM_OBEH 10 // òåðìîäàò÷èê îâåí
|
||||
#define POWER_380 0 // питание 380В
|
||||
#define POWER_38O 1 // питание 380В
|
||||
#define CURRENT 2 // ток
|
||||
#define VOLTAGE 3 // напражение
|
||||
#define POWER_31 4 // питание 31В
|
||||
#define POWER_27 5 // питание 24В
|
||||
#define POWER_24 6 // питание 24В
|
||||
#define POWER_15 7 // питание 15В
|
||||
#define TERMO_AD 8 // термодатчик мелкосхема
|
||||
#define TERMO_RS 9 // терморезистор
|
||||
#define TRM_OBEH 10 // термодатчик овен
|
||||
|
||||
extern int TPL_CANS,tpl_cans;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
/**
|
||||
* @file message.h
|
||||
* @brief Форматы команд, размеры ответов и API обработки Modbus-сообщений.
|
||||
*
|
||||
* CMD_TO_TMS описывает точную раскладку принятого кадра, включая CRC. Поля и
|
||||
* ANSWER_LEN/REPLY_LEN согласованы с удалённым мастером; структура использует
|
||||
* целевые типы DSP, поэтому не должна сериализоваться простым memcpy на PC.
|
||||
*/
|
||||
#ifndef MESSAGE_H
|
||||
#define MESSAGE_H
|
||||
|
||||
@@ -11,8 +19,8 @@ typedef unsigned char CHAR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char Address; // Àäðåñ êîíòðîëëåðà
|
||||
unsigned char Number; // Íîìåð êîìàíäû
|
||||
unsigned char Address; // Адрес контроллера
|
||||
unsigned char Number; // Номер команды
|
||||
|
||||
BAITE byte0;
|
||||
BAITE byte1;
|
||||
@@ -30,13 +38,20 @@ typedef struct
|
||||
|
||||
extern int modbus[];
|
||||
|
||||
/** Принимает запрос чтения регистров и подготавливает соответствующий ответ. */
|
||||
void ReceiveCommandModbus3(RS_DATA *rs_arr);
|
||||
/** Принимает запрос записи одного регистра и применяет разрешённый параметр. */
|
||||
void ReceiveCommandModbus6(RS_DATA *rs_arr);
|
||||
/** Отправляет текущий блок телеметрии ответом прикладной функции 4. */
|
||||
void SendCommandModbus4(RS_DATA *rs_arr);
|
||||
/** Разбирает ответ функции 4, полученный от ведомого устройства. */
|
||||
void ReceiveAnswerModbus4(RS_DATA *rs_arr);
|
||||
|
||||
/** Сохраняет текущий массив параметров в EEPROM. */
|
||||
void Save_params(void);
|
||||
/** Загружает параметры из EEPROM и заменяет некорректные значения безопасными. */
|
||||
void Load_params(void);
|
||||
/** Заполняет параметры значениями для выбранного в package.h варианта платы. */
|
||||
void Default_params(void);
|
||||
|
||||
#endif //MESSAGE_H
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file package.h
|
||||
* @brief Центральная конфигурация изделия Balsam и адресов его подсистем.
|
||||
*
|
||||
* Значение BALSAM выбирает аппаратный вариант, направление вращения и набор
|
||||
* возможностей. adr_* и последующие константы связывают физические модули с
|
||||
* протоколом и массивами измерений. Изменение этого файла влияет на всю прошивку
|
||||
* и должно сопровождаться проверкой схемы, карты CAN/Modbus и калибровки.
|
||||
*/
|
||||
#ifndef PACKAGE
|
||||
#define PACKAGE
|
||||
|
||||
@@ -91,15 +100,15 @@
|
||||
#define bSecretBt Buttons.bit.bit1
|
||||
#define bTermoCal Buttons.bit.bit2
|
||||
|
||||
#define Cancount (modbus+0x60) // ïàóçà ìåæäó I ïîñûëêàìè CAN
|
||||
#define Bright (modbus+0x62) // àðêîñòü ñèãíàëüíûõ ëàìïî÷åê
|
||||
#define Brightness modbus[0x62] // àðêîñòü ñèãíàëüíûõ ëàìïî÷åê
|
||||
#define Cancount (modbus+0x60) // пауза между I посылками CAN
|
||||
#define Bright (modbus+0x62) // аркость сигнальных лампочек
|
||||
#define Brightness modbus[0x62] // аркость сигнальных лампочек
|
||||
|
||||
#define Owncount modbus[0x63] // ïàóçà ìåæäó îïðîñàìè OWEN
|
||||
#define Owncount modbus[0x63] // пауза между опросами OWEN
|
||||
|
||||
/* Íå âðåìà!
|
||||
#define DAC_go modbus[0x64] // íà÷àëî çàðàäà
|
||||
#define DAC_stop modbus[0x65] // êîíåö çàðàäà
|
||||
/* Не врема!
|
||||
#define DAC_go modbus[0x64] // начало зарада
|
||||
#define DAC_stop modbus[0x65] // конец зарада
|
||||
*/
|
||||
|
||||
#define m_FAST 0
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file peripher.h
|
||||
* @brief GPIO-примитивы и интерфейс определения аппаратного режима.
|
||||
*
|
||||
* Inline-функции учитывают различия разводки плат через глобальный Desk.
|
||||
* Большинство выходов активны низким уровнем, поэтому set/clear не всегда
|
||||
* совпадают с физическими SET/CLEAR регистрами. Desk должен быть определён
|
||||
* get_Mode() до первого управления линиями.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||||
|
||||
extern int Mode,Desk,TermoAD,TermoRS,TermoSW,Kurrent,Kalibro,Owen;
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/**
|
||||
* @file pulto.h
|
||||
* @brief Обработчик периодического таймера для режима пульта.
|
||||
*
|
||||
* Функция устанавливается в вектор Timer1 только для соответствующего Desk.
|
||||
*/
|
||||
//void what_is(void);
|
||||
|
||||
/** ISR таймера CPU1: обновляет индикацию и контроль связи в режиме пульта. */
|
||||
interrupt void cpu_timer1_isr_PULT(void);
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file spise2p.h
|
||||
* @brief Конфигурация SPI EEPROM и структуры её конечного автомата.
|
||||
*
|
||||
* Определяет команды микросхемы, ширину адреса/данных, скорость SPI и состояния
|
||||
* транзакции. SPISE2P_DRV_DEFAULTS создаёт единственный драйвер с callback-функциями;
|
||||
* перед чтением или записью требуется InitSeeprom(), а диапазон операции должен
|
||||
* оставаться внутри SEEPROM_LEN.
|
||||
*/
|
||||
/*=====================================================================
|
||||
File name : SPISE2P.H
|
||||
|
||||
@@ -17,7 +26,7 @@ Date : 30/6/2003 (DD/MM/YYYY)
|
||||
|
||||
#define __SPISE2P_H__
|
||||
|
||||
// Ёмкость памати в байтах
|
||||
// Ёмкость памати в байтах
|
||||
#define SEEPROM_LEN 0x10000
|
||||
|
||||
#define NULL 0
|
||||
@@ -90,13 +99,28 @@ typedef struct {
|
||||
|
||||
typedef SPISE2P_DRV *SPISE2P_DRV_handle;
|
||||
|
||||
/** Сбрасывает поля конечного автомата и конфигурирует SPI. */
|
||||
void SPISE2P_DRV_init(SPISE2P_DRV * );
|
||||
/** Продвигает конечный автомат EEPROM на один таймерный такт. */
|
||||
void SPISE2P_DRV_tick(SPISE2P_DRV *);
|
||||
/** Деактивирует аппаратный chip-select EEPROM. */
|
||||
void SPISE2P_DRV_csset(void);
|
||||
/** Активирует аппаратный chip-select EEPROM. */
|
||||
void SPISE2P_DRV_csclr(void);
|
||||
|
||||
/** @return Ненулевое значение, когда драйвер готов принять новую операцию. */
|
||||
unsigned int spiSe2pFree(SPISE2P_DRV *se2p);
|
||||
/**
|
||||
* Запускает асинхронную запись.
|
||||
* @param se2p Экземпляр конечного автомата.
|
||||
* @param msgPtr Описание адреса, буфера и длины блока.
|
||||
*/
|
||||
void spiSe2pWrite(SPISE2P_DRV *se2p, SE2P_DATA *data);
|
||||
/**
|
||||
* Запускает асинхронное чтение.
|
||||
* @param se2p Экземпляр конечного автомата.
|
||||
* @param msgPtr Описание адреса, буфера и длины блока.
|
||||
*/
|
||||
void spiSe2pRead(SPISE2P_DRV *se2p, SE2P_DATA *data);
|
||||
|
||||
#if(SPISE2P_DATA_WIDTH==SIXTEEN_BIT)
|
||||
@@ -109,25 +133,27 @@ void spiSe2pRead(SPISE2P_DRV *se2p, SE2P_DATA *data);
|
||||
#define WORD_LEN 1
|
||||
#endif
|
||||
|
||||
/* Установка драйвера сериальной EEPROM. **
|
||||
** Инициализациа SPI и проч. Также настройка таймера. **
|
||||
** Драйвер работает на прерываниах от таймера 2! */
|
||||
/* Установка драйвера сериальной EEPROM. **
|
||||
** Инициализациа SPI и проч. Также настройка таймера. **
|
||||
** Драйвер работает на прерываниах от таймера 2! */
|
||||
void InitSeeprom(void);
|
||||
|
||||
/* Запись блока в SEEPROM. Параметры таковы: **
|
||||
** adres - адрес в епромке, куда писать. **
|
||||
** adres = 0..0x8000, если длина слова 8 бит **
|
||||
** adres = 0..0x4000, если длина слова 16 бит **
|
||||
** buf - указатель на памать, откуда писать. **
|
||||
** size - длина блока в байтах. По-любому в байтах! */
|
||||
/* Запись блока в SEEPROM. Параметры таковы: **
|
||||
** adres - адрес в епромке, куда писать. **
|
||||
** adres = 0..0x8000, если длина слова 8 бит **
|
||||
** adres = 0..0x4000, если длина слова 16 бит **
|
||||
** buf - указатель на памать, откуда писать. **
|
||||
** size - длина блока в байтах. По-любому в байтах! */
|
||||
/** @param size Размер блока в байтах, независимо от SPISE2P_DATA_WIDTH. */
|
||||
void Seeprom_write(unsigned int adres, unsigned int buf[], unsigned int size);
|
||||
|
||||
/* Чтение блока из SEEPROM. Параметры таковы: **
|
||||
** adres - адрес в епромке, откуда читать. **
|
||||
** adres = 0..0x8000, если длина слова 8 бит **
|
||||
** adres = 0..0x4000, если длина слова 16 бит **
|
||||
** buf - указатель на памать, куда читать. **
|
||||
** size - длина блока в байтах. По-любому в байтах! */
|
||||
/* Чтение блока из SEEPROM. Параметры таковы: **
|
||||
** adres - адрес в епромке, откуда читать. **
|
||||
** adres = 0..0x8000, если длина слова 8 бит **
|
||||
** adres = 0..0x4000, если длина слова 16 бит **
|
||||
** buf - указатель на памать, куда читать. **
|
||||
** size - длина блока в байтах. По-любому в байтах! */
|
||||
/** @param size Размер блока в байтах, независимо от SPISE2P_DATA_WIDTH. */
|
||||
void Seeprom_read(unsigned int adres, unsigned int buf[], unsigned int size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
/**
|
||||
* @file tools.h
|
||||
* @brief Низкоуровневые вспомогательные функции платформы TMS320F28335.
|
||||
*
|
||||
* init_zone7() настраивает внешнюю шину, pause_us() выполняет активную задержку.
|
||||
*/
|
||||
#ifndef TOOLS_H
|
||||
#define TOOLS_H
|
||||
|
||||
/** Настраивает 16-битную внешнюю шину XINTF Zone 7. */
|
||||
void init_zone7(void);
|
||||
/**
|
||||
* Выполняет активную задержку.
|
||||
* @param t Длительность в микросекундах при штатной частоте CPU.
|
||||
*/
|
||||
void pause_us(unsigned long t);
|
||||
|
||||
#endif //TOOLS_H
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
/**
|
||||
* @file RS485.c
|
||||
* @brief Драйвер двух каналов SCI/RS-485 и автоматы приёма/передачи кадров.
|
||||
*
|
||||
* Настраивает SCI-A/SCI-B, обслуживает RX/TX-прерывания, контролирует длины
|
||||
* команд и тайм-аут активности, а также переключает формат и скорость линии.
|
||||
* RS_DATA содержит разделяемое состояние конечного автомата; буферы должны
|
||||
* жить до завершения передачи и не превышать MAX_*_LENGTH. Обработчики обязаны
|
||||
* подтверждать PIE и корректно возвращать приоритеты прерываний.
|
||||
*/
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
RS485.с
|
||||
RS485.с
|
||||
****************************************************************
|
||||
* Процедуры работы с UART *
|
||||
* Процедуры работы с UART *
|
||||
****************************************************************/
|
||||
|
||||
//#include "big_dsp_module.h"
|
||||
@@ -32,7 +42,12 @@ static char size_cmd15=1;
|
||||
void RS_RX_Handler(RS_DATA *rs_arr);
|
||||
void RS_TX_Handler(RS_DATA *rs_arr);
|
||||
|
||||
/** Обработчик прерываний UART - принато */
|
||||
/** Обработчик прерываний UART - принато */
|
||||
/**
|
||||
* @brief ISR приёма SCI-A.
|
||||
* @details Временно ограничивает приоритеты группы PIE9, вызывает общий
|
||||
* RS_RX_Handler() для rs_a, затем восстанавливает маску и подтверждает группу.
|
||||
*/
|
||||
interrupt void RSA_RX_Handler(void)
|
||||
{
|
||||
// Set interrupt priority:
|
||||
@@ -51,6 +66,7 @@ interrupt void RSA_RX_Handler(void)
|
||||
PieCtrlRegs.PIEIER9.all = TempPIEIER;
|
||||
}
|
||||
|
||||
/** @brief ISR приёма SCI-B; адаптер общего автомата к состоянию rs_b. */
|
||||
interrupt void RSB_RX_Handler(void)
|
||||
{
|
||||
// Set interrupt priority:
|
||||
@@ -69,6 +85,7 @@ interrupt void RSB_RX_Handler(void)
|
||||
PieCtrlRegs.PIEIER9.all = TempPIEIER;
|
||||
}
|
||||
|
||||
/** @brief ISR освобождения TX SCI-A; продолжает передачу буфера rs_a. */
|
||||
interrupt void RSA_TX_Handler(void)
|
||||
{
|
||||
// Set interrupt priority:
|
||||
@@ -87,6 +104,7 @@ interrupt void RSA_TX_Handler(void)
|
||||
PieCtrlRegs.PIEIER9.all = TempPIEIER;
|
||||
}
|
||||
|
||||
/** @brief ISR освобождения TX SCI-B; продолжает передачу буфера rs_b. */
|
||||
interrupt void RSB_TX_Handler(void)
|
||||
{
|
||||
// Set interrupt priority:
|
||||
@@ -105,7 +123,15 @@ interrupt void RSB_TX_Handler(void)
|
||||
PieCtrlRegs.PIEIER9.all = TempPIEIER;
|
||||
}
|
||||
|
||||
/** Обработчик прерываний UART - принато */
|
||||
/** Обработчик прерываний UART - принато */
|
||||
/**
|
||||
* @brief Принимает очередной символ и продвигает автомат сборки кадра.
|
||||
* @param rs_arr Состояние порта, вызвавшего прерывание.
|
||||
* @details Проверяет аппаратные ошибки, адресный девятый бит, ожидаемую длину
|
||||
* команды и границы буфера. После полного кадра выставляет признак готовности
|
||||
* для foreground-кода; при нарушении синхронизации возвращается к ожиданию адреса.
|
||||
* @warning Выполняется из ISR и не должен вызывать блокирующие операции.
|
||||
*/
|
||||
void RS_RX_Handler(RS_DATA *rs_arr)
|
||||
{
|
||||
char Rc;
|
||||
@@ -113,16 +139,16 @@ void RS_RX_Handler(RS_DATA *rs_arr)
|
||||
|
||||
// led1_on();
|
||||
|
||||
for(;;) // 'goto' это не оператор азыка С
|
||||
for(;;) // 'goto' это не оператор азыка С
|
||||
{
|
||||
if(!rs_arr->SciRegs->SCIRXST.bit.RXRDY) // Receiver ready flag
|
||||
{
|
||||
PieCtrlRegs.PIEACK.bit.ACK9 |= 1;
|
||||
rs_arr->SciRegs->SCIFFRX.bit.RXFFINTCLR=1; // Clear INT flag
|
||||
return; // кстати это единственный выход из прерываниа
|
||||
return; // кстати это единственный выход из прерываниа
|
||||
}
|
||||
|
||||
Rc = rs_arr->SciRegs->SCIRXBUF.bit.RXDT; // Читаем символ в любом случае
|
||||
Rc = rs_arr->SciRegs->SCIRXBUF.bit.RXDT; // Читаем символ в любом случае
|
||||
|
||||
if(rs_arr->SciRegs->SCIRXST.bit.RXERROR) // Receiver error flag
|
||||
{
|
||||
@@ -132,42 +158,42 @@ void RS_RX_Handler(RS_DATA *rs_arr)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(rs_arr->RS_DataReady) continue; // Не забрали данные
|
||||
if(rs_arr->RS_DataReady) continue; // Не забрали данные
|
||||
|
||||
if (rs_arr->RS_Flag9bit==1) // дла RS485????????
|
||||
if (rs_arr->RS_Flag9bit==1) // дла RS485????????
|
||||
{
|
||||
// Инициализируем переменные и флаги
|
||||
rs_arr->RS_FlagBegin = true; // Ждем заголовок
|
||||
// Инициализируем переменные и флаги
|
||||
rs_arr->RS_FlagBegin = true; // Ждем заголовок
|
||||
rs_arr->RS_RecvLen = 0;
|
||||
rs_arr->RS_FlagSkiping = false;
|
||||
rs_arr->RS_HeaderCnt = 0;
|
||||
rs_arr->RS_Cmd = 0;
|
||||
}
|
||||
|
||||
if(rs_arr->RS_FlagSkiping) continue; // Не нам
|
||||
if(rs_arr->RS_FlagSkiping) continue; // Не нам
|
||||
|
||||
if (rs_arr->RS_FlagBegin) // Заголовок
|
||||
if (rs_arr->RS_FlagBegin) // Заголовок
|
||||
{
|
||||
if (rs_arr->RS_HeaderCnt==0) // Адрес контроллера или стандартнаа команда
|
||||
if (rs_arr->RS_HeaderCnt==0) // Адрес контроллера или стандартнаа команда
|
||||
{
|
||||
if( (Rc == CNTRL_ADDR_UNIVERSAL) || (Rc == CNTRL_ADDR && CNTRL_ADDR!=0) || ((Rc == rs_arr->addr_answer) && rs_arr->flag_LEADING)
|
||||
|| ((Rc == ADDR_FOR_ALL && ADDR_FOR_ALL!=0) && !rs_arr->flag_LEADING))
|
||||
|
||||
{
|
||||
rs_arr->addr_recive=Rc; // запомнили адрес по которому нас запросили
|
||||
rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc; // Первый байт
|
||||
RS_SetBitMode(rs_arr,8); // перестроились в 8-бит режим
|
||||
rs_arr->addr_recive=Rc; // запомнили адрес по которому нас запросили
|
||||
rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc; // Первый байт
|
||||
RS_SetBitMode(rs_arr,8); // перестроились в 8-бит режим
|
||||
}
|
||||
else
|
||||
{
|
||||
rs_arr->RS_FlagSkiping = true; // Не нашему контроллеру
|
||||
rs_arr->RS_FlagBegin = false; // остались в 9-бит режиме
|
||||
rs_arr->RS_FlagSkiping = true; // Не нашему контроллеру
|
||||
rs_arr->RS_FlagBegin = false; // остались в 9-бит режиме
|
||||
// led1_off();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc; // Второй байт и т.д.
|
||||
rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc; // Второй байт и т.д.
|
||||
|
||||
if (rs_arr->RS_HeaderCnt == 7 && rs_arr->RS_Cmd==CMD_MODBUS_16 && !rs_arr->flag_LEADING)
|
||||
{
|
||||
@@ -180,68 +206,75 @@ void RS_RX_Handler(RS_DATA *rs_arr)
|
||||
RS_Len[rs_arr->RS_Cmd] = Rc + 5;
|
||||
}
|
||||
|
||||
// если второй байт - это команда
|
||||
// если второй байт - это команда
|
||||
if (rs_arr->RS_HeaderCnt == 2)
|
||||
{
|
||||
rs_arr->RS_Cmd = Rc;
|
||||
// Проверка длины посылки
|
||||
// CMD_LOAD - младшаа на данный момент
|
||||
// CMD_STD_ANS - старшаа на данный момент
|
||||
// Проверка длины посылки
|
||||
// CMD_LOAD - младшаа на данный момент
|
||||
// CMD_STD_ANS - старшаа на данный момент
|
||||
if ((rs_arr->RS_Cmd < CMD_MODBUS_3) || (rs_arr->RS_Cmd > CMD_STD_ANS) || (RS_Len[rs_arr->RS_Cmd]<3)
|
||||
|| ((rs_arr->RS_Cmd == CMD_LOAD)&&(rs_arr->RS_PrevCmd != CMD_INITLOAD))
|
||||
)
|
||||
{
|
||||
RS_SetBitMode(rs_arr,9); // Получили все перестроились в 9-бит дла RS485?
|
||||
rs_arr->RS_HeaderCnt = 0; // Потому что команда не та
|
||||
RS_SetBitMode(rs_arr,9); // Получили все перестроились в 9-бит дла RS485?
|
||||
rs_arr->RS_HeaderCnt = 0; // Потому что команда не та
|
||||
rs_arr->RS_FlagBegin = true;
|
||||
rs_arr->RS_FlagSkiping = false;
|
||||
rs_arr->RS_Cmd=0;
|
||||
// led1_off();
|
||||
continue;
|
||||
}
|
||||
if (rs_arr->RS_Cmd == CMD_LOAD) // Дла этой команды заголовок очень короткий
|
||||
rs_arr->RS_FlagBegin = false;// дальше идут данные
|
||||
if (rs_arr->RS_Cmd == CMD_LOAD) // Дла этой команды заголовок очень короткий
|
||||
rs_arr->RS_FlagBegin = false;// дальше идут данные
|
||||
}
|
||||
|
||||
if( (rs_arr->RS_HeaderCnt >= RS_Len[rs_arr->RS_Cmd]) ||
|
||||
(rs_arr->RS_HeaderCnt >= sizeof(rs_arr->RS_Header)))
|
||||
{ // Получили заголовок
|
||||
RS_SetBitMode(rs_arr,9); // Получили все перестроились в 9-бит дла RS485?
|
||||
{ // Получили заголовок
|
||||
RS_SetBitMode(rs_arr,9); // Получили все перестроились в 9-бит дла RS485?
|
||||
rs_arr->RS_FlagBegin = false;
|
||||
rs_arr->RS_FlagSkiping = true;
|
||||
rs_arr->RS_DataReady = true;
|
||||
rs_arr->RS_Cmd=0;
|
||||
// led1_off();
|
||||
} } }
|
||||
else // Поток данных
|
||||
else // Поток данных
|
||||
{
|
||||
if(rs_arr->pRS_RecvPtr<(unsigned int *)Rec_Bloc_Begin || rs_arr->pRS_RecvPtr>(unsigned int *)Rec_Bloc_End)
|
||||
{
|
||||
rs_arr->pRS_RecvPtr = (unsigned int *)Rec_Bloc_Begin; // На программу надейса, а сам не плошай
|
||||
rs_arr->pRecvPtr = (unsigned int *)Rec_Bloc_Begin; // На программу надейса, а сам не плошай
|
||||
rs_arr->pRS_RecvPtr = (unsigned int *)Rec_Bloc_Begin; // На программу надейса, а сам не плошай
|
||||
rs_arr->pRecvPtr = (unsigned int *)Rec_Bloc_Begin; // На программу надейса, а сам не плошай
|
||||
}
|
||||
if(rs_arr->RS_PrevCmd != CMD_INITLOAD) continue; // Мы здесь оказались по какой-то чудовищной ошибке
|
||||
if(rs_arr->RS_PrevCmd != CMD_INITLOAD) continue; // Мы здесь оказались по какой-то чудовищной ошибке
|
||||
|
||||
if(rs_arr->RS_DataReady) // Если данные в основном цикле не забраны,
|
||||
{ // то пропускаем следующую посылку
|
||||
rs_arr->RS_FlagSkiping = true; // Игнорируем до следующего заголовка
|
||||
if(rs_arr->RS_DataReady) // Если данные в основном цикле не забраны,
|
||||
{ // то пропускаем следующую посылку
|
||||
rs_arr->RS_FlagSkiping = true; // Игнорируем до следующего заголовка
|
||||
// led1_off();
|
||||
continue;
|
||||
}
|
||||
RS_BytePtr = rs_arr->RS_RecvLen++ % 2;
|
||||
if(RS_BytePtr) *rs_arr->pRS_RecvPtr++ |= Rc; // Получили слово
|
||||
if(RS_BytePtr) *rs_arr->pRS_RecvPtr++ |= Rc; // Получили слово
|
||||
else *rs_arr->pRS_RecvPtr = Rc<<8;
|
||||
|
||||
if(rs_arr->RS_Length <= rs_arr->RS_RecvLen) // Конец посылки
|
||||
if(rs_arr->RS_Length <= rs_arr->RS_RecvLen) // Конец посылки
|
||||
{
|
||||
rs_arr->RS_PrevCmd = rs_arr->RS_Header[1] = CMD_LOAD;
|
||||
RS_SetBitMode(rs_arr,9); // Получили все данные перестроились в 9-бит дла RS485?
|
||||
rs_arr->RS_FlagSkiping = true; // Игнорируем до следующего заголовка
|
||||
rs_arr->RS_DataReady = true; // Флаг в основной цикл - данные получены
|
||||
RS_SetBitMode(rs_arr,9); // Получили все данные перестроились в 9-бит дла RS485?
|
||||
rs_arr->RS_FlagSkiping = true; // Игнорируем до следующего заголовка
|
||||
rs_arr->RS_DataReady = true; // Флаг в основной цикл - данные получены
|
||||
// led1_off();
|
||||
} } } }
|
||||
|
||||
/** Обработчик прерываний UART - послано */
|
||||
/** Обработчик прерываний UART - послано */
|
||||
/**
|
||||
* @brief Передаёт следующий элемент активного RS-485 буфера.
|
||||
* @param rs_arr Состояние обслуживаемого SCI.
|
||||
* @details Пока счётчик не достиг RS_Length, пишет следующий байт в SCITXBUF.
|
||||
* После последнего байта дожидается освобождения линии, возвращает трансивер
|
||||
* в режим приёма и сбрасывает состояние передачи.
|
||||
*/
|
||||
void RS_TX_Handler(RS_DATA *rs_arr)
|
||||
{
|
||||
char RS_BytePtr;
|
||||
@@ -251,18 +284,18 @@ void RS_TX_Handler(RS_DATA *rs_arr)
|
||||
{
|
||||
if(++rs_arr->RS_SendLen >= rs_arr->RS_SLength)
|
||||
{
|
||||
enableUARTInt(rs_arr); /* Запрещаем прерываниа по передаче */
|
||||
enableUARTInt(rs_arr); /* Запрещаем прерываниа по передаче */
|
||||
}
|
||||
SCI_send(rs_arr,*(rs_arr->pRS_SendPtr++));
|
||||
|
||||
if(rs_arr->RS_SendLen >= rs_arr->RS_SLength)
|
||||
{
|
||||
RS_Wait4OK(rs_arr);
|
||||
// for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */
|
||||
RS_SetBitMode(rs_arr,9); /* Передали все перестроились в 9-бит дла RS485?*/
|
||||
RS_Line_to_receive(rs_arr); /* режим приема RS485 */
|
||||
// for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */
|
||||
RS_SetBitMode(rs_arr,9); /* Передали все перестроились в 9-бит дла RS485?*/
|
||||
RS_Line_to_receive(rs_arr); /* режим приема RS485 */
|
||||
|
||||
rs_arr->flag_TIMEOUT_to_Send=false; /* сбросили флаг ожиданиа таймаута */
|
||||
rs_arr->flag_TIMEOUT_to_Send=false; /* сбросили флаг ожиданиа таймаута */
|
||||
}
|
||||
}
|
||||
else /* BM_PACKED */
|
||||
@@ -271,7 +304,7 @@ void RS_TX_Handler(RS_DATA *rs_arr)
|
||||
RS_BytePtr = (rs_arr->RS_SendLen++) % 2;
|
||||
if(rs_arr->RS_SendLen >= rs_arr->RS_SLength)
|
||||
{
|
||||
enableUARTInt(rs_arr); /* Запрещаем прерываниа по передаче */
|
||||
enableUARTInt(rs_arr); /* Запрещаем прерываниа по передаче */
|
||||
}
|
||||
if(RS_BytePtr) SCI_send(rs_arr, LOBYTE( *(rs_arr->pRS_SendPtr++) ));
|
||||
else SCI_send(rs_arr, HIBYTE( *rs_arr->pRS_SendPtr ));
|
||||
@@ -279,9 +312,9 @@ void RS_TX_Handler(RS_DATA *rs_arr)
|
||||
if(rs_arr->RS_SendLen >= rs_arr->RS_SLength)
|
||||
{
|
||||
RS_Wait4OK(rs_arr);
|
||||
// for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */
|
||||
// RS_SetBitMode(rs_arr,9); /* Передали все перестроились в 9-бит дла RS485?*/
|
||||
// RS_Line_to_receive(); /* режим приема RS485 */
|
||||
// for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */
|
||||
// RS_SetBitMode(rs_arr,9); /* Передали все перестроились в 9-бит дла RS485?*/
|
||||
// RS_Line_to_receive(); /* режим приема RS485 */
|
||||
|
||||
}
|
||||
}
|
||||
@@ -290,7 +323,11 @@ void RS_TX_Handler(RS_DATA *rs_arr)
|
||||
// rs_arr->SciRegs->SCIFFTX.bit.TXINTCLR=1; // Clear INT flag
|
||||
}
|
||||
|
||||
/** Инициализациа массива длин команд */
|
||||
/** Инициализациа массива длин команд */
|
||||
/**
|
||||
* @brief Заполняет таблицу ожидаемых длин сервисных и Modbus-команд.
|
||||
* @post RS_Len[код] содержит полную длину кадра для поддерживаемых команд.
|
||||
*/
|
||||
void setup_arr_cmd_length()
|
||||
{
|
||||
int i;
|
||||
@@ -317,86 +354,105 @@ void setup_arr_cmd_length()
|
||||
RS_Len[CMD_EXTEND] = 18;
|
||||
}
|
||||
|
||||
/** Настройка режима приема/передачи */
|
||||
/** Настройка режима приема/передачи */
|
||||
/**
|
||||
* @brief Переключает SCI между 8- и 9-битным форматом символа.
|
||||
* @param rs_arr Настраиваемый порт.
|
||||
* @param n Требуемое число бит данных.
|
||||
*/
|
||||
void RS_SetBitMode(RS_DATA *rs_arr,int n)
|
||||
{
|
||||
if(n == 8)
|
||||
{
|
||||
RS_SetLineMode(rs_arr,8,'N',1); /* режим линии */
|
||||
RS_SetLineMode(rs_arr,8,'N',1); /* режим линии */
|
||||
rs_arr->RS_Flag9bit=0;
|
||||
}
|
||||
if(n == 9)
|
||||
{
|
||||
RS_SetLineMode(rs_arr,8,'N',1); /* режим линии */
|
||||
RS_SetLineMode(rs_arr,8,'N',1); /* режим линии */
|
||||
rs_arr->RS_Flag9bit=1;
|
||||
} }
|
||||
|
||||
/** Посылка блока байтов.
|
||||
Посылает массива 32-битных целых чисел старшие биты должны быть 0.
|
||||
@precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR
|
||||
@param buf адрес массива
|
||||
@param len количество байт
|
||||
/** Посылка блока байтов.
|
||||
Посылает массива 32-битных целых чисел старшие биты должны быть 0.
|
||||
@precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR
|
||||
@param buf адрес массива
|
||||
@param len количество байт
|
||||
@see RS_BSend, RS_TRANSMIT_INTR */
|
||||
/**
|
||||
* @brief Запускает передачу массива, где один элемент хранит один байт.
|
||||
* @return 1 после успешного запуска, 0 если порт занят или длина недопустима.
|
||||
* @note Первый адресный символ отправляется в 9-битном режиме, оставшиеся — в 8-битном.
|
||||
*/
|
||||
int RS_Send(RS_DATA *rs_arr,unsigned int *pBuf,unsigned long len)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i=0; i <= 30000; i++){} /* Пауза дла PC */
|
||||
for (i=0; i <= 30000; i++){} /* Пауза дла PC */
|
||||
|
||||
RS_Line_to_send(rs_arr); /* режим передачи RS485 */
|
||||
RS_Line_to_send(rs_arr); /* режим передачи RS485 */
|
||||
|
||||
for (i=0; i <= 10000; i++){} /* Пауза дла PC */
|
||||
for (i=0; i <= 10000; i++){} /* Пауза дла PC */
|
||||
|
||||
rs_arr->RS_SLength = len; /* Настраиваем переменные */
|
||||
rs_arr->RS_SLength = len; /* Настраиваем переменные */
|
||||
rs_arr->pRS_SendPtr = pBuf + 1;
|
||||
|
||||
rs_arr->RS_SendBlockMode = BM_CHAR32;
|
||||
|
||||
RS_Wait4OK(rs_arr); /* Дожидаемса ухода */
|
||||
RS_SetBitMode(rs_arr,8); /* Остальные в 8-бит режиме */
|
||||
RS_Wait4OK(rs_arr); /* Дожидаемса ухода */
|
||||
RS_SetBitMode(rs_arr,8); /* Остальные в 8-бит режиме */
|
||||
|
||||
rs_arr->RS_SendLen = 1; /* Два байта уже передали */
|
||||
rs_arr->RS_SendLen = 1; /* Два байта уже передали */
|
||||
if(len > 1)
|
||||
{
|
||||
enableUARTIntW(rs_arr); /* Разрешаем прерываниа по передаче */
|
||||
SCI_send(rs_arr, *pBuf); // Передаем второй байт по прерыванию
|
||||
enableUARTIntW(rs_arr); /* Разрешаем прерываниа по передаче */
|
||||
SCI_send(rs_arr, *pBuf); // Передаем второй байт по прерыванию
|
||||
}
|
||||
else
|
||||
{
|
||||
SCI_send(rs_arr, *pBuf); // Передаем второй байт по прерыванию
|
||||
RS_Wait4OK(rs_arr); /* Дожидаемса ухода без прерываниа */
|
||||
for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */
|
||||
RS_SetBitMode(rs_arr,9); /* Обратно в 9-бит режим */
|
||||
RS_Line_to_receive(rs_arr); /* режим приема RS485 */
|
||||
SCI_send(rs_arr, *pBuf); // Передаем второй байт по прерыванию
|
||||
RS_Wait4OK(rs_arr); /* Дожидаемса ухода без прерываниа */
|
||||
for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */
|
||||
RS_SetBitMode(rs_arr,9); /* Обратно в 9-бит режим */
|
||||
RS_Line_to_receive(rs_arr); /* режим приема RS485 */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Посылка блока упакованных байтов
|
||||
// Посылка блока упакованных байтов
|
||||
/**
|
||||
* @brief Запускает передачу массива с байтами, упакованными в слова DSP.
|
||||
* @return 1 после успешного запуска, 0 при занятом порте или ошибке длины.
|
||||
*/
|
||||
int RS_BSend(RS_DATA *rs_arr,unsigned int *pBuf, unsigned long len)
|
||||
{
|
||||
|
||||
RS_Line_to_send(rs_arr); // режим передачи RS485
|
||||
RS_Line_to_send(rs_arr); // режим передачи RS485
|
||||
|
||||
rs_arr->RS_SLength = len; // Настраиваем переменные
|
||||
rs_arr->RS_SLength = len; // Настраиваем переменные
|
||||
rs_arr->pRS_SendPtr = pBuf;
|
||||
rs_arr->RS_SendBlockMode = BM_PACKED;
|
||||
|
||||
RS_Wait4OK(rs_arr); // Ожидаем очистки и ухода последнего байта
|
||||
RS_SetBitMode(rs_arr,8); /* Остальные в 8-бит режиме */
|
||||
RS_Wait4OK(rs_arr); // Ожидаем очистки и ухода последнего байта
|
||||
RS_SetBitMode(rs_arr,8); /* Остальные в 8-бит режиме */
|
||||
|
||||
rs_arr->RS_SendLen = 1; // Один байт уже передали
|
||||
rs_arr->RS_SendLen = 1; // Один байт уже передали
|
||||
|
||||
enableUARTIntW(rs_arr); /* Разрешаем прерываниа по передаче */
|
||||
enableUARTIntW(rs_arr); /* Разрешаем прерываниа по передаче */
|
||||
|
||||
SCI_send(rs_arr,HIBYTE(*pBuf));// Передаем первый байт
|
||||
SCI_send(rs_arr,HIBYTE(*pBuf));// Передаем первый байт
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Устанавливает скорость обмена.
|
||||
@param speed скорость RS в бод */
|
||||
/** Устанавливает скорость обмена.
|
||||
@param speed скорость RS в бод */
|
||||
/** Устанавливает скорость обмена.
|
||||
@param speed скорость RS в бод */
|
||||
/** Устанавливает скорость обмена.
|
||||
@param speed скорость RS в бод */
|
||||
/**
|
||||
* @brief Пересчитывает делитель baud-rate выбранного SCI.
|
||||
* @param speed Требуемая скорость в бодах.
|
||||
* @pre speed больше нуля и достижима от LSPCLK.
|
||||
*/
|
||||
void RS_SetLineSpeed(RS_DATA *rs_arr,unsigned long speed)
|
||||
{
|
||||
long SciBaud;
|
||||
@@ -410,7 +466,11 @@ void RS_SetLineSpeed(RS_DATA *rs_arr,unsigned long speed)
|
||||
}
|
||||
|
||||
|
||||
/** Инициализациа последовательного порта */
|
||||
/** Инициализациа последовательного порта */
|
||||
/**
|
||||
* @brief Обнуляет состояния обоих портов и создаёт таблицу длин команд.
|
||||
* @param size_cmd15_set Прикладная длина команды функции 15.
|
||||
*/
|
||||
void create_uart_vars(char size_cmd15_set)
|
||||
{
|
||||
size_cmd15=size_cmd15_set;
|
||||
@@ -420,8 +480,13 @@ void create_uart_vars(char size_cmd15_set)
|
||||
|
||||
|
||||
|
||||
/** Инициализациа последовательного порта */
|
||||
/** Инициализациа последовательного порта */
|
||||
|
||||
/**
|
||||
* @brief Назначает GPIO/векторы и запускает один из двух SCI-портов.
|
||||
* @param commnumber COM_1 для SCI-A либо COM_2 для SCI-B.
|
||||
* @param speed_baud Начальная скорость линии.
|
||||
*/
|
||||
void setup_uart(char commnumber, unsigned long speed_baud)
|
||||
{
|
||||
volatile struct SCI_REGS *SciRegs;
|
||||
@@ -485,14 +550,14 @@ void setup_uart(char commnumber, unsigned long speed_baud)
|
||||
SciRegs->SCICTL1.bit.RXENA=1;
|
||||
|
||||
SciRegs->SCIFFTX.bit.SCIFFENA=0; // fifo off
|
||||
SciRegs->SCIFFRX.bit.RXFFIL=1; // Длина наименьшей команды
|
||||
SciRegs->SCIFFRX.bit.RXFFIL=1; // Длина наименьшей команды
|
||||
|
||||
setup_arr_cmd_length();
|
||||
RS_SetLineSpeed(rs_arr,speed_baud); // скорость линии
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
enableUARTInt(rs_arr); // разрешение прерываний UART
|
||||
RS_SetLineSpeed(rs_arr,speed_baud); // скорость линии
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
enableUARTInt(rs_arr); // разрешение прерываний UART
|
||||
RS_SetBitMode(rs_arr,9);
|
||||
rs_arr->RS_PrevCmd = 0; // не было никаких команд
|
||||
rs_arr->RS_PrevCmd = 0; // не было никаких команд
|
||||
rs_arr->flag_TIMEOUT_to_Send = 0;
|
||||
rs_arr->flag_LEADING = 0;
|
||||
|
||||
@@ -500,10 +565,11 @@ void setup_uart(char commnumber, unsigned long speed_baud)
|
||||
SciRegs->SCICTL1.bit.SWRESET=1; // Relinquish SCI from Reset
|
||||
}
|
||||
|
||||
/** Настройка режима линии.
|
||||
@param bit количество бит данных
|
||||
@param parity режим четности (N,O,E,M,S)
|
||||
@param stop количество стоповых бит */
|
||||
/** Настройка режима линии.
|
||||
@param bit количество бит данных
|
||||
@param parity режим четности (N,O,E,M,S)
|
||||
@param stop количество стоповых бит */
|
||||
/** @brief Программирует длину слова, чётность и число стоп-битов SCI. */
|
||||
void RS_SetLineMode(RS_DATA *rs_arr, int bit, char parity, int stop)
|
||||
{
|
||||
volatile struct SCI_REGS *SciRegs;
|
||||
@@ -541,12 +607,14 @@ Bit Bit Name Designation Functions
|
||||
SciRegs->SCICCR.bit.ADDRIDLE_MODE = 0;
|
||||
}
|
||||
|
||||
/** @brief Отмечает успешную активность порта и сбрасывает его watchdog связи. */
|
||||
void clear_timer_rs_live(RS_DATA *rs_arr)
|
||||
{
|
||||
rs_arr->time_wait_rs_out=0;
|
||||
}
|
||||
|
||||
/* проверка на живучесть RS */
|
||||
/* проверка на живучесть RS */
|
||||
/** @brief Увеличивает watchdog связи и фиксирует тайм-аут удалённого узла. */
|
||||
void test_rs_live(RS_DATA *rs_arr)
|
||||
{
|
||||
/* if (rs_arr->time_wait_rs_out < RS_TIME_OUT)
|
||||
@@ -554,6 +622,6 @@ void test_rs_live(RS_DATA *rs_arr)
|
||||
else
|
||||
{
|
||||
rs_arr->time_wait_rs_out=0;
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_SetBitMode(rs_arr,9);
|
||||
}*/ }
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
/**
|
||||
* @file bios.c
|
||||
* @brief Сервисные команды удалённого доступа к памяти и загрузки программы.
|
||||
*
|
||||
* Реализует разбор BIOS-команд, формирование ответов, чтение/запись памяти,
|
||||
* загрузку блоков и запуск кода через транспорт RS-485. Адреса и размеры
|
||||
* приходят извне, поэтому корректность пакета и CRC должна быть подтверждена
|
||||
* до вызова обработчиков. Прямой доступ к памяти преднамеренно использует
|
||||
* volatile и требует адресов из допустимой карты памяти контроллера.
|
||||
*/
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
Bios.c
|
||||
**************************************************************
|
||||
Основные комманды BIOS *
|
||||
дла работы с RS232
|
||||
Основные комманды BIOS *
|
||||
дла работы с RS232
|
||||
****************************************************************/
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
#include "RS485.h"
|
||||
@@ -18,82 +28,95 @@
|
||||
//#include "spartan_tools.h"
|
||||
//#include "big_dsp_module.h"
|
||||
|
||||
int flag_DEBUG = false; /* Флаг отладочного режима */
|
||||
int flag_DEBUG = false; /* Флаг отладочного режима */
|
||||
|
||||
|
||||
//static unsigned int *RecvPtr;
|
||||
//static int BS_LoadOK = false; /** Флаг успешности приема блока */
|
||||
//static int BS_LoadOK = false; /** Флаг успешности приема блока */
|
||||
|
||||
/**********************************************************/
|
||||
/* Прототипы функций, используемых и определенных в файле */
|
||||
/* Прототипы функций, используемых и определенных в файле */
|
||||
/**********************************************************/
|
||||
//static int _getbyte(int *addr, int offs);
|
||||
|
||||
/** @brief Читает одно volatile-слово из физического адресного пространства DSP. */
|
||||
unsigned int read_memory(unsigned long addr)
|
||||
{
|
||||
return (*(volatile int *)(addr));
|
||||
}
|
||||
|
||||
/** @brief Записывает одно слово data по физическому адресу addr. */
|
||||
void write_memory(unsigned long addr, unsigned int data)
|
||||
{
|
||||
(*(volatile int *)( addr )) = data;
|
||||
}
|
||||
|
||||
|
||||
/** Возвращает номер комманды, если есть или -1 если транзакций не было */
|
||||
/** Возвращает номер комманды, если есть или -1 если транзакций не было */
|
||||
/**
|
||||
* @brief Проверяет и диспетчеризует полностью принятый сервисный кадр.
|
||||
* @param rs_arr Порт и буфер принятой команды.
|
||||
* @return Код распознанной команды либо признак ошибки кадра.
|
||||
* @details Проверяет адрес, длину и CRC, затем вызывает обработчик CMD_*.
|
||||
*/
|
||||
int get_command(RS_DATA *rs_arr)
|
||||
{
|
||||
int cmd;
|
||||
unsigned int crc, rcrc;
|
||||
|
||||
if(rs_arr->RS_DataReady) // Данные по RS пришли
|
||||
if(rs_arr->RS_DataReady) // Данные по RS пришли
|
||||
{
|
||||
rs_arr->RS_DataReady = false;
|
||||
cmd = rs_arr->RS_Header[1]; // Прочитали номер команды
|
||||
cmd = rs_arr->RS_Header[1]; // Прочитали номер команды
|
||||
|
||||
// Провераем длину команды дла считываниа CRC
|
||||
// Провераем длину команды дла считываниа CRC
|
||||
if((RS_Len[cmd]<3) || (RS_Len[cmd]>MAX_RECEIVE_LENGTH))
|
||||
{
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_SetBitMode(rs_arr,9);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(cmd == CMD_LOAD) // Если команда загрузки
|
||||
if(cmd == CMD_LOAD) // Если команда загрузки
|
||||
{
|
||||
rs_arr->RS_PrevCmd = cmd;
|
||||
return cmd; // Нет проверки crc
|
||||
return cmd; // Нет проверки crc
|
||||
}
|
||||
else // Все остальные команды
|
||||
else // Все остальные команды
|
||||
{
|
||||
// Считываем crc из посылки
|
||||
// Считываем crc из посылки
|
||||
crc = (rs_arr->RS_Header[RS_Len[cmd]-1] << 8) |
|
||||
(rs_arr->RS_Header[RS_Len[cmd]-2]) ;
|
||||
}
|
||||
// Рассчитываем crc из посылки
|
||||
// Рассчитываем crc из посылки
|
||||
rcrc = 0xffff;
|
||||
rcrc = get_crc_16( rcrc, rs_arr->RS_Header, (RS_Len[cmd]-2) );
|
||||
|
||||
if(crc == rcrc) // Провераем crc
|
||||
if(crc == rcrc) // Провераем crc
|
||||
{
|
||||
rs_arr->RS_PrevCmd = cmd;
|
||||
return cmd;
|
||||
}
|
||||
else
|
||||
{
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_SetBitMode(rs_arr,9);
|
||||
} }
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Стандартный ответ, без параметров */
|
||||
/** Стандартный ответ, без параметров */
|
||||
/**
|
||||
* @brief Добавляет CRC и отправляет n слов ответа через исходный порт.
|
||||
* @param rs_arr Порт, через который пришёл запрос.
|
||||
* @param n Число информационных слов до CRC.
|
||||
*/
|
||||
void Answer(RS_DATA *rs_arr,int n)
|
||||
{
|
||||
int crc;
|
||||
|
||||
flag_DEBUG = true; // Флаг отладочного режима
|
||||
flag_DEBUG = true; // Флаг отладочного режима
|
||||
|
||||
rs_arr->buffer[0] = rs_arr->addr_recive; //CNTRL_ADDR;
|
||||
rs_arr->buffer[1] = n;
|
||||
@@ -109,7 +132,7 @@ void Answer(RS_DATA *rs_arr,int n)
|
||||
RS_Send(rs_arr,rs_arr->buffer, 6);
|
||||
}
|
||||
|
||||
/* Внутреннаа ф-циа */
|
||||
/* Внутреннаа ф-циа */
|
||||
static char _getbyte(unsigned int *addr, int32 offs)
|
||||
{
|
||||
unsigned int *address;
|
||||
@@ -122,7 +145,8 @@ static char _getbyte(unsigned int *addr, int32 offs)
|
||||
}
|
||||
|
||||
|
||||
/* начальные установки (не работает)*/
|
||||
/* начальные установки (не работает)*/
|
||||
/** @brief Сбрасывает параметры текущей загрузочной сессии и подтверждает команду. */
|
||||
void init(RS_DATA *rs_arr)
|
||||
{
|
||||
/*
|
||||
@@ -145,13 +169,18 @@ void init(RS_DATA *rs_arr)
|
||||
*/
|
||||
}
|
||||
|
||||
/**@name Комманды
|
||||
* Комманды, вызываемые через последовательный канал
|
||||
/**@name Комманды
|
||||
* Комманды, вызываемые через последовательный канал
|
||||
*/
|
||||
//@{
|
||||
|
||||
/** Инициировать загрузку блока.
|
||||
Настраивает прием блока данных */
|
||||
/** Инициировать загрузку блока.
|
||||
Настраивает прием блока данных */
|
||||
/**
|
||||
* @brief Принимает заголовок нового образа и подготавливает диапазон загрузки.
|
||||
* @details Из кадра извлекаются начальный адрес, длина и контрольные параметры;
|
||||
* запись данных разрешается только после успешной проверки заголовка.
|
||||
*/
|
||||
void initload(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned long Address;
|
||||
@@ -175,8 +204,12 @@ void initload(RS_DATA *rs_arr)
|
||||
Answer(rs_arr,CMD_INITLOAD);
|
||||
}
|
||||
|
||||
/** Загрузка блока.
|
||||
Вызываетса после загрузки блока через RS */
|
||||
/** Загрузка блока.
|
||||
Вызываетса после загрузки блока через RS */
|
||||
/**
|
||||
* @brief Записывает очередную порцию образа по текущему адресу загрузки.
|
||||
* @post Рабочий адрес и остаток длины продвинуты на принятый блок.
|
||||
*/
|
||||
void load(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned int rcrc, crc;
|
||||
@@ -201,27 +234,32 @@ void load(RS_DATA *rs_arr)
|
||||
else
|
||||
{
|
||||
rs_arr->BS_LoadOK = false;
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_SetBitMode(rs_arr,9);
|
||||
} }
|
||||
|
||||
/** Выполнить программу в формате Serial Boot.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес программы беретса из заголовка и
|
||||
сравниваетса с переменной RecvPtr, заполнаемой в ф-ции load
|
||||
/** Выполнить программу в формате Serial Boot.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес программы беретса из заголовка и
|
||||
сравниваетса с переменной RecvPtr, заполнаемой в ф-ции load
|
||||
@see load */
|
||||
/** @brief Подтверждает команду и передаёт управление загруженной программе. */
|
||||
void run (RS_DATA *rs_arr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/** Прочитать ачейку памати */
|
||||
/** Прочитать ачейку памати */
|
||||
/**
|
||||
* @brief Возвращает содержимое заданного диапазона памяти.
|
||||
* @warning Диапазон должен быть предварительно разрешён протокольным уровнем.
|
||||
*/
|
||||
void peek(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned long Address;
|
||||
unsigned int Data, crc;
|
||||
|
||||
flag_DEBUG = true; // Флаг отладочного режима
|
||||
flag_DEBUG = true; // Флаг отладочного режима
|
||||
|
||||
Address = rs_arr->RS_Header[5] & 0xFF;
|
||||
Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
|
||||
@@ -254,7 +292,8 @@ void peek(RS_DATA *rs_arr)
|
||||
|
||||
}
|
||||
|
||||
/** Записать в ачейку памати */
|
||||
/** Записать в ачейку памати */
|
||||
/** @brief Записывает данные команды в заданную область памяти и отвечает статусом. */
|
||||
void poke(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned long Address;
|
||||
@@ -276,12 +315,13 @@ void poke(RS_DATA *rs_arr)
|
||||
Answer(rs_arr,CMD_POKE);
|
||||
}
|
||||
|
||||
/** Передать блок памати */
|
||||
/** Передать блок памати */
|
||||
/** @brief Передаёт ведущему очередной блок ранее выбранной области памяти. */
|
||||
void upload(RS_DATA *rs_arr)
|
||||
{
|
||||
int32 Address, Length, crc;
|
||||
|
||||
no_write = 1; // Флаг отладочного режима
|
||||
no_write = 1; // Флаг отладочного режима
|
||||
// stopp=1;
|
||||
|
||||
Address = rs_arr->RS_Header[5] & 0xFF;
|
||||
@@ -301,10 +341,10 @@ void upload(RS_DATA *rs_arr)
|
||||
crc = get_crc_16( crc, rs_arr->buffer, 2);
|
||||
crc = get_crc_16b( crc, (unsigned int *)Address, Length);
|
||||
|
||||
RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 байт по флагу
|
||||
RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 байт по флагу
|
||||
|
||||
rs_arr->buffer[0] = CMD_UPLOAD;
|
||||
RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 байт по флагу
|
||||
RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 байт по флагу
|
||||
|
||||
RS_Wait4OK(rs_arr);
|
||||
RS_BSend(rs_arr,(unsigned int*)Address, Length);
|
||||
@@ -318,22 +358,24 @@ void upload(RS_DATA *rs_arr)
|
||||
|
||||
}
|
||||
|
||||
/** Прошить XILINX.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load,
|
||||
так же смотрит магическое слово в начале прошивки
|
||||
/** Прошить XILINX.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load,
|
||||
так же смотрит магическое слово в начале прошивки
|
||||
@see load */
|
||||
/** @brief Обрабатывает совместимую команду программирования внешней логики. */
|
||||
void xflash(RS_DATA *rs_arr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/** Прошить TMS.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
|
||||
/** Прошить TMS.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
|
||||
@see load */
|
||||
/** @brief Обрабатывает команду программирования памяти целевого контроллера. */
|
||||
void tflash(RS_DATA *rs_arr)
|
||||
{
|
||||
// volatile unsigned long Address1,Address2;
|
||||
@@ -341,7 +383,7 @@ void tflash(RS_DATA *rs_arr)
|
||||
/*
|
||||
if(!rs_arr->BS_LoadOK)
|
||||
{
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_SetBitMode(rs_arr,9);
|
||||
return;
|
||||
}
|
||||
@@ -366,7 +408,7 @@ void tflash(RS_DATA *rs_arr)
|
||||
|
||||
if( (Address2 < 0x100000) || (Address2 > 0x180000) || ((Address2+LengthW) > 0x180000) )
|
||||
{
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_Line_to_receive(rs_arr); // режим приема RS485
|
||||
RS_SetBitMode(rs_arr,9);
|
||||
return;
|
||||
}
|
||||
@@ -378,11 +420,15 @@ void tflash(RS_DATA *rs_arr)
|
||||
return;
|
||||
}
|
||||
|
||||
/** Прошить TMS.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
|
||||
/** Прошить TMS.
|
||||
@precondition Должна быть произведена загрузка блока
|
||||
Адрес и длина прошивки беретса из заголовка и
|
||||
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
|
||||
@see load */
|
||||
/**
|
||||
* @brief Выполняет расширенную BIOS-команду, не входящую в базовый набор.
|
||||
* @details Подкоманда и её аргументы извлекаются из принятого сервисного кадра.
|
||||
*/
|
||||
void extendbios(RS_DATA *rs_arr)
|
||||
{
|
||||
volatile unsigned long Address1,Address2,Length;
|
||||
@@ -407,10 +453,10 @@ void extendbios(RS_DATA *rs_arr)
|
||||
|
||||
switch ( code )
|
||||
{
|
||||
// Прошиваем EPROM Из RAM
|
||||
// Прошиваем EPROM Из RAM
|
||||
case 4: Seeprom_write(Address1,(unsigned int*)Address2,Length);
|
||||
break;
|
||||
// Читаем из EPROM в RAM
|
||||
// Читаем из EPROM в RAM
|
||||
case 5: Seeprom_read(Address1,(unsigned int*)Address2,Length);
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
/**
|
||||
* @file cntrl_adr.c
|
||||
* @brief Хранение и изменение сетевых адресов контроллера.
|
||||
*
|
||||
* Содержит рабочий, широковещательный, ответный и терминальный адреса узла.
|
||||
* set_cntrl_addr() меняет только изменяемые адреса; вызывающий код отвечает
|
||||
* за проверку диапазона и за отсутствие обмена во время перенастройки.
|
||||
*/
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2000 г. */
|
||||
/****************************************************************
|
||||
cntrl_adr.c
|
||||
****************************************************************
|
||||
* Адрес контроллера *
|
||||
* Адрес контроллера *
|
||||
****************************************************************/
|
||||
|
||||
#include "cntrl_adr.h"
|
||||
@@ -16,27 +24,34 @@
|
||||
#define ADDR_UNIVERSAL_DEF 10
|
||||
|
||||
|
||||
/** Установка адреса контроллера дла посылки всем АИНам */
|
||||
/** Установка адреса контроллера дла посылки всем АИНам */
|
||||
int ADDR_FOR_ALL = ADDR_FOR_ALL_DEF;
|
||||
|
||||
/** Установка адреса контроллера дла посылки ответа */
|
||||
/** Установка адреса контроллера дла посылки ответа */
|
||||
const int ADDR_ANSWER = ADDR_ANSWER_DEF;
|
||||
|
||||
/** Установка адреса терминала дла посылки ответа */
|
||||
/** Установка адреса терминала дла посылки ответа */
|
||||
const int ADDR_TERMINAL = ADDR_TERMINAL_DEF;
|
||||
|
||||
/* Универсальный адрес контроллера */
|
||||
/* Универсальный адрес контроллера */
|
||||
const int CNTRL_ADDR_UNIVERSAL=ADDR_UNIVERSAL_DEF;
|
||||
|
||||
/* Адрес контроллера */
|
||||
/* Адрес контроллера */
|
||||
int CNTRL_ADDR=1;
|
||||
|
||||
int cntr_addr_c;
|
||||
int cntr_addr_c_all;
|
||||
|
||||
/** Установка адреса контроллера дла прошивки */
|
||||
/** Установка адреса контроллера дла прошивки */
|
||||
/**
|
||||
* @brief Одновременно обновляет индивидуальный и групповой адреса узла.
|
||||
* @param cntrl_addr Новый адрес данного контроллера.
|
||||
* @param cntrl_addr_for_all Адрес, по которому принимаются групповые команды.
|
||||
* @note Проверка допустимого диапазона выполняется уровнем конфигурации.
|
||||
*/
|
||||
void set_cntrl_addr (int cntrl_addr,int cntrl_addr_for_all)
|
||||
{
|
||||
/* Пара адресов меняется в одном месте, исключая смешанную конфигурацию. */
|
||||
CNTRL_ADDR = cntrl_addr;
|
||||
ADDR_FOR_ALL = cntrl_addr_for_all;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file crc16.c
|
||||
* @brief Расчёт контрольных сумм CRC-CCITT и CRC-16 для протокольных кадров.
|
||||
*
|
||||
* Поддерживает табличные и побитовые варианты алгоритмов. Текущая конфигурация
|
||||
* FAST_CRC/ONLY_CRC16 оставляет в прошивке только требуемый быстрый CRC-16.
|
||||
* Размер задаётся в элементах буфера целевой платформы, а не в байтах host-PC;
|
||||
* начальное значение CRC определяет вызывающий протокол.
|
||||
*/
|
||||
#include "crc16.h"
|
||||
#define MAKE_TABS 0 /* Builds tables below */
|
||||
#define FAST_CRC 1 /* If fast CRC should be used */
|
||||
@@ -87,6 +96,13 @@ WORD crc_16_tab[] = {
|
||||
|
||||
/* CRC-CCITT is based on the polynomial x^16 + x^12 + x^5 + 1. Bits */
|
||||
/* are sent MSB to LSB. */
|
||||
/**
|
||||
* @brief Продолжает расчёт CRC-CCITT по массиву слов.
|
||||
* @param crc Начальное значение либо CRC предыдущего блока.
|
||||
* @param buf Буфер данных; значим младший байт каждого слова.
|
||||
* @param size Число обрабатываемых элементов.
|
||||
* @return Итоговое 16-битное значение CRC-CCITT.
|
||||
*/
|
||||
unsigned int get_crc_ccitt(unsigned int crc,unsigned int *buf,unsigned long size )
|
||||
{
|
||||
#if !(FAST_CRC & !MAKE_TABS)
|
||||
@@ -112,6 +128,13 @@ unsigned int get_crc_ccitt(unsigned int crc,unsigned int *buf,unsigned long size
|
||||
|
||||
/* CRC-16 is based on the polynomial x^16 + x^15 + x^2 + 1. Bits are */
|
||||
/* sent LSB to MSB. */
|
||||
/**
|
||||
* @brief Вычисляет быстрый табличный CRC-16 с отражённым полиномом 0xA001.
|
||||
* @param crc Начальное значение или результат предыдущей порции.
|
||||
* @param buf Входные слова протокольного кадра.
|
||||
* @param size Количество слов.
|
||||
* @return CRC после обработки всего блока.
|
||||
*/
|
||||
unsigned int get_crc_16(unsigned int crc,unsigned int *buf,unsigned long size )
|
||||
{
|
||||
#if !(FAST_CRC & !MAKE_TABS)
|
||||
@@ -139,6 +162,11 @@ unsigned int get_crc_16(unsigned int crc,unsigned int *buf,unsigned long size )
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Побитовый эталон расчёта CRC-16 без таблицы.
|
||||
* @details Используется как компактная реализация и для сверки табличного
|
||||
* варианта; восемь итераций обрабатывают каждый входной байт.
|
||||
*/
|
||||
unsigned int get_crc_16b(unsigned int crc,unsigned int *buf,unsigned long size )
|
||||
{
|
||||
|
||||
@@ -175,6 +203,12 @@ unsigned long i;
|
||||
return (crc & 0xffff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проектная обёртка CRC-16 с установленным протоколом начальным значением.
|
||||
* @param buf Кадр без добавляемого поля CRC.
|
||||
* @param size Число элементов кадра.
|
||||
* @return Контрольная сумма, готовая для сравнения или передачи.
|
||||
*/
|
||||
int get_crc16(unsigned int *buf, int size )
|
||||
{
|
||||
int crc16,i,j;
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file ecan.c
|
||||
* @brief Инициализация eCAN, передача кадров и обработка CAN-прерываний.
|
||||
*
|
||||
* Настраивает выбранный CAN-контроллер и mailbox, нормализует номер устройства,
|
||||
* отправляет данные и ведёт счётчики приёма, передачи и ошибок. Регистры eCAN
|
||||
* изменяются через shadow-копии согласно требованиям C2000; обработчики должны
|
||||
* подтверждать источник прерывания и не задерживать остальные группы PIE.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
|
||||
@@ -30,6 +39,14 @@ int CanTimeOutErrorTR = 0;
|
||||
|
||||
int wait=0;
|
||||
|
||||
/**
|
||||
* @brief Настраивает eCAN-A и его почтовые ящики для выбранного номера узла.
|
||||
* @param Port Номер интерфейса; текущая аппаратная реализация использует CAN-A.
|
||||
* @param DevNum Номер устройства 1..16, насыщаемый реализацией на границах.
|
||||
* @details Регистры управления изменяются через ECanShadow, чтобы исключить
|
||||
* опасные read-modify-write операции над регистрами с особыми битами.
|
||||
* @post Разрешены приёмные mailbox и прерывания CAN, счётчики ошибок сброшены.
|
||||
*/
|
||||
void InitCan(int Port, int DevNum)
|
||||
{
|
||||
struct ECAN_REGS ECanShadow;
|
||||
@@ -40,6 +57,7 @@ void InitCan(int Port, int DevNum)
|
||||
|
||||
long id = 0x80BA0000;
|
||||
|
||||
/* Протокольная нумерация начинается с 1, аппаратное поле — с 0. */
|
||||
DevNum--;
|
||||
if(DevNum<0)DevNum=0;
|
||||
if(DevNum>15)DevNum=15;
|
||||
@@ -66,16 +84,16 @@ void InitCan(int Port, int DevNum)
|
||||
// Required before writing the MSGIDs
|
||||
ECanRegs->CANME.all = 0;
|
||||
|
||||
// задаем адрес 0 ащикa на передачу
|
||||
// задаем адрес 0 ащикa на передачу
|
||||
ECanMboxes->MBOX0.MSGID.all = id + 0x10 + DevNum;
|
||||
|
||||
// задаем адрес 1 ащикa на прием
|
||||
ECanMboxes->MBOX1.MSGID.all = id + DevNum; //поменать!!!! 1 и 0!!!
|
||||
// задаем адрес 1 ащикa на прием
|
||||
ECanMboxes->MBOX1.MSGID.all = id + DevNum; //поменать!!!! 1 и 0!!!
|
||||
|
||||
// задаем режимы работы ащикa 0 на передачу, остальные на прием
|
||||
// задаем режимы работы ащикa 0 на передачу, остальные на прием
|
||||
ECanRegs->CANMD.all = 0xFFFFFFFE;
|
||||
|
||||
// выбираем только 2 ащикa дла работы, остальные запрещаем
|
||||
// выбираем только 2 ащикa дла работы, остальные запрещаем
|
||||
ECanRegs->CANME.all = 0x00000003;
|
||||
|
||||
// Clear all TAn bits
|
||||
@@ -100,7 +118,7 @@ void InitCan(int Port, int DevNum)
|
||||
ECanRegs->CANMC.all = ECanShadow.CANMC.all;
|
||||
while(!ECanRegs->CANES.bit.CCE); // Wait for CCE bit to be set..
|
||||
|
||||
// настриваем скорость CAN
|
||||
// настриваем скорость CAN
|
||||
ECanShadow.CANBTC.all = ECanRegs->CANBTC.all;
|
||||
ECanShadow.CANBTC.bit.SJWREG=1;
|
||||
|
||||
@@ -113,7 +131,7 @@ void InitCan(int Port, int DevNum)
|
||||
ECanRegs->CANMC.all = ECanShadow.CANMC.all;
|
||||
while(ECanRegs->CANES.bit.CCE); // Wait for CCE bit to be cleared..
|
||||
|
||||
// задаем таймауты дла ожиданиа отправки получениа посылки
|
||||
// задаем таймауты дла ожиданиа отправки получениа посылки
|
||||
ECanMOTORegs->MOTO0 = 550000;
|
||||
ECanMOTORegs->MOTO1 = 550000;
|
||||
|
||||
@@ -140,7 +158,7 @@ void InitCan(int Port, int DevNum)
|
||||
IER |= M_INT9; // Enable CPU INT
|
||||
EDIS;
|
||||
|
||||
// завершили настройку CAN ащиков
|
||||
// завершили настройку CAN ащиков
|
||||
|
||||
MessageReceivedCount = 0;
|
||||
ErrorCount = 0;
|
||||
@@ -148,6 +166,14 @@ void InitCan(int Port, int DevNum)
|
||||
MessageTransivedCount=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Формирует и запускает передачу одного прикладного CAN-кадра.
|
||||
* @param Port Номер CAN-интерфейса.
|
||||
* @param data Слова полезной нагрузки в формате проекта.
|
||||
* @param Addr Идентификатор/адрес получателя.
|
||||
* @note Перед записью mailbox проверяется завершение предыдущей передачи;
|
||||
* тайм-аут отражается в CanTimeOutErrorTR.
|
||||
*/
|
||||
void CAN_send(int Port, int data[], int Addr)
|
||||
{
|
||||
unsigned long hiword,loword;
|
||||
@@ -177,13 +203,19 @@ void CAN_send(int Port, int data[], int Addr)
|
||||
ECanRegs->CANTSC = 0; // clear time-out counter
|
||||
EDIS;
|
||||
|
||||
ECanRegs->CANTRS.all = 1; // запустить передачу
|
||||
ECanRegs->CANTRS.all = 1; // запустить передачу
|
||||
|
||||
wait=1;
|
||||
led1_toggle();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Разбирает данные сработавшего приёмного mailbox.
|
||||
* @param ECanMboxes Набор mailbox активного CAN-контроллера.
|
||||
* @details Копирует полезную нагрузку в CAN_input_data и обновляет счётчик
|
||||
* принятых сообщений; подтверждение аппаратного флага выполняет вызывающий ISR.
|
||||
*/
|
||||
void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
|
||||
{
|
||||
unsigned int adr;
|
||||
@@ -215,6 +247,11 @@ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
|
||||
led2_toggle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Основной ISR eCAN-A для приёма кадров и завершения передачи.
|
||||
* @details Определяет источник по CANRMP/CANTA, вызывает Handlai() для входного
|
||||
* mailbox, очищает обслуженные флаги и подтверждает группу PIE9.
|
||||
*/
|
||||
interrupt void CANa_handler(void)
|
||||
{
|
||||
// Set interrupt priority:
|
||||
@@ -234,6 +271,11 @@ interrupt void CANa_handler(void)
|
||||
PieCtrlRegs.PIEIER9.all = TempPIEIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ISR линии ошибок eCAN-A.
|
||||
* @details Сохраняет диагностические счётчики, очищает причину ошибки и
|
||||
* возвращает контроллер к приёму, не меняя прикладную адресацию mailbox.
|
||||
*/
|
||||
interrupt void CANa_reset_err(void)
|
||||
{
|
||||
// Set interrupt priority:
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
/**
|
||||
* @file filter_bat2.c
|
||||
* @brief Один шаг рекурсивного фильтра второго порядка.
|
||||
*
|
||||
* filterbat() вычисляет новый выход по текущему входу и сохранённой истории,
|
||||
* затем сдвигает состояние FILTERBAT. Каждый независимый сигнал обязан иметь
|
||||
* собственный экземпляр структуры; коэффициенты задаются в filter_bat2.h и
|
||||
* предполагают фиксированную частоту вызова, использованную при их расчёте.
|
||||
*/
|
||||
#include "filter_bat2.h"
|
||||
|
||||
/**
|
||||
* @brief Вычисляет очередной отсчёт IIR-фильтра второго порядка.
|
||||
* @param b Коэффициенты и история конкретного фильтруемого канала.
|
||||
* @param InpVarCurr Текущий нефильтрованный отсчёт.
|
||||
* @return Отфильтрованное значение.
|
||||
* @pre b указывает на инициализированный объект FILTERBAT.
|
||||
* @post История двух предыдущих входов и выходов сдвинута на один отсчёт.
|
||||
*/
|
||||
float filterbat(FILTERBAT *b, float InpVarCurr)
|
||||
{
|
||||
float y;
|
||||
|
||||
/* Прямая ветвь использует текущий и два предыдущих входных отсчёта. */
|
||||
y = (b->k_0 * (InpVarCurr + (b->i_0*2) + b->i_1)) +
|
||||
/* Рекурсивная ветвь возвращает два предыдущих выхода фильтра. */
|
||||
(b->k_1 * b->u_0) + (b->k_2 * b->u_1);
|
||||
|
||||
/* Сначала сдвигается старая история, затем сохраняются новые значения. */
|
||||
b->u_1=b->u_0;
|
||||
b->u_0=y;
|
||||
b->i_1=b->i_0;
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file kanal.c
|
||||
* @brief Последовательный вывод числовых данных на канальный индикатор.
|
||||
*
|
||||
* Управляет линиями DCLK/DOUT, формирует импульс сброса и передаёт разряды
|
||||
* индикатора с учётом адреса, десятичной точки и множителя тактовой частоты.
|
||||
* Задержки и таблица сегментов привязаны к внешней схеме; изменение GPIO или
|
||||
* CLKMULT требует повторной проверки временной диаграммы.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
#include "filter_bat2.h"
|
||||
@@ -15,12 +24,14 @@
|
||||
int digits[16] = {63,6,91,79,102,109,125,7,127,111,64,0,0,0,121,0};
|
||||
int readr[5] = {0x08,0x0C,0x10,0x00,0x04};
|
||||
|
||||
/** @brief Устанавливает тактовую линию канального последовательного интерфейса. */
|
||||
void DCLK(int x)
|
||||
{
|
||||
if(x) GpioDataRegs.GPASET.bit.GPIO6=1;
|
||||
else GpioDataRegs.GPACLEAR.bit.GPIO6=1;
|
||||
}
|
||||
|
||||
/** @brief Устанавливает линию данных канального последовательного интерфейса. */
|
||||
void DOUT(int x)
|
||||
{
|
||||
if(x) GpioDataRegs.GPASET.bit.GPIO8=1;
|
||||
@@ -48,6 +59,10 @@ void DOUT(int x)
|
||||
#define POWS1 80L
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Формирует последовательность сброса внешних регистров индикатора.
|
||||
* @note Число холостых тактов является частью аппаратного протокола.
|
||||
*/
|
||||
void RESET()
|
||||
{
|
||||
DCLK(0);
|
||||
@@ -64,6 +79,7 @@ void RESET()
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @brief Выдаёт один бит данных и сопровождающий его импульс DCLK. */
|
||||
void SENDBIT(int x)
|
||||
{
|
||||
DOUT(x); DCLK(1);
|
||||
@@ -78,12 +94,20 @@ void SENDBIT(int x)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Кодирует адрес и число и передаёт их семисегментному индикатору.
|
||||
* @param adr Адрес физического канала.
|
||||
* @param dat Значение для отображения.
|
||||
* @param dot Позиция десятичной точки.
|
||||
* @details Таблица digits преобразует цифры в сегменты; знак и ведущие позиции
|
||||
* обрабатываются до побитовой отправки каждого разряда.
|
||||
*/
|
||||
void kanal_Send(int adr, long dat, int dot)
|
||||
{
|
||||
long Word,data,aliq_part,dg[4];
|
||||
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;
|
||||
}
|
||||
@@ -134,7 +158,7 @@ void kanal_Send(int adr, long dat, int dot)
|
||||
for(i=3;i>0;i--)
|
||||
{
|
||||
if((dg[i]==0)&&(i!=dot))
|
||||
dg[i]=0xF; // Это значит пусто
|
||||
dg[i]=0xF; // Это значит пусто
|
||||
else break;
|
||||
}
|
||||
|
||||
@@ -143,7 +167,7 @@ void kanal_Send(int adr, long dat, int dot)
|
||||
{
|
||||
if( (dg[i]==0xF)||(i==3))
|
||||
{
|
||||
dg[i]=0xA; // Это значит минус
|
||||
dg[i]=0xA; // Это значит минус
|
||||
break;
|
||||
} }
|
||||
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
/**
|
||||
* @file log_to_mem.c
|
||||
* @brief Кольцевой журнал событий во внешней области памяти.
|
||||
*
|
||||
* Резервирует секцию .logg, хранит границы и текущий адрес журнала и очищает
|
||||
* всю отведённую область по запросу. LOG_PAGE_START/LOG_PAGE_LEN должны
|
||||
* соответствовать linker command file; clear_mem() выполняет длительную
|
||||
* блокирующую запись и не предназначена для вызова из обработчика прерывания.
|
||||
*/
|
||||
/****************************************************************/
|
||||
/* TMS320C32 */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2001г. */
|
||||
/* ====== BIOS, КЛАИН, КЛВСП ====== */
|
||||
/* ЦНИИ СЭТ (с) 1998-2001г. */
|
||||
/****************************************************************/
|
||||
/* log_to_mem.c
|
||||
****************************************************************
|
||||
* Запись логов в памyть *
|
||||
* Запись логов в памyть *
|
||||
****************************************************************/
|
||||
|
||||
#include "log_to_mem.h"
|
||||
|
||||
int no_write = 0,
|
||||
never_write = 0; // Флаги, чтобы не писать (если что)
|
||||
never_write = 0; // Флаги, чтобы не писать (если что)
|
||||
|
||||
#pragma DATA_SECTION(logs_block,".logg");
|
||||
unsigned int logs_block[0xFA00];
|
||||
@@ -19,7 +28,13 @@ unsigned int logs_block[0xFA00];
|
||||
LOG Log;
|
||||
unsigned int flog=0;
|
||||
|
||||
// Очищение памати, где логи лежат
|
||||
// Очищение памати, где логи лежат
|
||||
/**
|
||||
* @brief Сбрасывает метаданные и физически очищает всю область журнала.
|
||||
* @post Log.Adres установлен в LOG_PAGE_START, Log.Circl сброшен, а каждое
|
||||
* слово выделенной области равно нулю.
|
||||
* @warning Функция блокируется на LOG_PAGE_LEN операций внешней памяти.
|
||||
*/
|
||||
void clear_mem()
|
||||
{
|
||||
unsigned long i;
|
||||
@@ -29,6 +44,7 @@ void clear_mem()
|
||||
Log.Adres = Log.Start;
|
||||
Log.Circl = 0;
|
||||
|
||||
/* Полуинтервал [Start, Finis) исключает запись за последним словом секции. */
|
||||
for (i=Log.Start; i<Log.Finis; i++)
|
||||
*(volatile int *)i = 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file main.c
|
||||
* @brief Точка входа и основной диспетчер периферийной прошивки Balsam 167.
|
||||
*
|
||||
* Выполняет инициализацию тактирования, GPIO, интерфейсов и измерительных
|
||||
* модулей, выбирает обработчик Timer1 по типу платы и затем координирует CAN,
|
||||
* RS-485, команды и контроль состояния. Порядок инициализации важен: глобальные
|
||||
* прерывания разрешаются только после настройки таблицы PIE и зависимых блоков.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
|
||||
#include "cntrl_adr.h"
|
||||
@@ -23,6 +32,13 @@
|
||||
#include "measure.h"
|
||||
extern void DSP28x_usDelay(Uint32 Count);
|
||||
|
||||
/**
|
||||
* @brief Настраивает CPU Timer1 и выбирает его ISR по роли платы.
|
||||
* @details Для пульта используется cpu_timer1_isr_PULT(), для остальных ролей
|
||||
* — измерительный cpu_timer1_isr_SENS(). Период равен одному тику READY_FREQ.
|
||||
* @pre Desk уже считан из конфигурационных GPIO.
|
||||
* @post Вектор XINT13 установлен, Timer1 запущен, CPU INT13 разрешён.
|
||||
*/
|
||||
void timer_Init()
|
||||
{
|
||||
EALLOW; // This is needed to write to EALLOW protected registers
|
||||
@@ -35,6 +51,17 @@ void timer_Init()
|
||||
IER |= M_INT13;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализирует устройство и выполняет бесконечный диспетчерский цикл.
|
||||
*
|
||||
* @details Последовательно поднимает системное тактирование, внешнюю память,
|
||||
* PIE, GPIO, UART, EEPROM, CAN, АЦП и таймеры. Затем обслуживает завершённые
|
||||
* RS-485 кадры, сервисные команды, CAN-периодику, кнопки и контроль связи.
|
||||
* Точные ветви исполнения определяются Desk и опциями package.h.
|
||||
*
|
||||
* @warning Порядок запуска существенен: ISR не должны сработать до создания
|
||||
* буферов, установки векторов и инициализации разделяемого состояния.
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
int i,j,mask;
|
||||
@@ -46,8 +73,10 @@ void main()
|
||||
InitSysCtrl();
|
||||
|
||||
// Disable CPU interrupts and clear all CPU interrupt flags:
|
||||
/* Конфигурация PIE и периферии выполняется при запрещённых прерываниях CPU. */
|
||||
DINT;
|
||||
|
||||
/* После сброса PIE источники разрешаются отдельно каждым драйвером. */
|
||||
InitPieCtrl();
|
||||
|
||||
IER = 0x0000;
|
||||
@@ -56,6 +85,7 @@ void main()
|
||||
InitPieVectTable();
|
||||
init_zone7();
|
||||
|
||||
/* Роль платы определяет дальнейшую разводку ADC, GPIO и Timer1 ISR. */
|
||||
get_Mode();
|
||||
InitCan(0,Mode);
|
||||
|
||||
@@ -83,6 +113,7 @@ void main()
|
||||
clear_mem();
|
||||
set_cntrl_addr(Mode,16);
|
||||
timer_Init();
|
||||
/* Все базовые векторы и транспортные состояния готовы к обслуживанию ISR. */
|
||||
EnableInterrupts();
|
||||
|
||||
if(Desk!=dsk_EPLT)
|
||||
@@ -104,8 +135,10 @@ void main()
|
||||
SysCtrlRegs.WDCR= 0x2F;
|
||||
EDIS;
|
||||
|
||||
/* READY разрешает измерительному ADC ISR использовать накопленные данные. */
|
||||
READY=1;
|
||||
|
||||
/* Foreground-цикл обрабатывает события, подготовленные ISR и таймерами. */
|
||||
while(1)
|
||||
{
|
||||
if(CanGO)
|
||||
@@ -206,16 +239,16 @@ void main()
|
||||
led2_toggle();
|
||||
switch(j)
|
||||
{
|
||||
case CMD_INIT: init(rs); break; // íŕ÷ŕëüíűĺ óńňŕíîâęč
|
||||
case CMD_INITLOAD: initload(rs); break; // íŕńňđîéęŕ çŕăđóçęč
|
||||
case CMD_RUN: run(rs); break; // çŕăđóçčňü áëîę
|
||||
case CMD_LOAD: load(rs); break; // çŕăđóçčňü áëîę
|
||||
case CMD_PEEK: peek(rs); break; // ďđî÷čňŕňü ŕ÷ĺéęó ďŕěŕňč
|
||||
case CMD_POKE: poke(rs); break; // çŕďčńŕňü â ŕ÷ĺéęó ďŕěŕňč
|
||||
case CMD_UPLOAD: upload(rs); break; // ďĺđĺäŕňü áëîę ďŕěŕňč
|
||||
case CMD_EXTEND: extendbios(rs); break; // đŕńřčđĺííűĺ ęîěŕíäű äëŕ áčîńŕ
|
||||
case CMD_INIT: init(rs); break; // начальные установки
|
||||
case CMD_INITLOAD: initload(rs); break; // настройка загрузки
|
||||
case CMD_RUN: run(rs); break; // загрузить блок
|
||||
case CMD_LOAD: load(rs); break; // загрузить блок
|
||||
case CMD_PEEK: peek(rs); break; // прочитать ачейку памати
|
||||
case CMD_POKE: poke(rs); break; // записать в ачейку памати
|
||||
case CMD_UPLOAD: upload(rs); break; // передать блок памати
|
||||
case CMD_EXTEND: extendbios(rs); break; // расширенные команды дла биоса
|
||||
|
||||
case CMD_TFLASH: tflash(rs); break; // ďđîřčňü TMS
|
||||
case CMD_TFLASH: tflash(rs); break; // прошить TMS
|
||||
|
||||
case CMD_MODBUS_3: ReceiveCommandModbus3(rs); break;
|
||||
case CMD_MODBUS_6: ReceiveCommandModbus6(rs); break;
|
||||
|
||||
@@ -1,3 +1,27 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Обработка измерительных каналов, индикации и защит устройства.
|
||||
*
|
||||
* @details
|
||||
* Модуль выполняет настройку каналов датчиков, фильтрацию результатов АЦП,
|
||||
* пересчёт токов, напряжений и температур в физические величины, формирование
|
||||
* диагностических признаков, а также подготовку масок передаваемых данных.
|
||||
* Обработчик CPU Timer1 обслуживает сторожевой таймер, период запуска CAN-обмена
|
||||
* и световую индикацию.
|
||||
*
|
||||
* Модуль использует глобальные параметры конфигурации, таблицы измерений и
|
||||
* аппаратные функции, объявленные в подключаемых заголовочных файлах проекта.
|
||||
*
|
||||
* @note Исходная исполняемая логика сохранена; добавлены комментарии
|
||||
* в формате Doxygen и поясняющие комментарии непосредственно внутри кода.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sensor_processing Обработка датчиков и диагностик
|
||||
* @brief Инициализация, измерение, фильтрация и контроль измерительных каналов.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
#include "filter_bat2.h"
|
||||
@@ -14,85 +38,187 @@
|
||||
#include "message.h"
|
||||
#include "log_to_mem.h"
|
||||
|
||||
#include <math.h> // Это чтобы мерить амплитуду! sqrt без этого будет крив!!!
|
||||
#include <math.h> // Это чтобы мерить амплитуду! sqrt без этого будет крив!!!
|
||||
|
||||
/**
|
||||
* @brief Состояние периодического запуска CAN-обмена.
|
||||
*
|
||||
* `CanPowse` увеличивается обработчиком таймера до значения `CANPOWSE`.
|
||||
* При достижении порога счётчик сбрасывается, а `CanGO` устанавливается в 1.
|
||||
*/
|
||||
unsigned int CanPowse=CANPOWSE,CanGO=0;
|
||||
|
||||
/**
|
||||
* @brief Битовые маски состава быстрых и медленных пакетов.
|
||||
*
|
||||
* Первый индекс выбирает режим передачи (`m_FAST` или `m_SLOW`), второй —
|
||||
* 16-битное слово общей таблицы данных.
|
||||
*/
|
||||
unsigned int Maska[2][8];
|
||||
|
||||
int READY=0; // Все загрузилос
|
||||
/** @brief Флаг завершения начальной загрузки и готовности модуля. */
|
||||
int READY=0; // Все загрузилос
|
||||
|
||||
int TPL_CANS=0; // Количество температурных каналов
|
||||
int tpl_cans=0; // Количество температурных датчиков
|
||||
int cal_addr=0; // Начало калибровочных датчиков
|
||||
int pow_addr=0; // Начало датчиков напражениа\тока
|
||||
/** @brief Настроенное количество температурных групп TPL для текущего режима. */
|
||||
int TPL_CANS=0; // Количество температурных каналов
|
||||
/** @brief Фактическое количество логических температурных каналов. */
|
||||
int tpl_cans=0; // Количество температурных датчиков
|
||||
/** @brief Индекс начала калибровочных каналов в общей таблице датчиков. */
|
||||
int cal_addr=0; // Начало калибровочных датчиков
|
||||
/** @brief Индекс начала каналов измерения напряжения и тока. */
|
||||
int pow_addr=0; // Начало датчиков напражениа\\тока
|
||||
|
||||
/**
|
||||
* @brief Периоды, используемые логикой готовности и мигания индикации.
|
||||
*/
|
||||
int period_ready, period_blink;
|
||||
|
||||
/**
|
||||
* @brief Накопленные и зафиксированные сводные признаки состояния.
|
||||
*
|
||||
* `chk` накапливает признаки в текущем цикле обработки каналов, а `sig`
|
||||
* получает снимок накопленного состояния при начале следующего цикла.
|
||||
*/
|
||||
FLAG chk,sig;
|
||||
/**
|
||||
* @brief Временные интервалы, выраженные в периодах обработки АЦП.
|
||||
*
|
||||
* Значения рассчитываются функцией Init_sensors() из частоты `ADC_FREQ`.
|
||||
*/
|
||||
unsigned int time_1_5sec, time_5msec, time_3sec, time_5sec;
|
||||
|
||||
/** @brief Счётчики выдержки пониженного уровня для двух силовых каналов. */
|
||||
unsigned int low_count[2] = {0,0};
|
||||
/** @brief Интегрирующие счётчики ошибок по фазным значениям. */
|
||||
unsigned int err_count[6];
|
||||
/** @brief Действующие значения измеряемых фаз, полученные из lev_quadr[]. */
|
||||
int lev_count[6];
|
||||
/** @brief Состояния фильтра квадратов мгновенных фазных значений. */
|
||||
float lev_quadr[6];
|
||||
/** @brief Оценки среднего, то есть нулевого, уровня четырёх каналов АЦП. */
|
||||
float zer_count[4];
|
||||
|
||||
/** @brief Тип каждого логического измерительного канала. */
|
||||
int sens_type[24];
|
||||
/** @brief Индекс парного канала для совместной диагностики и вычислений. */
|
||||
int sens_pair[24];
|
||||
/** @brief Счётчики фильтрации диагностик дискретных входов. */
|
||||
unsigned int din_count[32];
|
||||
|
||||
/** @brief Температуры, полученные от внешних измерительных устройств. */
|
||||
int ext_temp[8];
|
||||
/** @brief Диагностические состояния внешних температурных каналов. */
|
||||
int ext_diag[8];
|
||||
|
||||
/** @brief Рабочий счётчик времени процедуры калибровки. */
|
||||
unsigned int Caliber_time = 0;
|
||||
/** @brief Минимальный уровень тока, при котором контролируется перекос фаз. */
|
||||
int Curr_Edge;
|
||||
/**
|
||||
* @brief Маска состояний, исключающих канал из выбора опорных данных имитации.
|
||||
*/
|
||||
ERROR okay;
|
||||
|
||||
/**
|
||||
* @brief Коэффициенты пересчёта кодов АЦП в физические величины.
|
||||
*
|
||||
* Начальные значения соответствуют типам питающих каналов. Первые четыре
|
||||
* коэффициента могут быть переопределены функцией calc_sensor_koef() по
|
||||
* калибровочным значениям `Caliber[]`.
|
||||
*/
|
||||
float powK[] =
|
||||
{
|
||||
0.127, // питание 380В
|
||||
0.127, // питание 380В
|
||||
0.127, // питание 380В
|
||||
0.127, // питание 380В
|
||||
|
||||
1.000, // ток
|
||||
1.000, // напражение
|
||||
1.000, // ток
|
||||
1.000, // напражение
|
||||
|
||||
0.0076, // питание 31В
|
||||
0.0076, // питание 24В
|
||||
0.0076, // питание 24В
|
||||
0.0076, // питание 15В
|
||||
1.0000, // термодатчик мелкосхема
|
||||
0.0076, // питание 31В
|
||||
0.0076, // питание 24В
|
||||
0.0076, // питание 24В
|
||||
0.0076, // питание 15В
|
||||
1.0000, // термодатчик мелкосхема
|
||||
};
|
||||
|
||||
/** @brief Шаблон начального состояния цифрового фильтра. */
|
||||
FILTERBAT def_FILTERBAT = DEF_FILTERBAT;
|
||||
FILTERBAT adc_filter[20+4]; // макс.TPL*2 + 4 калибр
|
||||
FILTERBAT out_filter[20+4]; // макс.TPL*2 + 4 напраж
|
||||
FILTERBAT zer_filter[4]; // 4 напраж
|
||||
/** @brief Фильтры входных значений АЦП и калибровочных каналов. */
|
||||
FILTERBAT adc_filter[20+4]; // макс.TPL*2 + 4 калибр
|
||||
/** @brief Вторичные фильтры выходных и калибровочных значений. */
|
||||
FILTERBAT out_filter[20+4]; // макс.TPL*2 + 4 напраж
|
||||
/** @brief Фильтры оценок нулевого уровня четырёх силовых каналов. */
|
||||
FILTERBAT zer_filter[4]; // 4 напраж
|
||||
|
||||
/** @brief Рабочие счётчики состояний измерительных каналов. */
|
||||
long sens_count[24+4];
|
||||
|
||||
/** @brief Коэффициенты пересчёта температурных каналов групп 100 и 50. */
|
||||
float K100,K_50;
|
||||
/** @brief Коэффициенты пересчёта первой и второй температурных ветвей. */
|
||||
float K_T1,K_T2;
|
||||
|
||||
/**
|
||||
* @brief Обработчик прерывания CPU Timer1 для обслуживания датчиков и индикации.
|
||||
*
|
||||
* Обработчик обслуживает сторожевой таймер, формирует периодический флаг
|
||||
* `CanGO`, управляет индикацией готовности, аварии и нагрева, а в режиме
|
||||
* `dsk_LOAD` передаёт выполнение функции Load_runner().
|
||||
*
|
||||
* @note Функция использует статические счётчики ШИМ яркости и мигания ламп.
|
||||
*/
|
||||
interrupt void cpu_timer1_isr_SENS(void);
|
||||
|
||||
/********************************************************************/
|
||||
/* Расчет модула тока из показаний двух фаз */
|
||||
/********************************************************************/
|
||||
/**
|
||||
* @brief Рассчитывает модуль трёхфазного вектора по двум измеренным фазам.
|
||||
*
|
||||
* @param ia Мгновенное значение первой измеренной фазы.
|
||||
* @param ib Мгновенное значение второй измеренной фазы.
|
||||
*
|
||||
* @return Модуль результирующего вектора в тех же единицах, что и входы.
|
||||
*
|
||||
* @note Расчёт предполагает, что третья фаза может быть восстановлена из
|
||||
* условия `ia + ib + ic = 0`.
|
||||
*/
|
||||
float im_calc(float ia,float ib)
|
||||
{
|
||||
float isa,isb;
|
||||
|
||||
|
||||
/*
|
||||
* Из двух измеренных фаз формируются две взаимно перпендикулярные
|
||||
* составляющие результирующего трёхфазного вектора. Третья фаза
|
||||
* подразумевается равной -(ia + ib).
|
||||
*/
|
||||
isa = - 1.5 * (ia + ib);
|
||||
|
||||
/* COSPi6 = cos(pi/6) = sqrt(3)/2; эта составляющая зависит от разности фаз. */
|
||||
isb = COSPi6 * (ia - ib);
|
||||
|
||||
/* Нормировка 2/3 возвращает модуль в масштабе исходных фазных величин. */
|
||||
return (2*sqrt(isa*isa+isb*isb)/3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Пересчитывает коэффициенты преобразования измерительных каналов.
|
||||
*
|
||||
* Для температурных каналов коэффициенты выбираются по активному варианту
|
||||
* `TermoRS` или `TermoAD`. Коэффициенты первых четырёх силовых каналов
|
||||
* рассчитываются из массива `Caliber[]` с учётом типа канала.
|
||||
*
|
||||
* @pre Разности калибровочных точек, используемые как делители, не равны нулю.
|
||||
* @post Обновлены `K100`, `K_50`, `K_T1`, `K_T2` и `powK[0..3]` в зависимости
|
||||
* от выбранной конфигурации.
|
||||
*/
|
||||
void calc_sensor_koef()
|
||||
{
|
||||
int i;
|
||||
float K;
|
||||
|
||||
/*
|
||||
* Вариант резистивных температурных датчиков. Коэффициент равен
|
||||
* заданному температурному диапазону, делённому на разность двух
|
||||
* сохранённых калибровочных кодов АЦП.
|
||||
*/
|
||||
if(TermoRS)
|
||||
{
|
||||
K100 = 129.0/(K150_D - K100_D);
|
||||
@@ -101,6 +227,10 @@ void calc_sensor_koef()
|
||||
K_T2 = 129.0/(K150_2 - K100_2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Вариант аналоговых термодатчиков: для каждой ветви используется
|
||||
* собственная пара калибровочных точек K300/K400.
|
||||
*/
|
||||
if(TermoAD)
|
||||
{
|
||||
K_T1 = 100.0/(K400_1 - K300_1);
|
||||
@@ -108,66 +238,101 @@ void calc_sensor_koef()
|
||||
}
|
||||
|
||||
// if(Kurrent)
|
||||
/* Перевод пользовательских калибровок первых четырёх каналов в float-масштаб. */
|
||||
for(i=0;i<4;i++)
|
||||
{
|
||||
K = Caliber[i];
|
||||
|
||||
/* Для тока и остальных величин калибровка хранится с разным десятичным масштабом. */
|
||||
if(sens_type[i]==CURRENT) K/=1000.0;
|
||||
else K/=10000.0;
|
||||
|
||||
powK[i] = K;
|
||||
} }
|
||||
|
||||
/** @copydoc cpu_timer1_isr_SENS */
|
||||
interrupt void cpu_timer1_isr_SENS(void)
|
||||
{
|
||||
/*
|
||||
* Статические переменные сохраняют фазу программного ШИМ яркости,
|
||||
* фазу мигания и требуемые логические состояния ламп между прерываниями.
|
||||
*/
|
||||
static unsigned int
|
||||
count_blink=0, count_bright=0, count_mode,
|
||||
blink_over, blink_alarm, work_lamp, heat_lamp, power_lamp;
|
||||
|
||||
/* Предыдущее состояние теста нужно для обнаружения фронта команды тестирования. */
|
||||
static int preTest;
|
||||
|
||||
/* Объединённый запрос теста ламп от двух источников управления. */
|
||||
int TST;
|
||||
|
||||
#define err_lamp work_lamp // это дла шкапа,
|
||||
#define alm_lamp heat_lamp // чтоб было понатнее
|
||||
#define err_lamp work_lamp // Для исполнения шкафа первый светодиод трактуется как «Ошибка».
|
||||
#define alm_lamp heat_lamp // Второй светодиод трактуется как «Авария».
|
||||
|
||||
/*
|
||||
* Разрешается запись в защищённые регистры, обновляется статистика таймера
|
||||
* и настраивается маска прерываний. EINT разрешает вложенные прерывания
|
||||
* с приоритетом, оставленным маской MINT13.
|
||||
*/
|
||||
EALLOW;
|
||||
CpuTimer1.InterruptCount++;
|
||||
IER |= M_INT13; // Set "global" priority
|
||||
IER &= MINT13; // Set "global" priority
|
||||
EINT;
|
||||
EDIS; // This is needed to disable write to EALLOW protected registers
|
||||
EDIS; // Запрет дальнейшей записи в защищённые EALLOW-регистры.
|
||||
|
||||
/* Во время активного сброса сторожевой таймер намеренно не обслуживается. */
|
||||
if(!cReset) ServiceDog();
|
||||
|
||||
/* Делитель частоты: один раз в CANPOWSE прерываний разрешается очередной CAN-цикл. */
|
||||
if(++CanPowse >= CANPOWSE)
|
||||
{
|
||||
CanPowse = 0;
|
||||
CanGO = 1;
|
||||
}
|
||||
|
||||
/* Тест включён, если установлен хотя бы один из двух командных флагов. */
|
||||
TST = cTestLamp|bTestLamp;
|
||||
|
||||
/*
|
||||
* Индикатор READY мигает при отсутствии ошибки; тест ламп принудительно
|
||||
* разрешает его переключение. Здесь применено побитовое OR для флагов 0/1.
|
||||
*/
|
||||
if(!sig.bit.Error|TST) toggle_READY();
|
||||
else clear_READY();
|
||||
|
||||
/* В исполнении нагрузки дальнейшей индикацией занимается отдельный автомат. */
|
||||
if(Desk==dsk_LOAD)
|
||||
{
|
||||
Load_runner();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Начало нового периода программного ШИМ яркости. Нужные выходы сначала
|
||||
* включаются согласно логическим состояниям ламп, а ниже будут выключены
|
||||
* при достижении значения Brightness.
|
||||
*/
|
||||
if(++count_bright == maximum_bright)
|
||||
{
|
||||
count_bright = 0 ;
|
||||
|
||||
/* Назначение дискретного RES_OUT_1 зависит от исполнения устройства. */
|
||||
if( ((Desk==dsk_SHKF) && power_lamp) ||
|
||||
((Desk==dsk_COMM) && heat_lamp) ) set_RES_OUT_1();
|
||||
else clear_RES_OUT_1();
|
||||
|
||||
if(work_lamp) set_LED_OUT_1(); // Она же err_lamp дла шкапа
|
||||
if(work_lamp) set_LED_OUT_1(); // Она же err_lamp для шкафа.
|
||||
else clear_LED_OUT_1();
|
||||
if(heat_lamp) set_LED_OUT_2(); // Она же alm_lamp дла шкапа
|
||||
if(heat_lamp) set_LED_OUT_2(); // Она же alm_lamp для шкафа.
|
||||
else clear_LED_OUT_2();
|
||||
}
|
||||
|
||||
/*
|
||||
* Конец активной части ШИМ. В режиме теста выходы не гасятся по Brightness,
|
||||
* поэтому лампы проверяются с полной заданной логической активностью.
|
||||
*/
|
||||
if(!TST)
|
||||
if(count_bright == Brightness)
|
||||
{
|
||||
@@ -176,6 +341,7 @@ interrupt void cpu_timer1_isr_SENS(void)
|
||||
clear_RES_OUT_1();
|
||||
}
|
||||
|
||||
/* На фронте теста немедленно запускается новый цикл мигания с известной фазы. */
|
||||
if(TST & !preTest)
|
||||
{
|
||||
count_blink = BLINK_TIME;
|
||||
@@ -183,13 +349,19 @@ interrupt void cpu_timer1_isr_SENS(void)
|
||||
}
|
||||
preTest = TST;
|
||||
|
||||
/* Обновление медленной фазы индикации выполняется один раз за BLINK_TIME. */
|
||||
if(++count_blink >= BLINK_TIME)
|
||||
{
|
||||
count_blink=0;
|
||||
count_mode++;
|
||||
|
||||
/* Быстрый шаблон меняет состояние на каждом шаге. */
|
||||
blink_over = (count_mode & 1)?1:0;
|
||||
|
||||
/* Медленный шаблон равен нулю только на каждом восьмом шаге. */
|
||||
blink_alarm = (count_mode & 7)?1:0;
|
||||
|
||||
/* При тесте все лампы получают один и тот же мигающий шаблон. */
|
||||
if(TST)
|
||||
{
|
||||
heat_lamp = blink_over;
|
||||
@@ -198,13 +370,18 @@ interrupt void cpu_timer1_isr_SENS(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Отдельная схема индикации для шкафа. */
|
||||
if(Mode==adr_SHKF)
|
||||
{
|
||||
/* Наличие питания показывается постоянно, пока нет общей ошибки. */
|
||||
power_lamp= 1;
|
||||
|
||||
/* Общая авария мигает на выходе alm_lamp. */
|
||||
if(sig.bit.Alarm){// power_lamp= blink_alarm;
|
||||
alm_lamp = blink_over; }
|
||||
else alm_lamp = 0;
|
||||
|
||||
/* Ошибка останова заставляет одновременно мигать питание и err_lamp. */
|
||||
if(sig.bit.Error){ power_lamp= blink_over;
|
||||
err_lamp = blink_over; }
|
||||
else err_lamp = 0;
|
||||
@@ -214,22 +391,45 @@ interrupt void cpu_timer1_isr_SENS(void)
|
||||
// if(sig.bit.Error) work_lamp = blink_over;
|
||||
// else if(sig.bit.Alarm) work_lamp = blink_alarm;
|
||||
// else
|
||||
/* В штатном режиме лампа работы горит непрерывно. */
|
||||
work_lamp = 1;
|
||||
|
||||
/* Секретная команда заменяет постоянное свечение медленным шаблоном. */
|
||||
if(bSecretBt|cSecretBt) work_lamp = blink_alarm;
|
||||
|
||||
/*
|
||||
* Температурная индикация имеет приоритет: перегрев — постоянно,
|
||||
* предупреждение — быстрое мигание, обрыв — короткий импульс
|
||||
* на каждом восьмом шаге.
|
||||
*/
|
||||
if(sig.bit.OverHeat) heat_lamp = 1;
|
||||
else if(sig.bit.SubHeat) heat_lamp = blink_over;
|
||||
else if(sig.bit.OutHeat) heat_lamp = !blink_alarm;
|
||||
else heat_lamp = 0;
|
||||
} } } }
|
||||
|
||||
/**
|
||||
* @brief Выполняет базовую инициализацию измерительных каналов.
|
||||
*
|
||||
* Функция определяет число и размещение каналов по `Mode`, назначает типы и
|
||||
* пары датчиков, сбрасывает фильтры и счётчики, настраивает специальные каналы
|
||||
* для выбранного исполнения `Desk`, а также переводит временные выдержки из
|
||||
* секунд в число периодов `ADC_FREQ`.
|
||||
*
|
||||
* @post Инициализированы таблицы `sens_type[]`, `sens_pair[]`, фильтры,
|
||||
* диагностические счётчики и маска `okay`.
|
||||
*/
|
||||
void Init_sensors()
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
/* Сначала формируется пустая карта каналов; далее её заполняет выбранный Mode. */
|
||||
TPL_CANS = tpl_cans = cal_addr = 0;
|
||||
|
||||
/*
|
||||
* Определение числа температурных каналов и позиции калибровочных входов.
|
||||
* В режимах TRN/POW на одну группу TPL приходится два логических датчика.
|
||||
*/
|
||||
switch(Mode)
|
||||
{
|
||||
case adr_TRN1:
|
||||
@@ -246,17 +446,24 @@ void Init_sensors()
|
||||
case adr_SHKF: tpl_cans = TPL_SHK; cal_addr = tpl_cans-2; break;
|
||||
}
|
||||
|
||||
/* Силовые каналы размещаются после локальных и внешних температурных каналов. */
|
||||
pow_addr = tpl_cans + Owen;
|
||||
|
||||
/* Общие значения по умолчанию для всей статической таблицы датчиков. */
|
||||
for(i=0;i<24;i++)
|
||||
{
|
||||
/* Тип 0 означает, что специальная обработка каналу пока не назначена. */
|
||||
sens_type[i]=0;
|
||||
|
||||
/* До явной настройки парным считается сам канал. */
|
||||
sens_pair[i]=i;
|
||||
|
||||
/* Каждый канал получает независимое начальное состояние обоих фильтров. */
|
||||
adc_filter[i] = def_FILTERBAT;
|
||||
out_filter[i] = def_FILTERBAT;
|
||||
}
|
||||
|
||||
/* Назначение типа всем локальным температурным каналам. */
|
||||
if(TermoSW)
|
||||
for(i=0;i<tpl_cans;i++)
|
||||
{
|
||||
@@ -264,32 +471,45 @@ void Init_sensors()
|
||||
if(TermoAD) sens_type[i] = TERMO_AD;
|
||||
}
|
||||
|
||||
/* Внешние каналы OWEN следуют непосредственно за локальными температурами. */
|
||||
for(i=0;i<Owen;i++)
|
||||
{
|
||||
sens_type[tpl_cans+i] = TRM_OBEH;
|
||||
}
|
||||
|
||||
/* Настройка четырёхканального тракта измерения тока/напряжения. */
|
||||
if(Kurrent)
|
||||
{
|
||||
/* Ниже этого RMS-уровня контроль перекоса фаз не выполняется. */
|
||||
Curr_Edge = 200;
|
||||
|
||||
for(i=0;i<4;i++)
|
||||
{
|
||||
/* Базово все четыре силовых входа считаются каналами напряжения. */
|
||||
sens_type[pow_addr+i]=VOLTAGE;
|
||||
|
||||
/* XOR с 1 образует пары 0<->1 и 2<->3. */
|
||||
sens_pair[pow_addr+i]=pow_addr+(i^1);
|
||||
|
||||
/* Старт оценки нуля с последнего сохранённого значения. */
|
||||
zer_count[i] = Zero_lev[i];
|
||||
zer_filter[i] = def_FILTERBAT;
|
||||
} }
|
||||
|
||||
/* Для стенда нагрузки вторая пара силовых входов измеряет ток. */
|
||||
if(Desk==dsk_LOAD)
|
||||
{
|
||||
/* Для этого исполнения контроль перекоса начинается с более высокого уровня. */
|
||||
Curr_Edge = 300;
|
||||
|
||||
sens_type[2]=
|
||||
sens_type[3]=CURRENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* В шкафном исполнении карта каналов фиксирована аппаратной схемой:
|
||||
* первые шесть входов образуют три пары, остальные обрабатываются отдельно.
|
||||
*/
|
||||
if(Mode==adr_SHKF)
|
||||
{
|
||||
sens_type[0] = POWER_380; sens_pair[0]=1;
|
||||
@@ -310,45 +530,72 @@ void Init_sensors()
|
||||
sens_type[14] = TERMO_AD;
|
||||
}
|
||||
|
||||
/* Сброс принятой карты дискретных неисправностей. */
|
||||
DigErr.all=0;
|
||||
|
||||
/* Все выдержки ниже хранятся не в секундах, а в количестве циклов ADC_FREQ. */
|
||||
time_1_5sec = (3 * ADC_FREQ) / 2;
|
||||
time_5msec = (5 * ADC_FREQ) / 1000;
|
||||
time_3sec = (3 * ADC_FREQ);
|
||||
time_5sec = (5 * ADC_FREQ);
|
||||
|
||||
/*
|
||||
* Канал с любым из этих признаков не используется как исправный источник
|
||||
* при имитации температурного датчика в Temper_count().
|
||||
*/
|
||||
okay.all=0;
|
||||
okay.bit.Tear=1;
|
||||
okay.bit.Bypas=1;
|
||||
okay.bit.Ignor=1;
|
||||
okay.bit.Imit=1;
|
||||
|
||||
/* Сброс накопителей RMS и выдержек фазных неисправностей. */
|
||||
for(i=0;i<6; i++)
|
||||
{
|
||||
err_count[i] = 0;
|
||||
lev_count[i] = 0;
|
||||
lev_quadr[i] = 0;
|
||||
}
|
||||
|
||||
/* Сброс остальных счётчиков и буферов внешних температур. */
|
||||
for(i=0;i<28;i++) sens_count[i] = 0;
|
||||
for(i=0;i<32;i++) din_count[i] = 0;
|
||||
for(i=0;i<8; i++) ext_temp[i] = ext_diag[i] = 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Завершает инициализацию после загрузки рабочей конфигурации.
|
||||
*
|
||||
* Очищает оперативные измерения и признаки ошибок, восстанавливает нулевые
|
||||
* уровни, задаёт начальные значения для режима нагрузки, включает игнорирование
|
||||
* отдельных каналов в специальных исполнениях и пересчитывает коэффициенты.
|
||||
*
|
||||
* @pre Ранее вызвана Init_sensors(), а калибровочные параметры уже доступны.
|
||||
*/
|
||||
void Init_sensors_more()
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Удаляются динамические биты состояния, но сохраняются служебные биты,
|
||||
* разрешённые маской NOER. Параллельно очищаются измеренные значения.
|
||||
*/
|
||||
for(i=0;i<24;i++)
|
||||
{
|
||||
modbus[i] &= NOER;
|
||||
sens_data[i]=0;
|
||||
}
|
||||
|
||||
/* Восстановление сохранённых нулей силовых АЦП. */
|
||||
for(i=0;i<4;i++)
|
||||
{
|
||||
zer_count[i] = Zero_lev[i];
|
||||
|
||||
/*
|
||||
* Для LOAD до появления реального измерения задаются стартовые значения
|
||||
* напряжения, различающиеся для чётного и нечётного входа пары.
|
||||
*/
|
||||
if(Desk==dsk_LOAD)
|
||||
if(sens_type[i]==VOLTAGE)
|
||||
{
|
||||
@@ -356,6 +603,7 @@ void Init_sensors_more()
|
||||
else sens_data[i]=390;
|
||||
} }
|
||||
|
||||
/* В COMM все четыре силовых канала запускаются с установленным признаком Ignore. */
|
||||
if(Desk==dsk_COMM)
|
||||
{
|
||||
Modbus[pow_addr+0].bit.bitE = 1; // Ignore
|
||||
@@ -364,91 +612,186 @@ void Init_sensors_more()
|
||||
Modbus[pow_addr+3].bit.bitE = 1; // Ignore
|
||||
}
|
||||
|
||||
/* В LOAD игнорируются первые два канала общей таблицы. */
|
||||
if(Desk==dsk_LOAD)
|
||||
{
|
||||
Modbus[0].bit.bitE = 1; // Ignore
|
||||
Modbus[1].bit.bitE = 1; // Ignore
|
||||
}
|
||||
|
||||
/* Коэффициенты рассчитываются после того, как типы каналов окончательно назначены. */
|
||||
calc_sensor_koef();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Формирует маски данных быстрых и медленных пакетов обмена.
|
||||
*
|
||||
* Состав масок зависит от исполнения `Desk`, количества температурных каналов,
|
||||
* наличия измерения тока (`Kurrent`) и внешних каналов (`Owen`).
|
||||
*
|
||||
* @post Массив `Maska[m_FAST][]` и `Maska[m_SLOW][]` содержит актуальный набор
|
||||
* передаваемых диагностик, показаний, уставок и команд.
|
||||
*/
|
||||
void Init_packMask()
|
||||
{
|
||||
int i,j,can=0;
|
||||
|
||||
/* Количество каналов, для которых надо включить диагностику и показания. */
|
||||
can = pow_addr;
|
||||
|
||||
/* При наличии силового измерителя к базовой карте добавляются четыре канала. */
|
||||
if(Kurrent) can += 4;
|
||||
|
||||
/* Полная очистка двух наборов по восемь 16-битных слов. */
|
||||
for(i=0;i<2;i++)
|
||||
for(j=0;j<8;j++) { Maska[i][j]=0; }
|
||||
|
||||
switch(Desk)
|
||||
{
|
||||
case dsk_EPLT:
|
||||
Maska[m_SLOW][0]|= 0x000F; // Полученное
|
||||
Maska[m_SLOW][6]|= 0x01FC; // Яркость ламп и одиночество
|
||||
/* Для EPLT используется фиксированный сокращённый набор медленных данных. */
|
||||
Maska[m_SLOW][0]|= 0x000F; // Полученные данные.
|
||||
Maska[m_SLOW][6]|= 0x01FC; // Яркость ламп и служебные признаки.
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Для каждого канала включается один бит диагностики и один бит показания. */
|
||||
for(i=0;i<can;i++)
|
||||
{
|
||||
Maska[m_FAST][ i /16]|=(1<<( i %16)); // Диагностика
|
||||
Maska[m_FAST][(i+24)/16]|=(1<<((i+24)%16)); // Показаниа
|
||||
}
|
||||
for(i=0;i<3; i++)
|
||||
Maska[m_SLOW][i+3] = Maska[m_FAST][i]; // Уставки
|
||||
/* Диагностики занимают битовые позиции, начиная с 0. */
|
||||
Maska[m_FAST][ i /16]|=(1<<( i %16)); // Диагностика.
|
||||
|
||||
if(Desk==dsk_BKSD) Maska[m_SLOW][7]|= 0x0300; // Калибровка термодатчиков
|
||||
else
|
||||
Maska[m_SLOW][7]|= 0x0F00; // Калибровка термодатчиков
|
||||
if(Kurrent)
|
||||
{ Maska[m_SLOW][7]|= 0x000F; // Ноль датчиков напражениа
|
||||
Maska[m_SLOW][7]|= 0x00F0; // Калибровка датчиков напражениа
|
||||
Maska[m_FAST][6]|= 0x3F00; // Фазные значениа
|
||||
/* Показания размещены в том же пространстве со смещением 24 бита. */
|
||||
Maska[m_FAST][(i+24)/16]|=(1<<((i+24)%16)); // Показания.
|
||||
}
|
||||
if(Owen) Maska[m_FAST][6]|= 0x0008; // Период опроса OWEN
|
||||
|
||||
/* Первые три слова быстрой карты копируются в область масок уставок. */
|
||||
for(i=0;i<3; i++)
|
||||
Maska[m_SLOW][i+3] = Maska[m_FAST][i]; // Уставки.
|
||||
|
||||
/* BKSD передаёт две калибровки температуры, остальные исполнения — четыре. */
|
||||
if(Desk==dsk_BKSD) Maska[m_SLOW][7]|= 0x0300; // Калибровка термодатчиков.
|
||||
else
|
||||
Maska[m_SLOW][7]|= 0x0F00; // Калибровка термодатчиков.
|
||||
|
||||
if(Kurrent)
|
||||
{
|
||||
/* Четыре нулевых уровня и четыре коэффициента силовых каналов. */
|
||||
Maska[m_SLOW][7]|= 0x000F; // Ноль датчиков напряжения.
|
||||
Maska[m_SLOW][7]|= 0x00F0; // Калибровка датчиков напряжения/тока.
|
||||
|
||||
/* Шесть RMS-значений: по три фазы для двух измерительных групп. */
|
||||
Maska[m_FAST][6]|= 0x3F00; // Фазные значения.
|
||||
}
|
||||
/* При наличии OWEN включается поле периода его опроса. */
|
||||
if(Owen) Maska[m_FAST][6]|= 0x0008; // Период опроса OWEN.
|
||||
|
||||
if(Desk==dsk_LOAD)
|
||||
{ Maska[m_SLOW][7]|= 0x0030; // Калибровка ЦАП
|
||||
Maska[m_FAST][7]|= 0xE000; // Дублировать команды
|
||||
Maska[m_FAST][1]|= 0x3000; // Управлающий ток СИФУ
|
||||
{
|
||||
/* Дополнительные поля, используемые только стендом нагрузки. */
|
||||
Maska[m_SLOW][7]|= 0x0030; // Калибровка ЦАП.
|
||||
Maska[m_FAST][7]|= 0xE000; // Дублирование команд.
|
||||
Maska[m_FAST][1]|= 0x3000; // Управляющий ток СИФУ.
|
||||
} }
|
||||
|
||||
Maska[m_FAST][1]|= 0x0001; // Дискретные входы
|
||||
Maska[m_SLOW][6]|= 0x0007; // Яркость ламп, и периоды посылок
|
||||
Maska[m_SLOW][7]|= 0xE000; // Адрес, команды, и чтоб не вылазило
|
||||
/* Эти служебные поля включаются независимо от исполнения. */
|
||||
Maska[m_FAST][1]|= 0x0001; // Дискретные входы.
|
||||
Maska[m_SLOW][6]|= 0x0007; // Яркость ламп и периоды посылок.
|
||||
Maska[m_SLOW][7]|= 0xE000; // Адрес и командные поля.
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Фильтрует логическое условие интегрирующим счётчиком.
|
||||
*
|
||||
* При активном условии счётчик увеличивается до порога, после чего функция
|
||||
* возвращает 1. При снятии условия счётчик уменьшается; в переходной области
|
||||
* возвращается переданное предыдущее состояние `pre`.
|
||||
*
|
||||
* @param term Текущее логическое условие: ненулевое значение означает аварию.
|
||||
* @param count Указатель на накопительный счётчик условия.
|
||||
* @param edge Порог подтверждения условия в циклах вызова.
|
||||
* @param pre Состояние, сохраняемое на этапе накопления или отпускания.
|
||||
*
|
||||
* @return 1 при подтверждённом условии; 0 при полностью снятом условии;
|
||||
* иначе значение `pre`.
|
||||
*
|
||||
* @pre `count` указывает на доступную переменную счётчика.
|
||||
*/
|
||||
int er_anal(int term, unsigned int * count, long edge, int pre)
|
||||
{
|
||||
{
|
||||
/* Активное условие постепенно заполняет счётчик подтверждения. */
|
||||
if (term)
|
||||
{
|
||||
/* После достижения edge состояние считается устойчиво подтверждённым. */
|
||||
if((*count)>=edge) return 1;
|
||||
|
||||
/* До порога сохраняется предыдущее логическое состояние. */
|
||||
(*count)++; return pre;
|
||||
}
|
||||
}
|
||||
|
||||
/* При снятии условия подтверждение также отпускается постепенно. */
|
||||
if( (*count) == 0 ) return 0;
|
||||
(*count)--; return pre;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обновляет состояние ошибок выбранного датчика.
|
||||
*
|
||||
* Сохраняет служебные признаки, заданные маской `NOER`, добавляет вычисленные
|
||||
* ошибки, обновляет сводный признак останова `chk.bit.Error` и формирует признак
|
||||
* готовности канала как инверсию `Stop`.
|
||||
*
|
||||
* @param sens Индекс датчика в массиве `sens_error[]`.
|
||||
* @param err Новое вычисленное состояние ошибок канала.
|
||||
*/
|
||||
void reset_errs(int sens, ERROR err)
|
||||
{
|
||||
ERROR set;
|
||||
|
||||
/* Служебные флаги канала сохраняются, вычисляемые ошибки заменяются новыми. */
|
||||
set.all = (sens_error[sens].all & NOER) | err.all;
|
||||
|
||||
/* Общий Stop накапливается по всем каналам текущего цикла обработки. */
|
||||
chk.bit.Error|= set.bit.Stop;
|
||||
|
||||
/* Канал готов только тогда, когда его ошибки не требуют останова. */
|
||||
set.bit.Ready = !set.bit.Stop;
|
||||
|
||||
sens_error[sens] = set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обрабатывает один канал измерения тока или напряжения.
|
||||
*
|
||||
* Функция отслеживает нулевой уровень АЦП, вычисляет мгновенное и действующее
|
||||
* значение фазы, а для второго канала пары — амплитуду результирующего вектора
|
||||
* и восстановленное действующее значение третьей фазы. Результаты записываются
|
||||
* в `sens_data[]` и диагностическую область `modbus[]`. Дополнительно выполняется
|
||||
* контроль перекоса фаз, верхнего и нижнего уровней.
|
||||
*
|
||||
* @param chan Относительный номер силового канала; допустимый диапазон задаётся
|
||||
* массивами четырёхканального измерительного тракта.
|
||||
*
|
||||
* @pre Выполнены Init_sensors() и Init_sensors_more(); индекс `chan` допустим
|
||||
* для `adc_table_lem[]`, `zer_count[]`, `powK[]` и связанных массивов.
|
||||
*/
|
||||
void Current_count(int chan)
|
||||
{
|
||||
/* Numb — рабочее значение; Zer — оценка нуля; Current — мгновенная фаза; Level — RMS. */
|
||||
float Numb,Zer,Current,Level;
|
||||
|
||||
/*
|
||||
* aCurrent хранит первую измеренную фазу до обработки второго канала пары.
|
||||
* Поэтому каналы каждой пары должны вызываться последовательно: чётный, затем нечётный.
|
||||
*/
|
||||
static float aCurrent,Amplitude;
|
||||
int sens, pair, ist, thrd, fazz, feed;
|
||||
|
||||
/* Индексы глобального датчика, пары, группы и восстановленной третьей фазы. */
|
||||
int ignor, sens, pair, ist, thrd, fazz, feed;
|
||||
|
||||
ERROR error;
|
||||
|
||||
/* В начале нового четырёхканального цикла фиксируется сводка прошлого цикла. */
|
||||
if(Desk == dsk_LOAD)
|
||||
if(!chan)
|
||||
{
|
||||
@@ -456,13 +799,25 @@ void Current_count(int chan)
|
||||
chk.all = 0;
|
||||
}
|
||||
|
||||
/* Переход от относительного номера силового входа к общей таблице датчиков. */
|
||||
sens = pow_addr + chan;
|
||||
|
||||
/* Парный канал нужен для сравнения фазных RMS-значений. */
|
||||
pair = sens_pair[chan];
|
||||
|
||||
/* Чётный канал — первая измеренная фаза пары, нечётный — вторая. */
|
||||
ist = !(chan & 1);
|
||||
|
||||
/* Номер двухканальной измерительной группы: 0 для каналов 0/1, 1 для 2/3. */
|
||||
feed = (chan >>1);
|
||||
|
||||
/* Начальная позиция трёх фаз этой группы в диагностической области Modbus. */
|
||||
fazz = feed*3;
|
||||
|
||||
/* Индекс накопителя RMS восстановленной третьей фазы: 4 либо 5. */
|
||||
thrd = feed+4;
|
||||
|
||||
/* Bypass полностью исключает канал из измерения, сохраняя сам флаг Bypass. */
|
||||
if(sens_error[sens].bit.Bypas)
|
||||
{
|
||||
sens_error[sens].all = 0;
|
||||
@@ -471,13 +826,23 @@ void Current_count(int chan)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Сырой код специализированного АЦП/датчика LEM. */
|
||||
Numb = adc_table_lem[chan];
|
||||
|
||||
/* Сохранение сырого кода в отдельной диагностической области. */
|
||||
modbus[0x64+chan] = Numb;
|
||||
|
||||
// Средний (он же нулевой) уровень показаний АЦП
|
||||
// Средний (он же нулевой) уровень показаний АЦП.
|
||||
/*
|
||||
* Первый IIR-слой медленно ведёт оценку к текущему коду. При вызове
|
||||
* ADC_FREQ раз в секунду коэффициент соответствует примерно 5-секундной базе.
|
||||
*/
|
||||
zer_count[chan] += (Numb-zer_count[chan])/(5.0 * ADC_FREQ);
|
||||
|
||||
/* Второй фильтр подавляет остаточную пульсацию оценки нулевого уровня. */
|
||||
Zer = (int)(filterbat(&zer_filter[chan],zer_count[chan]));
|
||||
|
||||
/* Сохранённый рабочий ноль обновляется только в разрешённой части WAKE-цикла. */
|
||||
if(WAKE < (WAKE_TIME /2)) Zero_lev[chan] = Zer;
|
||||
/*
|
||||
Test_mem_limit(12);
|
||||
@@ -485,40 +850,53 @@ Log_to_mem((int)adc_table_lem[chan]);
|
||||
Log_to_mem((int)zer_count[chan]);
|
||||
Log_to_mem((int)Zero_lev[chan]);
|
||||
*/
|
||||
// Мгновенное значение фазы
|
||||
// Мгновенное значение фазы.
|
||||
/* Удаление смещения АЦП и масштабирование в физическую величину. */
|
||||
Current = (Numb - Zero_lev[chan]) * powK[chan];
|
||||
|
||||
// Действующее (среднеквадратичное) значение фазы
|
||||
// Действующее (среднеквадратичное) значение фазы.
|
||||
/* Низкочастотная фильтрация квадрата мгновенного значения. */
|
||||
lev_quadr[chan] += ((Current*Current)-lev_quadr[chan])/(1.0 * ADC_FREQ);
|
||||
|
||||
/* Корень из среднего квадрата даёт RMS текущей измеренной фазы. */
|
||||
lev_count[chan] = sqrt(lev_quadr[chan]);
|
||||
|
||||
// Запомним
|
||||
// Первая фаза пары запоминается до прихода второй.
|
||||
if(ist)
|
||||
{
|
||||
/* В COMM полярность первой фазы аппаратно/логически развёрнута. */
|
||||
if(Desk==dsk_COMM) aCurrent =-Current;
|
||||
else aCurrent = Current; // Запомнили мгновенное значение - дла амплитуды
|
||||
else aCurrent = Current; // Мгновенное значение первой фазы для расчёта вектора.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Вычисление амплитуды
|
||||
// Вычисление амплитуды по двум измеренным фазам.
|
||||
/* im_calc() строит модуль трёхфазного вектора, затем результат фильтруется. */
|
||||
Amplitude = filterbat(&out_filter[sens], im_calc(Current,aCurrent));
|
||||
|
||||
/* Небольшие значения подавляются как шум; порог зависит от типа канала. */
|
||||
if(sens_type[sens]==VOLTAGE)
|
||||
if(Amplitude<20) Amplitude = 0;
|
||||
|
||||
if(sens_type[sens]==CURRENT)
|
||||
if(Amplitude<75) Amplitude = 0;
|
||||
|
||||
/* Для синусоиды действующее значение равно амплитуде, делённой на sqrt(2). */
|
||||
Level = Amplitude / RADIX2;
|
||||
|
||||
/* Во время WAKE вычисления ведутся, но рабочие выходные данные не обновляются. */
|
||||
if(!WAKE)
|
||||
{
|
||||
/* Нечётный элемент пары хранит амплитуду, предыдущий — RMS. */
|
||||
sens_data[sens ] = Amplitude;
|
||||
sens_data[sens-1] = Level;
|
||||
}
|
||||
|
||||
// Действующее (среднеквадратичное) значение третьей фазы
|
||||
// Действующее (среднеквадратичное) значение третьей фазы.
|
||||
/* Для симметричной трёхпроводной системы сумма мгновенных фаз равна нулю. */
|
||||
Numb =-Current-aCurrent;
|
||||
|
||||
/* Та же RMS-фильтрация применяется к восстановленной фазе. */
|
||||
lev_quadr[thrd] += (Numb*Numb-lev_quadr[thrd])/(1.0 * ADC_FREQ);
|
||||
lev_count[thrd] = sqrt(lev_quadr[thrd]);
|
||||
/*
|
||||
@@ -538,43 +916,60 @@ Log_to_mem(Amplitude);
|
||||
Log_to_mem(Level);
|
||||
}
|
||||
*/
|
||||
/* Публикация трёх RMS-фаз группы в последовательных Modbus-регистрах. */
|
||||
modbus[0x68+fazz ] = lev_count[pair];
|
||||
modbus[0x68+fazz+1] = lev_count[chan];
|
||||
modbus[0x68+fazz+2] = lev_count[thrd];
|
||||
}
|
||||
|
||||
// Это максимальное
|
||||
// Выбор максимального RMS из трёх фаз — опорного уровня для оценки перекоса.
|
||||
Numb = lev_count[chan];
|
||||
if(Numb<lev_count[pair]) Numb = lev_count[pair];
|
||||
if(Numb<lev_count[thrd]) Numb = lev_count[thrd];
|
||||
|
||||
// Зашиты!
|
||||
// Формирование защит.
|
||||
error.all = 0;
|
||||
if(WAKE || sens_error[chan].bit.Ignor) goto fin;
|
||||
|
||||
/* В переходном состоянии WAKE новые защиты не формируются. */
|
||||
if(WAKE) goto fin;
|
||||
|
||||
/* Ignore оставляет диагностику видимой, но ниже может запретить Stop. */
|
||||
ignor = sens_error[sens].bit.Ignor;
|
||||
|
||||
/*
|
||||
* Если измеренная фаза отстаёт от максимальной более чем на 30 % и общий
|
||||
* уровень выше Curr_Edge, условие должно сохраняться time_3sec циклов.
|
||||
*/
|
||||
if(er_anal( ((Numb-lev_count[chan])/Numb > 0.3) && (Numb>Curr_Edge),
|
||||
&err_count[chan],time_3sec,0))
|
||||
{
|
||||
error.bit.Wry = 1;
|
||||
error.bit.Stop = 1;
|
||||
if(!ignor) error.bit.Stop = 1;
|
||||
}
|
||||
|
||||
/* Аналогичный контроль для вычисленной третьей фазы. */
|
||||
if(er_anal( ((Numb-lev_count[thrd])/Numb > 0.3) && (Numb>Curr_Edge),
|
||||
&err_count[thrd],time_3sec,0))
|
||||
{
|
||||
error.bit.Wry = 1;
|
||||
error.bit.Stop = 1;
|
||||
if(!ignor) error.bit.Stop = 1;
|
||||
}
|
||||
|
||||
/* Полное игнорирование канала прекращает дальнейший контроль уровней. */
|
||||
if(ignor) goto fin;
|
||||
|
||||
/* Общий уровень пары проверяется один раз — при обработке её второго канала. */
|
||||
if(Desk == dsk_LOAD)
|
||||
if(!ist)
|
||||
{
|
||||
/* Верхняя уставка всегда считается аварийной и формирует Stop. */
|
||||
if(Level > sens_hi_edge[sens])
|
||||
{
|
||||
error.bit.Hyper = 1;
|
||||
error.bit.Stop = 1;
|
||||
}
|
||||
|
||||
/* Для напряжения пониженный уровень подтверждается трёхсекундной выдержкой. */
|
||||
if(sens_type[sens]==VOLTAGE)
|
||||
|
||||
if(er_anal( (Level < sens_lo_edge[sens]),
|
||||
@@ -584,6 +979,7 @@ modbus[0x68+fazz+2] = lev_count[thrd];
|
||||
error.bit.Stop = 1;
|
||||
}
|
||||
|
||||
/* Для тока та же sens_lo_edge используется как порог предупреждения Over. */
|
||||
if(sens_type[sens]==CURRENT)
|
||||
if(Level > sens_lo_edge[sens])
|
||||
{
|
||||
@@ -610,24 +1006,49 @@ Log_to_mem(WAKE);
|
||||
}
|
||||
*/
|
||||
fin:
|
||||
/* Объединение вычисленных ошибок со служебными флагами выбранного канала. */
|
||||
reset_errs(sens,error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обрабатывает один температурный канал.
|
||||
*
|
||||
* Поддерживаются локальные значения АЦП, внешние температуры типа `TRM_OBEH`,
|
||||
* режим выдачи сырого кода, имитация по исправным однотипным датчикам и режим
|
||||
* калибровки. После пересчёта температура ограничивается диапазоном от -20 до
|
||||
* 200 градусов, записывается в `sens_data[]` с масштабом 0,1 градуса и
|
||||
* проверяется на обрыв, перегрев и предупредительный уровень.
|
||||
*
|
||||
* @param chan Индекс температурного канала в общих массивах датчиков.
|
||||
* @param own Ненулевое значение разрешает получение данных внешнего канала
|
||||
* `TRM_OBEH` из массивов `ext_temp[]` и `ext_diag[]`.
|
||||
*
|
||||
* @pre Индекс `chan` допустим для выбранной конфигурации каналов.
|
||||
*/
|
||||
void Temper_count(int chan, int own)
|
||||
{
|
||||
/* Рабочее значение: сначала код/внешние данные, затем температура в градусах. */
|
||||
float Numb;
|
||||
|
||||
/* Целая температура используется при сравнении с уставками диагностики. */
|
||||
static int Temper;
|
||||
|
||||
/* j — число доноров имитации; kun — индекс калибровочного канала. */
|
||||
int i,j, kun;
|
||||
long s;
|
||||
ERROR error;
|
||||
|
||||
/* Индекс внешнего температурного канала относительно начала блока OWEN. */
|
||||
int ovn;
|
||||
|
||||
/* Первый температурный канал открывает новый цикл накопления общих флагов. */
|
||||
if(!chan)
|
||||
{
|
||||
sig.all = chk.all;
|
||||
chk.all = 0;
|
||||
}
|
||||
|
||||
/* Bypass применяется здесь только к локальным температурным каналам. */
|
||||
if(sens_error[chan].bit.Bypas)
|
||||
if(chan<tpl_cans)
|
||||
{
|
||||
@@ -637,14 +1058,20 @@ void Temper_count(int chan, int own)
|
||||
return;
|
||||
}
|
||||
|
||||
/* По умолчанию источником служит локальная таблица результатов АЦП. */
|
||||
Numb = ADC_table[chan];
|
||||
|
||||
/* Сервисный режим публикует сырой код без пересчёта и диагностики. */
|
||||
if(cRawMeat)
|
||||
{
|
||||
sens_data[chan] = Numb;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Имитация заменяет локальный датчик средним кодом исправных датчиков
|
||||
* того же типа. Каналы с флагами из okay исключаются из набора доноров.
|
||||
*/
|
||||
if(sens_error[chan].bit.Imit)
|
||||
if(chan<tpl_cans)
|
||||
{
|
||||
@@ -659,27 +1086,37 @@ void Temper_count(int chan, int own)
|
||||
j++;
|
||||
} }
|
||||
|
||||
/* При наличии доноров вычисляется среднее; без доноров s остаётся равным нулю. */
|
||||
if(j) s/=j;
|
||||
Numb = s;
|
||||
}
|
||||
|
||||
/* Неотрицательный kun означает, что текущий канал расположен в зоне калибровки. */
|
||||
kun = chan - cal_addr;
|
||||
|
||||
/* При own!=0 внешний TRM_OBEH подменяет локальное значение АЦП. */
|
||||
if(own)
|
||||
if(sens_type[chan]==TRM_OBEH)
|
||||
{
|
||||
ovn = chan-tpl_cans;
|
||||
|
||||
/* Внешняя температура приходит в десятых долях градуса. */
|
||||
Numb= 0.1 * ext_temp[ovn];
|
||||
|
||||
/* Любая внешняя диагностика преобразуется в заведомо аварийное значение. */
|
||||
if(ext_diag[ovn])
|
||||
Numb = -100;
|
||||
}
|
||||
|
||||
/* Локальный аналоговый вариант температурного тракта. */
|
||||
if(!own)
|
||||
if(TermoAD)
|
||||
{
|
||||
/* В режиме калибровки сырой код записывается в соответствующую точку. */
|
||||
if(cTermoCal|bTermoCal)
|
||||
if(!WAKE)
|
||||
{
|
||||
/* В шкафном исполнении уровень кода выбирает старшую пару калибровок. */
|
||||
if(Desk==dsk_SHKF)
|
||||
if(Numb>2200) kun|=2;
|
||||
|
||||
@@ -690,21 +1127,25 @@ void Temper_count(int chan, int own)
|
||||
return;
|
||||
} }
|
||||
|
||||
/* Калибровочные/служебные позиции за пределами tpl_cans здесь не измеряются. */
|
||||
if(chan>=tpl_cans) return;
|
||||
|
||||
// Kun именно чтоб скомпенсировать нечетность
|
||||
// Нечётность kun выбирает одну из двух независимых аналоговых ветвей.
|
||||
if(kun&1) Numb = (Numb-K300_2)*K_T2+ZERO;
|
||||
else Numb = (Numb-K300_1)*K_T1+ZERO;
|
||||
}
|
||||
|
||||
/* Резистивный вариант температурного тракта. */
|
||||
if(TermoRS)
|
||||
{
|
||||
/* Каналы начиная с cal_addr используются как калибровочные, а не измерительные. */
|
||||
if(kun>=0)
|
||||
{
|
||||
/* Во время WAKE вторичный фильтр синхронизируется с первичным. */
|
||||
if(WAKE) out_filter[chan] = adc_filter[chan];
|
||||
else
|
||||
{
|
||||
// Калибровку отфильтруем вторым слоем
|
||||
// Калибровочный код дополнительно фильтруется вторым слоем.
|
||||
Numb = filterbat(&out_filter[chan],Numb);
|
||||
|
||||
TCaliber[kun] = Numb;
|
||||
@@ -715,29 +1156,39 @@ void Temper_count(int chan, int own)
|
||||
|
||||
if(Desk==dsk_BKSD)
|
||||
{
|
||||
/* Для диагностики BKSD сырой код дополнительно публикуется со смещением +8. */
|
||||
sens_data[chan+8] = ADC_table[chan];
|
||||
|
||||
/* Первые шесть и последующие каналы используют разные масштабы. */
|
||||
if(chan<6) Numb = (Numb-K100_D)*K100;
|
||||
else Numb = (Numb-K100_D)*K_50;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* В остальных исполнениях чётные и нечётные каналы имеют свои калибровки. */
|
||||
if(chan&1) Numb = (Numb-K100_2)*K_T2;
|
||||
else Numb = (Numb-K100_1)*K_T1;
|
||||
} }
|
||||
|
||||
/* Ограничение диапазона одновременно защищает формат данных и задаёт аварийные границы. */
|
||||
if(Numb < -20) Numb = -20;
|
||||
if(Numb > 200) Numb = 200;
|
||||
|
||||
/* Сервисная команда подменяет результат фиксированной температурой 40 °C. */
|
||||
if(bSecretBt|cSecretBt) Numb = 40.0;
|
||||
|
||||
/* В таблице температура хранится в десятых долях градуса. */
|
||||
sens_data[chan] = Numb*10;
|
||||
|
||||
/* Для пороговых сравнений дробная часть отбрасывается. */
|
||||
Temper = Numb;
|
||||
|
||||
error.all = 0;
|
||||
|
||||
/* Во время запуска или при Ignore показание сохраняется, но диагностика не обновляется. */
|
||||
if(WAKE || sens_error[chan].bit.Ignor) goto fin;
|
||||
|
||||
// Обрыв или неисправность
|
||||
// Обрыв или неисправность: результат упёрся в одну из границ допустимого диапазона.
|
||||
if(Temper<=-20 || Temper>=200)
|
||||
{
|
||||
error.bit.Tear = 1;
|
||||
@@ -745,7 +1196,11 @@ sens_data[chan+8] = ADC_table[chan];
|
||||
}
|
||||
else
|
||||
|
||||
// Перегрев
|
||||
// Перегрев.
|
||||
/*
|
||||
* Если Hyper уже был активен, он удерживается до снижения температуры
|
||||
* ниже верхней уставки на величину Cooling — это температурный гистерезис.
|
||||
*/
|
||||
if(((Temper>sens_hi_edge[chan]-Cooling) && (sens_error[chan].bit.Hyper)) ||
|
||||
(Temper>sens_hi_edge[chan]) )
|
||||
{
|
||||
@@ -755,7 +1210,7 @@ sens_data[chan+8] = ADC_table[chan];
|
||||
}
|
||||
else
|
||||
|
||||
// Предупреждение по температуре
|
||||
// Предупреждение по температуре проверяется только при отсутствии обрыва и перегрева.
|
||||
if(Temper>sens_lo_edge[chan])
|
||||
{
|
||||
error.bit.Over = 1;
|
||||
@@ -763,21 +1218,39 @@ sens_data[chan+8] = ADC_table[chan];
|
||||
}
|
||||
|
||||
fin:
|
||||
/* Запись локальной диагностики и обновление общего признака Stop. */
|
||||
reset_errs(chan,error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обрабатывает канал контроля питающего напряжения.
|
||||
*
|
||||
* Код АЦП масштабируется коэффициентом, выбранным по типу датчика. Функция
|
||||
* фильтрует диагностические дискретные входы, контролирует пониженное напряжение
|
||||
* и формирует общий признак аварии. Останов по низкому напряжению формируется,
|
||||
* когда аналогичный признак присутствует и у парного канала.
|
||||
*
|
||||
* @param chan Индекс канала питания в таблицах `ADC_table[]`, `sens_type[]`,
|
||||
* `sens_pair[]` и `sens_error[]`.
|
||||
*
|
||||
* @note Проверка повышенного напряжения в исходном коде отключена блочным
|
||||
* комментарием и настоящей документацией не активируется.
|
||||
*/
|
||||
void Power_count(int chan)
|
||||
{
|
||||
/* Numb — сырой код АЦП; Power — пересчитанное напряжение; bitt — позиция диагностики. */
|
||||
float Numb;
|
||||
int Power,bitt;
|
||||
ERROR error;
|
||||
|
||||
/* Нулевой канал начинает новый цикл контроля питающих каналов. */
|
||||
if(!chan)
|
||||
{
|
||||
sig.all = chk.all;
|
||||
chk.all = 0;
|
||||
}
|
||||
|
||||
/* Bypass исключает канал, обнуляя его показание и оставляя флаг Bypass. */
|
||||
if(sens_error[chan].bit.Bypas)
|
||||
{
|
||||
sens_error[chan].all = 0;
|
||||
@@ -786,56 +1259,77 @@ void Power_count(int chan)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Получение последнего кода общего АЦП. */
|
||||
Numb = ADC_table[chan];
|
||||
|
||||
/* В сервисном режиме наружу передаётся сырой код без проверок. */
|
||||
if(cRawMeat)
|
||||
{
|
||||
sens_data[chan] = Numb;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Тип канала используется как индекс таблицы коэффициентов powK[]. */
|
||||
Power = Numb * powK[sens_type[chan]];
|
||||
|
||||
/* Рабочая таблица хранит уже пересчитанное физическое значение. */
|
||||
sens_data[chan] = Power;
|
||||
|
||||
error.all = 0;
|
||||
|
||||
/* При запуске и Ignore аналоговое значение обновляется, а защиты пропускаются. */
|
||||
if(WAKE || sens_error[chan].bit.Ignor) goto fin;
|
||||
|
||||
// Дискретные каналы
|
||||
// Дискретные каналы.
|
||||
/* Обычно каждому аналоговому каналу соответствуют два последовательных бита DigErr. */
|
||||
bitt = chan*2;
|
||||
if(chan!=7)
|
||||
{
|
||||
/* Каждый вход подтверждается интегрирующей выдержкой 1000 вызовов. */
|
||||
error.bit.Discr1 = er_anal(((DigErr.all>>bitt)&1), &din_count[bitt], 1000, 0); bitt++;
|
||||
error.bit.Discr2 = er_anal(((DigErr.all>>bitt)&1), &din_count[bitt], 1000, 0); bitt++;
|
||||
}
|
||||
|
||||
/* У шестого канала предусмотрены ещё два дополнительных дискретных признака. */
|
||||
if(chan==6)
|
||||
{
|
||||
error.bit.Discr3 = er_anal(((DigErr.all>>bitt)&1), &din_count[bitt], 1000, 0); bitt++;
|
||||
error.bit.Discr4 = er_anal(((DigErr.all>>bitt)&1), &din_count[bitt], 1000, 0); bitt++;
|
||||
}
|
||||
|
||||
/* Contr — сводный признак наличия хотя бы одной дискретной неисправности. */
|
||||
error.bit.Contr = error.bit.Discr1 | error.bit.Discr2 | error.bit.Discr3 | error.bit.Discr4;
|
||||
|
||||
// Пониженное напражение
|
||||
// Пониженное напряжение.
|
||||
if(Power <sens_lo_edge[chan])
|
||||
{
|
||||
error.bit.Out = 1;
|
||||
|
||||
/* Останов формируется только при одновременном снижении в парном канале. */
|
||||
if(sens_error[sens_pair[chan]].bit.Out)
|
||||
{
|
||||
error.bit.Stop = 1;
|
||||
} }
|
||||
|
||||
// Повышенное напражение
|
||||
// Повышенное напряжение.
|
||||
/*
|
||||
* Эта защита присутствует в исходнике, но намеренно отключена блочным
|
||||
* комментарием; исполняемый код её не учитывает.
|
||||
*/
|
||||
/* if(Power > sens_hi_edge[chan])
|
||||
{
|
||||
error.bit.Hyper = 1;
|
||||
error.bit.Stop = 1;
|
||||
}
|
||||
*/
|
||||
/* Любая локальная неисправность питания поднимает общую ламповую аварию. */
|
||||
if(error.all)
|
||||
chk.bit.Alarm = 1;
|
||||
|
||||
fin:
|
||||
/* Сохранение вычисленных ошибок и обновление общего Stop. */
|
||||
reset_errs(chan,error);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file message.c
|
||||
* @brief Параметры устройства и прикладные сообщения протокола Modbus.
|
||||
*
|
||||
* Инициализирует значения по умолчанию, загружает и сохраняет параметры в
|
||||
* EEPROM, принимает команды функций 3/6 и формирует ответы функции 4.
|
||||
* Индексы param/Modbus согласованы с внешней картой регистров; менять порядок,
|
||||
* ANSWER_LEN или представление слов можно только вместе с ведущей системой.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
#include "package.h"
|
||||
#include "RS485.h"
|
||||
@@ -18,9 +27,17 @@
|
||||
|
||||
#include "caliber.h"
|
||||
|
||||
/** @brief Рабочий образ регистров Modbus, передаваемый внешнему мастеру. */
|
||||
int modbus[ANSWER_LEN+1];
|
||||
/** @brief Сохраняемые параметры, индексно согласованные с картой регистров. */
|
||||
unsigned int param[ANSWER_LEN+1];
|
||||
|
||||
/**
|
||||
* @brief Создаёт полный набор безопасных параметров для текущего варианта платы.
|
||||
* @post Modbus/param, режимы, пороги, яркость и калибровки имеют штатные значения.
|
||||
* @details Начальная очистка предотвращает сохранение мусора в зарезервированных
|
||||
* регистрах; далее значения выбираются по Desk и compile-time конфигурации.
|
||||
*/
|
||||
void Default_params()
|
||||
{
|
||||
unsigned int i,def;
|
||||
@@ -46,19 +63,19 @@ void Default_params()
|
||||
|
||||
if(Desk == dsk_EPLT)
|
||||
{
|
||||
Cancount[m_FAST] = 2; // пауза между посылками CAN
|
||||
Cancount[m_FAST] = 2; // пауза между посылками CAN
|
||||
|
||||
for(i=0;i<6;i++) Bright[i] = bright[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
Cancount[m_FAST] = 10; // пауза между посылками CAN
|
||||
Cancount[m_FAST] = 10; // пауза между посылками CAN
|
||||
Brightness = 8;
|
||||
}
|
||||
|
||||
Cancount[m_SLOW] = 101; // пауза между посылками CAN
|
||||
Cancount[m_SLOW] = 101; // пауза между посылками CAN
|
||||
|
||||
if(Owen) Owncount = 20; // пауза между опросами OWEN
|
||||
if(Owen) Owncount = 20; // пауза между опросами OWEN
|
||||
|
||||
if(Kalibro)
|
||||
{
|
||||
@@ -122,9 +139,9 @@ void Default_params()
|
||||
DAC_20 = Caliber[6];
|
||||
DAC_04 = Caliber[7];
|
||||
|
||||
/* Не врема!
|
||||
DAC_go = 6; // начало зарада
|
||||
DAC_stop= 15; // конец зарада
|
||||
/* Не врема!
|
||||
DAC_go = 6; // начало зарада
|
||||
DAC_stop= 15; // конец зарада
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -135,6 +152,11 @@ void Default_params()
|
||||
Init_sensors_more();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Загружает параметрический блок из EEPROM и проверяет его целостность.
|
||||
* @details При несовпадении сигнатуры/CRC вызывается Default_params(); после
|
||||
* успешной загрузки значения переносятся в рабочие глобальные настройки.
|
||||
*/
|
||||
void Load_params()
|
||||
{
|
||||
unsigned int i,crc;
|
||||
@@ -159,6 +181,11 @@ void Load_params()
|
||||
Caliber_time = 0xFFFF;
|
||||
} } }
|
||||
|
||||
/**
|
||||
* @brief Формирует параметрический блок с CRC и записывает его в EEPROM.
|
||||
* @warning Запись следует запускать только при свободном драйвере EEPROM;
|
||||
* питание должно сохраняться до физического завершения транзакции.
|
||||
*/
|
||||
void Save_params()
|
||||
{
|
||||
unsigned int i,dif=0;
|
||||
@@ -177,24 +204,30 @@ void Save_params()
|
||||
|
||||
/***************************************************************/
|
||||
/***************************************************************/
|
||||
/* Передача данных по протоколу ModBus - команда 3
|
||||
Чтение ачеек данных */
|
||||
/* Передача данных по протоколу ModBus - команда 3
|
||||
Чтение ачеек данных */
|
||||
/***************************************************************/
|
||||
/***************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Обрабатывает запрос Modbus чтения диапазона регистров.
|
||||
* @param rs_arr Порт с проверенным входным кадром и буфером ответа.
|
||||
* @details Проверяет начальный адрес и длину, копирует слова из modbus и
|
||||
* формирует CRC непосредственно перед отправкой.
|
||||
*/
|
||||
void ReceiveCommandModbus3(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned int crc, Address_MB, Length_MB, i;
|
||||
|
||||
// получили начальный адрес чтениа
|
||||
// получили начальный адрес чтениа
|
||||
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];
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Отсылка
|
||||
/* Посчитали контрольную сумму перед самой посылкой */
|
||||
// Отсылка
|
||||
/* Посчитали контрольную сумму перед самой посылкой */
|
||||
|
||||
rs_arr->buffer[0] = CNTRL_ADDR;
|
||||
rs_arr->buffer[1] = CMD_MODBUS_3;
|
||||
@@ -223,22 +256,27 @@ void ReceiveCommandModbus3(RS_DATA *rs_arr)
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Применяет команду записи одного параметра Modbus.
|
||||
* @details После проверки адреса обновляет разрешённое значение, выставляет
|
||||
* события перенастройки/сохранения и возвращает эхо принятой команды.
|
||||
*/
|
||||
void ReceiveCommandModbus6(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned int Address_MB, Data_MB, i;
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Отсылка
|
||||
/* Отправлаем назад то же самое */
|
||||
// Отсылка
|
||||
/* Отправлаем назад то же самое */
|
||||
|
||||
for (i=0;i<8;i++)
|
||||
rs_arr->buffer[i] = rs_arr->RS_Header[i];
|
||||
|
||||
|
||||
// получили начальный адрес записи
|
||||
// получили начальный адрес записи
|
||||
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];
|
||||
|
||||
Modbus[Address_MB].all = Data_MB;
|
||||
@@ -247,12 +285,17 @@ void ReceiveCommandModbus6(RS_DATA *rs_arr)
|
||||
RS_Send(rs_arr, rs_arr->buffer, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Формирует периодический запрос/ответ функции 4 для внешнего устройства.
|
||||
* @details Адрес, полезная нагрузка и CRC помещаются в буфер выбранного RS-порта,
|
||||
* после чего передача запускается неблокирующим RS_Send().
|
||||
*/
|
||||
void SendCommandModbus4(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned int crc;
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Отсылка
|
||||
// Отсылка
|
||||
|
||||
rs_arr->buffer[0] = 16;
|
||||
rs_arr->buffer[1] = 4;
|
||||
@@ -275,12 +318,17 @@ void SendCommandModbus4(RS_DATA *rs_arr)
|
||||
RS_Send(rs_arr, rs_arr->buffer, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Разбирает ответ внешнего измерителя на функцию Modbus 4.
|
||||
* @details Проверяет формат и переносит температуры/диагностики в ext_temp и
|
||||
* ext_diag; некорректный ответ не должен заменять последний пригодный снимок.
|
||||
*/
|
||||
void ReceiveAnswerModbus4(RS_DATA *rs_arr)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Отсылка
|
||||
// Отсылка
|
||||
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file peripher.c
|
||||
* @brief Определение типа платы и управление дискретной периферией.
|
||||
*
|
||||
* Читает конфигурационные входы, выбирает режим изделия, коммутирует каналы
|
||||
* термопар и опрашивает кнопки. Временное переназначение LED-линий сохраняет
|
||||
* исходные MUX/DIR и должно всегда завершаться unsetup_leds_line(). Таблицы GPIO
|
||||
* зависят от варианта платы и описаны в GPIO_table.h.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||||
#include "filter_bat2.h"
|
||||
#include "measure.h"
|
||||
@@ -10,12 +19,19 @@
|
||||
#include "peripher.h"
|
||||
#include "GPIO_table.h"
|
||||
|
||||
/** @brief Распознанный адрес/режим и признаки установленной периферии платы. */
|
||||
int Mode,Desk,TermoAD=0,TermoRS=0,TermoSW=0,Kurrent=0,Kalibro=0,Owen=0;
|
||||
/** @brief Интегрирующие счётчики фильтрации дискретных входов. */
|
||||
unsigned int INcount0=0,INcount1=0;
|
||||
/** @brief Снимок диагностических битов дискретной периферии. */
|
||||
LONGE DigErr;
|
||||
|
||||
int MUX_GPIO32,MUX_GPIO48,DIR_GPIO32,DIR_GPIO48;
|
||||
|
||||
/**
|
||||
* @brief Временно переводит GPIO32/GPIO48 в режим обычных цифровых выходов.
|
||||
* @post Предыдущие MUX/DIR сохранены для unsetup_leds_line().
|
||||
*/
|
||||
void setup_leds_line()
|
||||
{
|
||||
MUX_GPIO32 = GpioCtrlRegs.GPBMUX1.bit.GPIO32;
|
||||
@@ -31,6 +47,7 @@ void setup_leds_line()
|
||||
EDIS;
|
||||
}
|
||||
|
||||
/** @brief Восстанавливает MUX/DIR LED-линий, сохранённые setup_leds_line(). */
|
||||
void unsetup_leds_line()
|
||||
{
|
||||
EALLOW;
|
||||
@@ -41,14 +58,21 @@ void unsetup_leds_line()
|
||||
EDIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Считывает код исполнения платы и формирует её программную конфигурацию.
|
||||
* @details По комбинации GPIO задаёт Mode/Desk, наличие температурных трактов,
|
||||
* токовых входов, калибровки и внешнего OWEN. Затем применяет соответствующие
|
||||
* таблицы направления, MUX и начальных уровней GPIO_table.h.
|
||||
* @post Все inline-примитивы peripher.h можно безопасно использовать.
|
||||
*/
|
||||
void get_Mode()
|
||||
{
|
||||
EALLOW;
|
||||
|
||||
GpioCtrlRegs.GPAMUX1.all &= 0xFF000000; // 00—11
|
||||
GpioCtrlRegs.GPAMUX2.all &= 0xFF00003F; // 19—27
|
||||
GpioCtrlRegs.GPBMUX1.all &= 0xFFFFFFC0; // 32—34
|
||||
GpioCtrlRegs.GPBMUX2.all &= 0x000FF000; // 48—53, 58—63
|
||||
GpioCtrlRegs.GPAMUX1.all &= 0xFF000000; // 00—11
|
||||
GpioCtrlRegs.GPAMUX2.all &= 0xFF00003F; // 19—27
|
||||
GpioCtrlRegs.GPBMUX1.all &= 0xFFFFFFC0; // 32—34
|
||||
GpioCtrlRegs.GPBMUX2.all &= 0x000FF000; // 48—53, 58—63
|
||||
|
||||
GpioCtrlRegs.GPADIR.bit.GPIO20 = 0;
|
||||
GpioCtrlRegs.GPADIR.bit.GPIO21 = 0;
|
||||
@@ -117,6 +141,10 @@ void get_Mode()
|
||||
EDIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Переводит адресные линии мультиплексора термопар в невыбранное состояние.
|
||||
* @note Используется между каналами, чтобы снизить влияние переходных процессов.
|
||||
*/
|
||||
void select_tpl_255(void)
|
||||
{
|
||||
if(Desk==dsk_BKSD)
|
||||
@@ -144,6 +172,11 @@ void select_tpl_255(void)
|
||||
GpioDataRegs.GPBSET.all = BKST_B_tpl_zero;
|
||||
} }
|
||||
|
||||
/**
|
||||
* @brief Выбирает один физический канал мультиплексора термопар.
|
||||
* @param n_tpl Номер канала в логической нумерации измерительного модуля.
|
||||
* @details Номер раскладывается на адресные GPIO с учётом разводки текущего Desk.
|
||||
*/
|
||||
void select_tpl_canal(int n_tpl)
|
||||
{
|
||||
unsigned long GPIO_A_tpl_set = 0;
|
||||
@@ -187,6 +220,11 @@ void select_tpl_canal(int n_tpl)
|
||||
GpioDataRegs.GPBCLEAR.all = GPIO_B_tpl_set;
|
||||
} }
|
||||
|
||||
/**
|
||||
* @brief Опрашивает кнопки и дискретные входы с программным антидребезгом.
|
||||
* @details Счётчики INcount* требуют устойчивого уровня несколько циклов;
|
||||
* подтверждённые состояния переносятся в команды и диагностические биты.
|
||||
*/
|
||||
void get_Buttons()
|
||||
{
|
||||
unsigned long butt =0;
|
||||
@@ -208,7 +246,7 @@ void get_Buttons()
|
||||
Inputs.all = butt;
|
||||
}
|
||||
|
||||
/* Ничего такого в действительности нет
|
||||
/* Ничего такого в действительности нет
|
||||
if(Desk==dsk_BKST)
|
||||
{ bSecretBt = !GpioDataRegs.GPBDAT.bit.GPIO63;
|
||||
InputRep1 = bSecretBt;
|
||||
@@ -244,7 +282,7 @@ void get_Buttons()
|
||||
if(GpioDataRegs.GPADAT.bit.GPIO5 ) butt +=0x0800;
|
||||
|
||||
if(GpioDataRegs.GPBDAT.bit.GPIO48) butt +=0x1000;
|
||||
if(GpioDataRegs.GPADAT.bit.GPIO10) butt +=0x2000; // Секретный вход
|
||||
if(GpioDataRegs.GPADAT.bit.GPIO10) butt +=0x2000; // Секретный вход
|
||||
|
||||
Inputs.all = butt;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file pulto.c
|
||||
* @brief Периодическое обслуживание пульта индикации.
|
||||
*
|
||||
* Обработчик Timer1 обновляет яркость, маску ламп, числовые каналы и признак
|
||||
* связи с ведущим устройством. Работа выполняется в прерывании, поэтому обмен
|
||||
* с общими переменными должен оставаться коротким; частоты мигания вычисляются
|
||||
* из READY_FREQ и изменятся при смене базовой частоты таймера.
|
||||
*/
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
|
||||
@@ -10,6 +19,7 @@
|
||||
#include "kanal.h"
|
||||
#include "peripher.h"
|
||||
|
||||
/** @brief Маска мигающих сегментов и тестовое число режима самопроверки. */
|
||||
unsigned long isMask;
|
||||
int isNumb;
|
||||
|
||||
@@ -17,6 +27,11 @@ int quaLamp = 6;
|
||||
|
||||
unsigned long Lonely=0;
|
||||
|
||||
/**
|
||||
* @brief Выполняет шаг визуального теста всех цифр и сегментов.
|
||||
* @details Через BLINK_TIME изменяет цифру 0..9 и попеременно включает либо
|
||||
* гасит полную маску, позволяя заметить неисправный сегмент индикатора.
|
||||
*/
|
||||
void what_is()
|
||||
{
|
||||
static unsigned int count_blink;
|
||||
@@ -33,6 +48,12 @@ void what_is()
|
||||
else isMask = 0xFFFFFFFF;
|
||||
} }
|
||||
|
||||
/**
|
||||
* @brief Периодический ISR управления панелью EPLT.
|
||||
* @details Поддерживает программный PWM яркости, отображает актуальные каналы,
|
||||
* управляет лампами и отслеживает тайм-аут связи через Lonely. Перед выходом
|
||||
* восстанавливает PIEIER и подтверждает источник Timer1.
|
||||
*/
|
||||
interrupt void cpu_timer1_isr_PULT(void)
|
||||
{
|
||||
static int cownt=0,count_bright;
|
||||
@@ -53,10 +74,11 @@ interrupt void cpu_timer1_isr_PULT(void)
|
||||
CanGO = 1;
|
||||
}
|
||||
|
||||
toggle_ONLINE(); // ñòðîá äëà ÏËÈÑ
|
||||
toggle_RES_OUT_1(); // òèïà ýòî ãîòîâíîñòü
|
||||
toggle_RES_OUT_2(); // íà âñàêèé
|
||||
toggle_ONLINE(); // строб дла ПЛИС
|
||||
toggle_RES_OUT_1(); // типа это готовность
|
||||
toggle_RES_OUT_2(); // на всакий
|
||||
|
||||
/* Насыщение предотвращает переполнение счётчика после длительной потери связи. */
|
||||
if(++Lonely > Alone) Lonely = Alone;
|
||||
|
||||
if(++count_bright >= maximum_bright) count_bright = 0 ;
|
||||
@@ -66,6 +88,7 @@ interrupt void cpu_timer1_isr_PULT(void)
|
||||
if(count_bright < Bright[i]) light+=(1<<i);
|
||||
}
|
||||
|
||||
/* За один ISR обновляется одна из трёх групп индикаторов. */
|
||||
if(++cownt>2) cownt=0;
|
||||
|
||||
if(cTestLamp|bTestLamp)
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @file spise2p.c
|
||||
* @brief Неблокирующий драйвер последовательной EEPROM поверх SPI.
|
||||
*
|
||||
* Высокоуровневые Seeprom_read/Seeprom_write запускают транзакцию, а конечный
|
||||
* автомат SPISE2P_DRV_tick продвигается от Timer2. Состояние драйвера единично:
|
||||
* новую операцию разрешено начинать только после spiSe2pFree(). Адрес и длина
|
||||
* должны укладываться в SEEPROM_LEN и не пересекать ограничения микросхемы.
|
||||
*/
|
||||
/*=================================================================
|
||||
File name : SPISE2PD.C
|
||||
|
||||
@@ -32,6 +41,14 @@ int ccc=0;
|
||||
/******* SPI bus Serial EEPROM driver Initialization routine ********/
|
||||
/********************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Синхронно записывает пользовательский блок через асинхронный драйвер.
|
||||
* @param adres Начальный адрес EEPROM.
|
||||
* @param buf Источник данных в памяти DSP.
|
||||
* @param size Размер блока в байтах.
|
||||
* @details Ожидает освобождения драйвера, запускает транзакцию и блокируется до
|
||||
* её завершения, которое продвигается прерываниями Timer2.
|
||||
*/
|
||||
void Seeprom_write( unsigned int adres,
|
||||
unsigned int buf[],
|
||||
unsigned int size)
|
||||
@@ -63,6 +80,12 @@ void Seeprom_write( unsigned int adres,
|
||||
CpuTimer2Regs.TCR.all = 0x4010; // Use write-only instruction to set TSS bit = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Синхронно читает блок EEPROM в пользовательский буфер.
|
||||
* @param adres Начальный адрес EEPROM.
|
||||
* @param buf Приёмный буфер DSP.
|
||||
* @param size Размер в байтах.
|
||||
*/
|
||||
void Seeprom_read( unsigned int adres,
|
||||
unsigned int buf[],
|
||||
unsigned int size)
|
||||
@@ -94,6 +117,10 @@ void Seeprom_read( unsigned int adres,
|
||||
CpuTimer2Regs.TCR.all = 0x4010; // Use write-only instruction to set TSS bit = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализирует SPI, объект драйвера и периодический Timer2.
|
||||
* @post se2p находится в свободном состоянии, Timer2 вызывает cpu_timer2_isr().
|
||||
*/
|
||||
void InitSeeprom()
|
||||
{
|
||||
se2p.init(&se2p);
|
||||
@@ -108,6 +135,7 @@ void InitSeeprom()
|
||||
IER |= M_INT14;
|
||||
}
|
||||
|
||||
/** @brief Сбрасывает конечный автомат и программирует регистры SPI-A. */
|
||||
void SPISE2P_DRV_init(SPISE2P_DRV *eeprom)
|
||||
{
|
||||
/* Configure SPI-A pins using GPIO regs*/
|
||||
@@ -141,28 +169,33 @@ void SPISE2P_DRV_init(SPISE2P_DRV *eeprom)
|
||||
SpiaRegs.SPICCR.bit.SPISWRESET=1; // Enable SCI
|
||||
}
|
||||
|
||||
/** @brief Деактивирует chip-select EEPROM. */
|
||||
void SPISE2P_DRV_csset()
|
||||
{
|
||||
GpioDataRegs.GPADAT.bit.GPIO19 = 1;
|
||||
}
|
||||
|
||||
/** @brief Активирует chip-select EEPROM перед транзакцией. */
|
||||
void SPISE2P_DRV_csclr()
|
||||
{
|
||||
GpioDataRegs.GPADAT.bit.GPIO19 = 0;
|
||||
}
|
||||
|
||||
/** @brief Возвращает ненулевое значение, если конечный автомат не занят. */
|
||||
unsigned int spiSe2pFree(SPISE2P_DRV *se2p)
|
||||
{
|
||||
if(se2p->csr&0x3) return(0);
|
||||
else return(1);
|
||||
}
|
||||
|
||||
/** @brief Привязывает описание блока и переводит автомат в начало записи. */
|
||||
void spiSe2pWrite(SPISE2P_DRV *se2p, SE2P_DATA *msgPtr)
|
||||
{
|
||||
se2p->msgPtr=msgPtr;
|
||||
se2p->csr|=0x1;
|
||||
}
|
||||
|
||||
/** @brief Привязывает описание блока и переводит автомат в начало чтения. */
|
||||
void spiSe2pRead(SPISE2P_DRV *se2p, SE2P_DATA *msgPtr)
|
||||
{
|
||||
se2p->msgPtr=msgPtr;
|
||||
@@ -173,6 +206,10 @@ void spiSe2pRead(SPISE2P_DRV *se2p, SE2P_DATA *msgPtr)
|
||||
/******* SPI bus Serial EEPROM driver Tick function *****************/
|
||||
/********************************************************************/
|
||||
|
||||
/**
|
||||
* @brief ISR Timer2, задающий такт конечному автомату EEPROM.
|
||||
* @note Один вызов выполняет только ограниченный шаг SPI-транзакции.
|
||||
*/
|
||||
interrupt void cpu_timer2_isr(void)
|
||||
{ EALLOW;
|
||||
CpuTimer2.InterruptCount++;
|
||||
@@ -183,6 +220,12 @@ interrupt void cpu_timer2_isr(void)
|
||||
EDIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Выполняет один переход конечного автомата SPI EEPROM.
|
||||
* @details Состояния последовательно выдают opcode, адрес и данные, ожидают
|
||||
* флаги SPI, управляют CS и проверяют готовность микросхемы после записи.
|
||||
* @param eeprom Активный экземпляр драйвера с описанием текущего блока.
|
||||
*/
|
||||
void SPISE2P_DRV_tick(SPISE2P_DRV *eeprom)
|
||||
{
|
||||
static unsigned int step=0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user