запущен проект motor identification c терминалкой
This commit is contained in:
157
AD_Keil_Project/AD_docs/ADC_CURRENT_SENSORS.md
Normal file
157
AD_Keil_Project/AD_docs/ADC_CURRENT_SENSORS.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# Чтение датчиков токов через ADC
|
||||
|
||||
## Где реализовано
|
||||
|
||||
Чтение токов добавлено в:
|
||||
|
||||
```text
|
||||
AD_Keil_Project/Core/Src/ad_board.c
|
||||
```
|
||||
|
||||
Главная функция:
|
||||
|
||||
```c
|
||||
void AD_Board_ReadMeasurements(AD_Measurements_t *meas);
|
||||
```
|
||||
|
||||
Она вызывается из `AD_Board_Loop()` на каждой итерации основного цикла. Внутри теперь вызывается ADC-слой, который заполняет:
|
||||
|
||||
```c
|
||||
meas->ia_A;
|
||||
meas->ib_A;
|
||||
meas->ic_A;
|
||||
meas->vdc_V;
|
||||
```
|
||||
|
||||
## Распиновка IHM08M1 по схеме ST
|
||||
|
||||
Каналы взяты не произвольно. Для `X-NUCLEO-IHM08M1` использована официальная схема ST `x-nucleo-ihm08m1_schematic.pdf`: на рисунке 6 указаны сигналы `PA0 - PhA`, `PC1 - PhB`, `PC0 - PhC`, `PA1 - BUSV`, `PC2 - Temp. Sens.`.
|
||||
|
||||
Источник схемы: `https://www.st.com/resource/en/schematic_pack/x-nucleo-ihm08m1_schematic.pdf`.
|
||||
|
||||
В коде сейчас читаются три фазных тока и напряжение DC-звена:
|
||||
|
||||
| Сигнал | Пин STM32 | ADC-канал | Поле измерений |
|
||||
|---|---|---:|---|
|
||||
| Ток фазы A | `PA0` | `ADC1_IN1` | `ia_A` |
|
||||
| Ток фазы B | `PC1` | `ADC1_IN7` | `ib_A` |
|
||||
| Ток фазы C | `PC0` | `ADC1_IN6` | `ic_A` |
|
||||
| DC-звено | `PA1` | `ADC1_IN2` | `vdc_V` |
|
||||
| Температура IHM08M1 | `PC2` | `ADC1_IN8` | пока не читается |
|
||||
|
||||
Эти пины настраиваются прямо в `ad_board.c`: включается тактирование `GPIOA` и `GPIOC`, пины `PA0`, `PA1`, `PC0`, `PC1` переводятся в аналоговый режим, затем `ADC1` читает каналы `1`, `7`, `6`, `2`.
|
||||
|
||||
Важно: это пока не CubeMX-конфигурация `.ioc`, а ручной аппаратный слой в коде. После подтверждения схемы надо перенести назначение в CubeMX или аккуратно синхронизировать `.ioc`.
|
||||
|
||||
## Масштабирование
|
||||
|
||||
По умолчанию используются безопасные макросы:
|
||||
|
||||
```c
|
||||
AD_BOARD_ADC_VREF_V 3.3f
|
||||
AD_BOARD_ADC_CURRENT_ZERO_V AD_BOARD_ADC_VREF_V * 0.5f
|
||||
AD_BOARD_ADC_DEFAULT_PHASE_SHUNT_OHM (0.1f)
|
||||
AD_BOARD_ADC_CURRENT_A_PER_V 1.0f / AD_BOARD_ADC_DEFAULT_PHASE_SHUNT_OHM
|
||||
AD_BOARD_ADC_VDC_BUS_V_PER_ADC_V 12.1770f
|
||||
AD_BOARD_ADC_VDC_LOW_CAL_ADC_V 0.618f
|
||||
AD_BOARD_ADC_VDC_LOW_CAL_BUS_V 10.0f
|
||||
AD_BOARD_ADC_VDC_HIGH_CAL_BUS_V 14.5f
|
||||
AD_BOARD_ADC_VDC_AVG_SAMPLES 16
|
||||
AD_BOARD_ADC_VDC_FILTER_ALPHA 0.125f
|
||||
```
|
||||
|
||||
Формулы:
|
||||
|
||||
```text
|
||||
Uadc = raw * AD_BOARD_ADC_VREF_V / 4095
|
||||
Iphase = (Uadc - AD_BOARD_ADC_CURRENT_ZERO_V) * AD_BOARD_ADC_CURRENT_A_PER_V * (0.1 / Rshunt)
|
||||
Udc = adc_vdc_from_voltage(Uadc)
|
||||
```
|
||||
|
||||
`Rshunt` задаётся через Modbus register `0x0041` / `H065_param_phase_shunt_mohm`
|
||||
с масштабом `1 мОм`. Дефолт `0.1 Ом` читается как `100`; запись `0` возвращает
|
||||
прошивку к дефолту.
|
||||
|
||||
Для DC-звена `Uadc` берется после сглаживания, а не из одного одиночного преобразования:
|
||||
|
||||
```text
|
||||
vdc_raw = последний одиночный ADC-код PA1/BUSV
|
||||
vdc_raw_avg = средний ADC-код PA1/BUSV
|
||||
vdc_adc_avg_V = vdc_raw_avg * AD_BOARD_ADC_VREF_V / 4095
|
||||
vdc_adc_V = IIR(vdc_adc_avg_V, AD_BOARD_ADC_VDC_FILTER_ALPHA)
|
||||
vdc_V = adc_vdc_from_voltage(vdc_adc_V)
|
||||
```
|
||||
|
||||
По умолчанию `AD_BOARD_ADC_VDC_AVG_SAMPLES=16`, а `AD_BOARD_ADC_VDC_FILTER_ALPHA=0.125`. Для более быстрой реакции можно поднять `AD_BOARD_ADC_VDC_FILTER_ALPHA` до `0.25`; для более спокойной индикации можно опустить до `0.05`.
|
||||
|
||||
Для DC-звена сейчас задан измеренный коэффициент по реальной плате:
|
||||
|
||||
```text
|
||||
реальное Udc = 10.0 В
|
||||
измеренное напряжение на ADC/PA1 = 0.618 В
|
||||
AD_BOARD_ADC_VDC_LOW_CAL_ADC_V = 0.618
|
||||
AD_BOARD_ADC_VDC_LOW_CAL_BUS_V = 10.0
|
||||
AD_BOARD_ADC_VDC_BUS_V_PER_ADC_V = 12.1770
|
||||
AD_BOARD_ADC_VDC_HIGH_CAL_BUS_V = 14.5
|
||||
```
|
||||
|
||||
После этой калибровки `g_ad_debug.measurements.vdc_V` должен показывать около `10 В`, когда `g_ad_debug.adc.vdc_adc_V` около `0.618 В`.
|
||||
|
||||
Если DC-звено прыгает почти на `1 В`, это примерно `77` отсчетов ADC на входе `PA1`, потому что один ADC-код после масштабирования равен примерно:
|
||||
|
||||
```text
|
||||
3.3 / 4095 * 12.1770 = 0.0098 В DC-шины
|
||||
```
|
||||
|
||||
Основные причины такого разброса: одиночная выборка ADC, пульсации DC-звена, наводки от PWM/силовой земли, несинхронный запуск ADC относительно ШИМ, длинные провода/земля измерения или шумный делитель. В коде одиночная выборка DC-звена заменена усреднением и IIR-фильтром.
|
||||
|
||||
Для реальной платы нужно также задать настоящие коэффициенты датчиков тока в настройках компиляции Keil или в коде. Коэффициент DC-звена можно переопределить в настройках компиляции, если будет новая точка калибровки.
|
||||
|
||||
Пример:
|
||||
|
||||
```text
|
||||
AD_BOARD_ADC_CURRENT_A_PER_V=20.0f
|
||||
AD_BOARD_ADC_DEFAULT_PHASE_SHUNT_OHM=0.1f
|
||||
AD_BOARD_ADC_VDC_BUS_V_PER_ADC_V=12.1770f
|
||||
AD_BOARD_ADC_VDC_LOW_CAL_ADC_V=0.618f
|
||||
AD_BOARD_ADC_VDC_LOW_CAL_BUS_V=10.0f
|
||||
AD_BOARD_ADC_VDC_HIGH_CAL_BUS_V=14.5f
|
||||
AD_BOARD_ADC_VDC_AVG_SAMPLES=16
|
||||
AD_BOARD_ADC_VDC_FILTER_ALPHA=0.125f
|
||||
```
|
||||
|
||||
## Что смотреть в Keil
|
||||
|
||||
В окно наблюдения добавьте:
|
||||
|
||||
```c
|
||||
g_ad_debug.adc
|
||||
g_ad_debug.measurements
|
||||
```
|
||||
|
||||
Поля `g_ad_debug.adc`:
|
||||
|
||||
| Поле | Смысл |
|
||||
|---|---|
|
||||
| `initialized` | ADC успешно запущен |
|
||||
| `faults` | ошибки init или ожидания преобразования |
|
||||
| `ia_raw`, `ib_raw`, `ic_raw` | сырые 12-битные значения ADC токовых каналов |
|
||||
| `vdc_raw` | последний одиночный 12-битный ADC-код `PA1/BUSV` |
|
||||
| `vdc_raw_avg` | средний ADC-код `PA1/BUSV` после `AD_BOARD_ADC_VDC_AVG_SAMPLES` преобразований |
|
||||
| `ia_adc_V`, `ib_adc_V`, `ic_adc_V` | напряжения на входах ADC токовых каналов |
|
||||
| `vdc_adc_avg_V` | напряжение `PA1/BUSV` после среднего по нескольким преобразованиям |
|
||||
| `vdc_adc_V` | отфильтрованное напряжение `PA1/BUSV`, которое используется для расчета `vdc_V` |
|
||||
|
||||
Поля `g_ad_debug.measurements.ia_A`, `ib_A`, `ic_A`, `vdc_V` показывают уже пересчитанные физические величины.
|
||||
|
||||
## Что осталось проверить на железе
|
||||
|
||||
- Соответствует ли подключенная плата именно распиновке `X-NUCLEO-IHM08M1`: `PA0/PhA`, `PC1/PhB`, `PC0/PhC`, `PA1/BUSV`.
|
||||
- Нужно ли добавить чтение температуры `PC2 / ADC1_IN8`.
|
||||
- Какой ноль у датчиков тока: обычно около `Vref/2`, но это надо измерить.
|
||||
- Какой коэффициент `А/В` у датчиков тока.
|
||||
- Уточнить коэффициент делителя DC-звена второй точкой, например на 20-30 В, если питание и безопасность позволяют.
|
||||
- Нет ли инверсии знака токов.
|
||||
- Нужно ли запускать ADC синхронно от `TIM1`, а не из основного цикла.
|
||||
|
||||
Для первого включения с силовой частью держать `AD_INVERTER_ENABLE_OUTPUTS=0`, смотреть только сырые ADC и пересчитанные значения.
|
||||
43
AD_Keil_Project/AD_docs/BINARY_TRANSPORT.md
Normal file
43
AD_Keil_Project/AD_docs/BINARY_TRANSPORT.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Binary Telemetry Transport
|
||||
|
||||
The firmware initializes two physical transports for the existing binary
|
||||
telemetry packet:
|
||||
|
||||
- USB FS CDC ACM on PA11/PA12, clocked from HSI48.
|
||||
- FDCAN1 classic CAN on PB8/PB9, default 500 kbit/s with an external CAN transceiver.
|
||||
|
||||
Modbus RTU on USART2 remains active as the control channel. This is intentional:
|
||||
the host can always switch the telemetry mode back without reflashing.
|
||||
|
||||
## Modbus Selection Registers
|
||||
|
||||
Modbus protocol/register-map version is `7`.
|
||||
|
||||
| Address hex / dec | Field | Access | Purpose |
|
||||
|---:|---|---|---|
|
||||
| `0x001C` / `28` | `H028_control_host_protocol` | R/W | `0`=Modbus control only, `1`=binary telemetry output enabled |
|
||||
| `0x001D` / `29` | `H029_control_binary_transport` | R/W | `0`=USB CDC, `1`=CAN/FDCAN1, `2`=USB CDC and CAN |
|
||||
|
||||
## USB CDC
|
||||
|
||||
USB is exposed as a CDC ACM serial stream. The stream does not guarantee message
|
||||
boundaries, so the PC side should parse by the telemetry header:
|
||||
|
||||
- `magic`
|
||||
- `payload_size`
|
||||
- `sequence`
|
||||
- `crc16`
|
||||
|
||||
## CAN/FDCAN
|
||||
|
||||
CAN carries the same binary packet split into classic 8-byte frames:
|
||||
|
||||
| Standard ID | Payload |
|
||||
|---:|---|
|
||||
| `0x5A0` | packet bytes `0..7` |
|
||||
| `0x5A1` | packet bytes `8..15` |
|
||||
| `0x5A2` | packet bytes `16..23` |
|
||||
|
||||
The base standard ID is controlled by `AD_CAN_TELEMETRY_STD_ID_BASE`, default
|
||||
`0x5A0`. The receiver reconstructs the packet from sequential frame IDs and
|
||||
uses the normal binary telemetry header to determine the full packet length.
|
||||
129
AD_Keil_Project/AD_docs/BUILD_AND_RUN.md
Normal file
129
AD_Keil_Project/AD_docs/BUILD_AND_RUN.md
Normal file
File diff suppressed because one or more lines are too long
177
AD_Keil_Project/AD_docs/DATA_STRUCTURES.md
Normal file
177
AD_Keil_Project/AD_docs/DATA_STRUCTURES.md
Normal file
File diff suppressed because one or more lines are too long
176
AD_Keil_Project/AD_docs/HOW_TO_START_TEST_AND_WATCH.md
Normal file
176
AD_Keil_Project/AD_docs/HOW_TO_START_TEST_AND_WATCH.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# Как начать тест и что смотреть в отладке
|
||||
|
||||
## Главное
|
||||
|
||||
В проект добавлены три уровня запуска:
|
||||
|
||||
- безопасное логирование без силовых ключей;
|
||||
- тестовый PWM на каждый отдельный вход драйвера `UH/UL/VH/VL/WH/WL`;
|
||||
- начальный алгоритм идентификации, который сейчас оценивает `Rs`, `Ls` и `Ll`.
|
||||
|
||||
По умолчанию физические PWM-выходы выключены на уровне сборки. Это сделано намеренно: прошивку можно залить и смотреть ADC без риска включить ключи.
|
||||
|
||||
## Где вход в приложение
|
||||
|
||||
Основной проект Keil:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\AD_Keil_Project\MDK-ARM\IHM08M.uvprojx
|
||||
```
|
||||
|
||||
Основная Simulink-модель:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl\inu_im_1wnd_3lvl.slx
|
||||
```
|
||||
|
||||
В коде запуск находится в `main.c`:
|
||||
|
||||
```c
|
||||
AD_Project_Init();
|
||||
|
||||
while (1)
|
||||
{
|
||||
AD_Project_Loop();
|
||||
}
|
||||
```
|
||||
|
||||
## Безопасный первый запуск
|
||||
|
||||
Для проверки измерений без ключей:
|
||||
|
||||
```c
|
||||
AD_Board_StartDataLogging();
|
||||
```
|
||||
|
||||
Останов:
|
||||
|
||||
```c
|
||||
AD_Board_StopParamTest();
|
||||
```
|
||||
|
||||
Кнопка `B1 / PC13` переключает только `DATA_LOGGING`, силовые ключи она не включает.
|
||||
|
||||
## Как разрешить реальные PWM-импульсы
|
||||
|
||||
Перед этим нужно проверить питание, `BKIN`, полярности входов драйвера, dead-time и ограничения тока/напряжения.
|
||||
|
||||
В Keil, в `Options for Target -> C/C++ -> Define`, можно включить один общий макрос:
|
||||
|
||||
```text
|
||||
AD_PROJECT_POWER_TEST_ENABLE=1
|
||||
```
|
||||
|
||||
Он внутри включает:
|
||||
|
||||
```text
|
||||
AD_PARAM_ID_ENABLE_POWER_TESTS=1
|
||||
AD_INVERTER_ENABLE_OUTPUTS=1
|
||||
```
|
||||
|
||||
Если `AD_PROJECT_POWER_TEST_ENABLE=0`, запрос силового режима будет переведён в безопасное логирование с флагом `AD_PARAM_ID_STATUS_POWER_TEST_BLOCKED`.
|
||||
|
||||
## PWM-тест каждого канала
|
||||
|
||||
Для проверки входов драйвера осциллографом:
|
||||
|
||||
```c
|
||||
AD_Board_StartParamTestWithDuty(AD_PARAM_ID_MODE_PWM_TEST_UH, 0.08f);
|
||||
AD_Board_StopParamTest();
|
||||
```
|
||||
|
||||
Второй аргумент это duty. Если передать `0`, будет использовано значение по умолчанию `AD_PARAM_ID_DEFAULT_PWM_DUTY_LIMIT = 0.08`. Внутренний тестовый алгоритм дополнительно ограничивает duty до `0.20`.
|
||||
|
||||
Рекомендуемый порядок проверки:
|
||||
|
||||
| Режим | Код | Пин IHM08M1 |
|
||||
|---|---:|---|
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_UH` | 6 | `PA8 / TIM1_CH1 / UH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_UL` | 7 | `PA7 / TIM1_CH1N / UL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_VH` | 8 | `PA9 / TIM1_CH2 / VH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_VL` | 9 | `PB0 / TIM1_CH2N / VL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_WH` | 10 | `PA10 / TIM1_CH3 / WH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_WL` | 11 | `PB1 / TIM1_CH3N / WL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_ALL` | 12 | все три плеча, duty фаз `0.5` |
|
||||
|
||||
В режиме одного канала проект не перезапускает таймер каждые 10 мс: выбранный канал удерживается, а последующие шаги только обновляют compare.
|
||||
|
||||
## Режимы идентификации
|
||||
|
||||
| Режим | Код | Что делает сейчас |
|
||||
|---|---:|---|
|
||||
| `AD_PARAM_ID_MODE_IDLE` | 0 | выключено |
|
||||
| `AD_PARAM_ID_MODE_STATOR_RESISTANCE` | 1 | оценивает `Rs_ohm` коротким DC-вектором |
|
||||
| `AD_PARAM_ID_MODE_NO_LOAD_MAGNETIZING` | 2 | оценивает `Lm_H` вращающимся полем без нагрузки |
|
||||
| `AD_PARAM_ID_MODE_LOCKED_ROTOR_LEAKAGE` | 3 | оценивает `Ll_H` и `Rr_ohm`; требует `AD_ParamID_SetLockedRotorAllowed(1)` |
|
||||
| `AD_PARAM_ID_MODE_INERTIA_FRICTION` | 4 | оценивает `J` и `B` по разгону/выбегу; нужен ненулевой `speed_rpm` |
|
||||
| `AD_PARAM_ID_MODE_DATA_LOGGING` | 5 | только измерения |
|
||||
| `AD_PARAM_ID_MODE_AUTO_IDENTIFICATION` | 13 | последовательно делает `Rs`, `Ll`, `Rr`, `Lm`, затем `J/B` |
|
||||
| `AD_PARAM_ID_MODE_ROTATION_3HZ` | 14 | 6-step вращение с настраиваемой частотой и модуляцией |
|
||||
|
||||
Запуск автоидентификации:
|
||||
|
||||
```c
|
||||
AD_Board_StartParamTestWithDuty(AD_PARAM_ID_MODE_AUTO_IDENTIFICATION, 0.08f);
|
||||
```
|
||||
|
||||
Запуск проверки вращения 3 Гц:
|
||||
|
||||
```c
|
||||
AD_Board_StartParamTestWithDuty(AD_PARAM_ID_MODE_ROTATION_3HZ, 0.35f);
|
||||
```
|
||||
|
||||
Через Modbus для этого режима:
|
||||
|
||||
```text
|
||||
write 0x000D / 13 = 30 ; частота 3.00 Hz
|
||||
write 0x000E / 14 = 3500 ; модуляция 0.35
|
||||
```
|
||||
|
||||
`J` и `B` помечаются действительными только если во время разгона и выбега приходит скорость `speed_rpm`; при нулевой скорости алгоритм не записывает фиктивные механические параметры.
|
||||
|
||||
## Что смотреть в Keil
|
||||
|
||||
Добавить в Watch:
|
||||
|
||||
```c
|
||||
g_ad_debug
|
||||
```
|
||||
|
||||
Основные поля:
|
||||
|
||||
| Поле | Смысл |
|
||||
|---|---|
|
||||
| `g_ad_debug.adc.ia_raw`, `ib_raw`, `ic_raw` | сырые ADC-коды токов |
|
||||
| `g_ad_debug.adc.vdc_raw_avg` | усреднённый ADC-код `BUSV` |
|
||||
| `g_ad_debug.adc.vdc_adc_V` | отфильтрованное напряжение на входе `PA1/BUSV` |
|
||||
| `g_ad_debug.measurements.vdc_V` | пересчитанное напряжение DC-звена |
|
||||
| `g_ad_debug.command.test_mode` | запрошенный режим |
|
||||
| `g_ad_debug.param_id_mode` | фактический режим |
|
||||
| `g_ad_debug.inverter.pwm_running` | TIM1 PWM реально запущен |
|
||||
| `g_ad_debug.inverter.service_pwm_running` | включён одиночный/сервисный PWM-тест |
|
||||
| `g_ad_debug.inverter.service_output` | какой выход проверяется: `1..7` |
|
||||
| `g_ad_debug.inverter.id_stage` | стадия алгоритма измерения |
|
||||
| `g_ad_debug.motor_parameters.valid_mask` | какие параметры действительны |
|
||||
| `g_ad_debug.motor_parameters.Rs_ohm` | измеренное сопротивление статора |
|
||||
| `g_ad_debug.motor_parameters.Ls_H` | измеренная индуктивность статора |
|
||||
| `g_ad_debug.motor_parameters.Ll_H` | оценка индуктивности рассеяния |
|
||||
|
||||
## Флаги состояния
|
||||
|
||||
| Флаг | Смысл |
|
||||
|---|---|
|
||||
| `AD_PARAM_ID_STATUS_ACTIVE` | режим активен |
|
||||
| `AD_PARAM_ID_STATUS_POWER_TEST_BLOCKED` | силовой тест заблокирован |
|
||||
| `AD_PARAM_ID_STATUS_POWER_STAGE_ARMED` | силовая часть программно разрешена |
|
||||
| `AD_PARAM_ID_STATUS_FAULT_LATCHED` | авария защёлкнута |
|
||||
| `AD_PARAM_ID_STATUS_TIMEOUT` | истекло время теста |
|
||||
| `AD_PARAM_ID_STATUS_LOCKED_ROTOR_BLOCKED` | locked-rotor режим не разрешён |
|
||||
| `AD_PARAM_ID_STATUS_SAFETY_LIMITS_UNKNOWN` | не заданы пределы тока или напряжения |
|
||||
| `AD_PARAM_ID_STATUS_DATA_VALID` | есть актуальные измерения/данные |
|
||||
| `AD_PARAM_ID_STATUS_COMPLETE` | алгоритм измерения завершён |
|
||||
| `AD_PARAM_ID_STATUS_PARTIAL_COMPLETE` | автоидентификация завершилась частично: часть параметров действительна |
|
||||
| `AD_PARAM_ID_STATUS_STEP_FAILED` | этап измерения не смог получить достаточный ток/напряжение/скорость |
|
||||
| `AD_PARAM_ID_STATUS_LOCKED_ROTOR_SKIPPED` | locked-rotor этап пропущен, потому что `locked_rotor_allowed=0` |
|
||||
|
||||
Любой `Stop`, fault или переход в блокировку вызывает аппаратное выключение PWM через `AD_ParamID_HardwareDisable()`.
|
||||
29
AD_Keil_Project/AD_docs/KEIL_ADD_FILES.md
Normal file
29
AD_Keil_Project/AD_docs/KEIL_ADD_FILES.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Файлы, добавленные в Keil
|
||||
|
||||
В собранном проекте `AD_Keil_Project/MDK-ARM/IHM08M.uvprojx` уже добавлена группа:
|
||||
|
||||
```text
|
||||
Application/User/AD Param ID
|
||||
```
|
||||
|
||||
В неё включены:
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `Core/Src/ad_project.c` | Общая инициализация проекта, единая точка `AD_Project_Init()`, цикл `AD_Project_Loop()` и структура `g_ad_debug` |
|
||||
| `Core/Src/ad_board.c` | Слой платы, кнопка, LED, безопасный цикл приложения |
|
||||
| `Core/Src/ad_inverter.c` | Инициализация и управление ключами инвертора, безопасное выключение PWM |
|
||||
| `Core/Src/ad_parameter_identification.c` | Состояние идентификации, защиты, команды тестов |
|
||||
| `Core/Src/simulink_interface.c` | Обмен измерениями, командами и телеметрией |
|
||||
|
||||
Заголовочные файлы лежат в `Core/Inc`, этот путь уже есть в путях включения проекта.
|
||||
|
||||
Файл `Core/Src/ad_debug.c` оставлен как пустая совместимая единица трансляции. Для сборки он не обязателен: `AD_Debug_Init()`, `AD_Debug_Update()` и `g_ad_debug` реализованы в `Core/Src/ad_project.c`. Это сделано специально, чтобы проект не падал линковкой, если Keil ещё не подхватил новый файл в списке исходников.
|
||||
|
||||
Если проект будет перенесён в новый `.uvprojx`, нужно добавить те же `.c` файлы и путь:
|
||||
|
||||
```text
|
||||
Core/Inc
|
||||
```
|
||||
|
||||
Сгенерированные файлы Simulink вручную не править, если это не предусмотрено процессом генерации.
|
||||
97
AD_Keil_Project/AD_docs/MD_DRIVER_MAP.md
Normal file
97
AD_Keil_Project/AD_docs/MD_DRIVER_MAP.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Карта слоя драйвера двигателя
|
||||
|
||||
## Что сейчас реализовано
|
||||
|
||||
Проект содержит рабочий слой TIM1 для IHM08M1:
|
||||
|
||||
- `PA8 / TIM1_CH1 / UH`;
|
||||
- `PA7 / TIM1_CH1N / UL`;
|
||||
- `PA9 / TIM1_CH2 / VH`;
|
||||
- `PB0 / TIM1_CH2N / VL`;
|
||||
- `PA10 / TIM1_CH3 / WH`;
|
||||
- `PB1 / TIM1_CH3N / WL`;
|
||||
- `PA6 / TIM1_BKIN / BKIN`.
|
||||
|
||||
TIM1 PWM timing: center-aligned mode, `ARR=32767`, `PSC=0`; carrier remains about 2.6 kHz.
|
||||
|
||||
`MX_TIM1_Init()` настраивает PWM1 на трёх каналах, комплементарные выходы, dead-time `AD_TIM1_DEADTIME_TICKS=100` и Break input.
|
||||
|
||||
## Безопасность включения
|
||||
|
||||
По умолчанию физические выходы запрещены:
|
||||
|
||||
```text
|
||||
AD_PROJECT_POWER_TEST_ENABLE=0
|
||||
```
|
||||
|
||||
Для стендового включения можно задать:
|
||||
|
||||
```text
|
||||
AD_PROJECT_POWER_TEST_ENABLE=1
|
||||
```
|
||||
|
||||
Это включает внутренние макросы:
|
||||
|
||||
```text
|
||||
AD_PARAM_ID_ENABLE_POWER_TESTS=1
|
||||
AD_INVERTER_ENABLE_OUTPUTS=1
|
||||
```
|
||||
|
||||
При `Stop`, fault, блокировке силового теста или `enable=0` вызывается `AD_ParamID_HardwareDisable()`, который в реализации `ad_inverter.c` гасит TIM1 через `AD_Inverter_Disable()`.
|
||||
|
||||
## API инвертора
|
||||
|
||||
| Функция | Назначение |
|
||||
|---|---|
|
||||
| `AD_Inverter_Init()` | инициализация состояния inverter слоя |
|
||||
| `AD_Inverter_Disable()` | останов всех PWM и сброс duty |
|
||||
| `AD_Inverter_SetDuty(a,b,c)` | запись duty трёх фаз |
|
||||
| `AD_Inverter_Enable()` | запуск всех трёх каналов и комплементарных выходов |
|
||||
| `AD_Inverter_StartPwmOutput(output,duty)` | сервисный PWM на один вход драйвера или на все плечи |
|
||||
| `AD_Inverter_ApplyCommand()` | применить трёхфазную команду |
|
||||
|
||||
## PWM-тест каналов
|
||||
|
||||
Сервисные режимы:
|
||||
|
||||
| Режим | Канал |
|
||||
|---|---|
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_UH` | `PA8 / UH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_UL` | `PA7 / UL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_VH` | `PA9 / VH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_VL` | `PB0 / VL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_WH` | `PA10 / WH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_WL` | `PB1 / WL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_ALL` | все три плеча, duty фаз `0.5` |
|
||||
|
||||
Пример:
|
||||
|
||||
```c
|
||||
AD_Board_StartParamTestWithDuty(AD_PARAM_ID_MODE_PWM_TEST_UH, 0.08f);
|
||||
```
|
||||
|
||||
Одиночный PWM-тест удерживает уже запущенный канал и не делает `Stop/Start` на каждом slow-step.
|
||||
|
||||
## Алгоритм измерения
|
||||
|
||||
Сейчас в `AD_ParamID_HardwareStep()` реализованы:
|
||||
|
||||
| Режим | Результат |
|
||||
|---|---|
|
||||
| `AD_PARAM_ID_MODE_STATOR_RESISTANCE` | измеряет `Rs_ohm`, ставит `AD_MOTOR_PARAM_VALID_RS` |
|
||||
| `AD_PARAM_ID_MODE_LOCKED_ROTOR_LEAKAGE` | измеряет `Ll_H` и `Rr_ohm`; после `Lm_H` пересчитывает `Ls_H/Lr_H` |
|
||||
| `AD_PARAM_ID_MODE_NO_LOAD_MAGNETIZING` | измеряет `Lm_H` вращающимся полем без нагрузки |
|
||||
| `AD_PARAM_ID_MODE_INERTIA_FRICTION` | измеряет `J_kg_m2` и `B_Nm_s` по разгону/выбегу при наличии `speed_rpm` |
|
||||
| `AD_PARAM_ID_MODE_AUTO_IDENTIFICATION` | последовательно выполняет `Rs`, `Ll`, `Rr`, `Lm`, затем `J/B` |
|
||||
| `AD_PARAM_ID_MODE_ROTATION_3HZ` | выдаёт 6-step вращение до 3 Гц для проверки работы двигателя |
|
||||
|
||||
Для расчёта `J` и `B` нужен реальный сигнал скорости в `AD_Measurements_t.speed_rpm`; при нулевой скорости механические параметры не помечаются действительными.
|
||||
|
||||
## Что ещё нужно проверить на железе
|
||||
|
||||
- полярность `UH/UL/VH/VL/WH/WL` на входе реального драйвера;
|
||||
- что `BKIN` реально выключает TIM1;
|
||||
- dead-time на затворах или входах драйвера;
|
||||
- масштаб и ноль токовых датчиков;
|
||||
- предел тока и напряжения перед первым запуском с двигателем;
|
||||
- наличие отдельного `EN_GATE`, если он есть на конкретной плате.
|
||||
425
AD_Keil_Project/AD_docs/MODBUS_REGISTERS.md
Normal file
425
AD_Keil_Project/AD_docs/MODBUS_REGISTERS.md
Normal file
File diff suppressed because one or more lines are too long
90
AD_Keil_Project/AD_docs/PINMAP_STM32G474CEU6.md
Normal file
90
AD_Keil_Project/AD_docs/PINMAP_STM32G474CEU6.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Распиновка STM32G474
|
||||
|
||||
## Источники
|
||||
|
||||
| Объект | Статус | Примечание |
|
||||
|---|---|---|
|
||||
| Проект `STM32G474CEU6` | не найден | Подтверждённого `.uvprojx/.ioc` для CEU6 нет |
|
||||
| Кандидатный проект | найден | `IHM08M`, цель `STM32G474RETx` |
|
||||
| CubeMX `.ioc` | найден | `AD_Keil_Project/IHM08M.ioc` |
|
||||
| Схема `X-NUCLEO-IHM08M1` | найдена | источник для ADC-сигналов `PhA`, `PhB`, `PhC`, `BUSV`, `Temp. Sens.`: `https://www.st.com/resource/en/schematic_pack/x-nucleo-ihm08m1_schematic.pdf` |
|
||||
| Плата | кандидат | `NUCLEO-G474RE`, не целевая плата CEU6 |
|
||||
| Старый embedded-код | найден | C2000/TMS320 в `Inu_im_1wnd_3lvl/Inu` |
|
||||
|
||||
## Подтверждённые пины STM32G474CEU6
|
||||
|
||||
Подтверждённой распиновки для `STM32G474CEU6` в проекте нет. Ниже приведена только кандидатная распиновка из `STM32G474RETx / NUCLEO-G474RE`.
|
||||
|
||||
## Кандидатная распиновка из `IHM08M.ioc` и схемы IHM08M1
|
||||
|
||||
| Пин | Сигнал | Направление | Назначение | Источник |
|
||||
|---|---|---|---|---|
|
||||
| `PC13` | `B1` | вход EXTI | кнопка пользователя | `.ioc`, `main.h` |
|
||||
| `PC14` | `RCC_OSC32_IN` | вход | LSE | `.ioc`, `main.h` |
|
||||
| `PC15` | `RCC_OSC32_OUT` | выход | LSE | `.ioc`, `main.h` |
|
||||
| `PC0` | `ADC1_IN6` | аналоговый вход | IHM08M1 `PhC`, ток фазы C | схема IHM08M1, `ad_board.c` |
|
||||
| `PC1` | `ADC1_IN7` | аналоговый вход | IHM08M1 `PhB`, ток фазы B | схема IHM08M1, `ad_board.c` |
|
||||
| `PC2` | `ADC1_IN8` | аналоговый вход | IHM08M1 `Temp. Sens.`, пока не читается | схема IHM08M1 |
|
||||
| `PF0` | `RCC_OSC_IN` | вход | HSE | `.ioc`, `main.h` |
|
||||
| `PF1` | `RCC_OSC_OUT` | выход | HSE | `.ioc`, `main.h` |
|
||||
| `PA0` | `ADC1_IN1` | аналоговый вход | IHM08M1 `PhA`, ток фазы A | схема IHM08M1, `ad_board.c` |
|
||||
| `PA1` | `ADC1_IN2` | аналоговый вход | IHM08M1 `BUSV`, напряжение DC-звена | схема IHM08M1, `ad_board.c` |
|
||||
| `PA5` | не используется | не инициализируется | IHM08M1 `PA5 - DAC`; конфликт с `LD2` убран | схема IHM08M1, `ad_board.c` |
|
||||
| `PA6` | `TIM1_BKIN` | AF-вход | аппаратный `BKIN` | `.ioc`, `stm32g4xx_hal_msp.c`, схема IHM08M1 |
|
||||
| `PA8` | `TIM1_CH1` | AF-выход | IHM08M1 `UH`, верхний ключ U | `.ioc`, `stm32g4xx_hal_msp.c`, `ad_inverter.c` |
|
||||
| `PA7` | `TIM1_CH1N` | AF-выход | IHM08M1 `UL`, нижний ключ U | `.ioc`, `stm32g4xx_hal_msp.c`, `ad_inverter.c` |
|
||||
| `PA9` | `TIM1_CH2` | AF-выход | IHM08M1 `VH`, верхний ключ V | `.ioc`, `stm32g4xx_hal_msp.c`, `ad_inverter.c` |
|
||||
| `PB0` | `TIM1_CH2N` | AF-выход | IHM08M1 `VL`, нижний ключ V | `.ioc`, `stm32g4xx_hal_msp.c`, `ad_inverter.c` |
|
||||
| `PA10` | `TIM1_CH3` | AF-выход | IHM08M1 `WH`, верхний ключ W | `.ioc`, `stm32g4xx_hal_msp.c`, `ad_inverter.c` |
|
||||
| `PB1` | `TIM1_CH3N` | AF-выход | IHM08M1 `WL`, нижний ключ W | `.ioc`, `stm32g4xx_hal_msp.c`, `ad_inverter.c` |
|
||||
| `PA13` | `T_SWDIO` | отладка | SWDIO | `.ioc`, `main.h` |
|
||||
| `PA14` | `T_SWCLK` | отладка | SWCLK | `.ioc`, `main.h` |
|
||||
| `PB3` | `GPIO_Input` | вход | IHM08M1 `Enc. B/H2`; SWO убран из `.ioc` | `.ioc`, схема IHM08M1 |
|
||||
|
||||
## Периферия кандидатного проекта
|
||||
|
||||
| Периферия | Статус |
|
||||
|---|---|
|
||||
| ADC | вручную включен `ADC1` в `ad_board.c`; `.ioc` еще не синхронизирован |
|
||||
| TIM/PWM | шесть линий IHM08M1 через `TIM1`: `UH/UL`, `VH/VL`, `WH/WL`; `PA6/TIM1_BKIN` включен |
|
||||
| GPIO | кнопка `B1`; `PA5/LD2` не используется по умолчанию |
|
||||
| DMA | HAL-файлы есть, CubeMX init нет |
|
||||
| UART/USART | не включён |
|
||||
| CAN/FDCAN | не включён |
|
||||
| SPI/I2C | не включён |
|
||||
| OPAMP/COMP | не включён |
|
||||
| Watchdog | не настроен |
|
||||
| TIM break | `PA6 / TIM1_BKIN`, `TIM_BREAKPOLARITY_HIGH`; полярность надо проверить на железе |
|
||||
|
||||
## Сигналы старого C2000-кода
|
||||
|
||||
Эти строки не являются STM32-распиновкой. Они нужны только как чек-лист миграции:
|
||||
|
||||
| Сигнал C2000 | Назначение |
|
||||
|---|---|
|
||||
| `EPWM1A/B` .. `EPWM6A/B` | PWM-выходы инвертора |
|
||||
| `ADCRESULT0` | DC-звено `udc1` |
|
||||
| `ADCRESULT2` | ток `ic1` |
|
||||
| `ADCRESULT4` | ток `ia1` |
|
||||
| `ADCRESULT6` | ток `ib1` |
|
||||
|
||||
Текущее STM32-сопоставление-кандидат:
|
||||
|
||||
| Сигнал | STM32 |
|
||||
|---|---|
|
||||
| `ia_A` | `PA0 / ADC1_IN1` |
|
||||
| `ib_A` | `PC1 / ADC1_IN7` |
|
||||
| `ic_A` | `PC0 / ADC1_IN6` |
|
||||
| `vdc_V` | `PA1 / ADC1_IN2`, кусочная калибровка: `0.618 В ADC -> 10 В`, выше `14.5 В` масштаб `12.1770 В/В` |
|
||||
| `EQEP2A/B/I` | датчик скорости/положения |
|
||||
| `DI_24V_SOURCE_FAULT` | авария +24 В |
|
||||
| `SPIA` + `CS` | EEPROM или внешний SPI |
|
||||
| `LED_GREEN1/2`, `LED_RED` | индикация |
|
||||
|
||||
## Что нужно для настоящей платы CEU6
|
||||
|
||||
- Добавить настоящий `.ioc` и `.uvprojx` для `STM32G474CEU6`.
|
||||
- Заполнить ШИМ-пины, комплементарные выходы, мёртвое время и break.
|
||||
- Заполнить ADC-каналы токов, DC-звена и температуры.
|
||||
- Добавить входы аварии и аварийного стопа.
|
||||
- Перегенерировать этот документ по реальному CubeMX-проекту.
|
||||
144
AD_Keil_Project/AD_docs/PINOUT_MEASUREMENTS_TEST_CONTROL.md
Normal file
144
AD_Keil_Project/AD_docs/PINOUT_MEASUREMENTS_TEST_CONTROL.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# Распиновка, измерения и управление тестами
|
||||
|
||||
## Проект
|
||||
|
||||
Keil-проект:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\AD_Keil_Project\MDK-ARM\IHM08M.uvprojx
|
||||
```
|
||||
|
||||
Распиновка силовой части приведена к `X-NUCLEO-IHM08M1`. ADC-каналы и PWM-линии не выбраны случайно: они сверены с IHM08M1.
|
||||
|
||||
## Распиновка IHM08M1
|
||||
|
||||
Разъёмы указаны для платы `NUCLEO-G474RE`: ST morpho `CN7/CN10`, Arduino `CN5/CN8/CN9` и ST-LINK VCP. Для `PC1` и `PC0` на ST morpho в документации ST есть альтернативы через solder bridges, поэтому их нужно проверить на конкретной плате.
|
||||
|
||||
| Пин STM32 | Функция | Сигнал IHM08M1 | Разъём NUCLEO | Пин разъёма | Использование в проекте |
|
||||
|---|---|---|---|---:|---|
|
||||
| `PA0` | `ADC1_IN1` | `PhA` | `CN8` / `CN7` | `1` / `28` | ток фазы A |
|
||||
| `PC1` | `ADC1_IN7` | `PhB` | `CN8` / `CN7` | `5` / `36` | ток фазы B; на `CN7-36` проверить вариант `PC1/PB9` |
|
||||
| `PC0` | `ADC1_IN6` | `PhC` | `CN8` / `CN7` | `6` / `38` | ток фазы C; на `CN7-38` проверить вариант `PC0/PA15` |
|
||||
| `PA1` | `ADC1_IN2` | `BUSV` | `CN8` / `CN7` | `2` / `30` | напряжение DC-звена |
|
||||
| `PC2` | `ADC1_IN8` | `Temp. Sens.` | `CN7` | `35` | пин учтён, чтение температуры ещё не подключено |
|
||||
| `PA8` | `TIM1_CH1` | `UH` | `CN9` / `CN10` | `8` / `23` | верхний ключ U |
|
||||
| `PA7` | `TIM1_CH1N` | `UL` | `CN5` / `CN10` | `4` / `15` | нижний ключ U |
|
||||
| `PA9` | `TIM1_CH2` | `VH` | `CN5` / `CN10` | `1` / `21` | верхний ключ V |
|
||||
| `PB0` | `TIM1_CH2N` | `VL` | `CN8` / `CN7` | `4` / `34` | нижний ключ V |
|
||||
| `PA10` | `TIM1_CH3` | `WH` | `CN9` / `CN10` | `3` / `33` | верхний ключ W |
|
||||
| `PB1` | `TIM1_CH3N` | `WL` | `CN10` | `24` | нижний ключ W |
|
||||
| `PA6` | `TIM1_BKIN` | `BKIN` | `CN5` / `CN10` | `5` / `13` | аппаратное аварийное отключение TIM1 |
|
||||
| `PA2` | `USART2_TX` | ST-LINK VCP TX | `CN10` | `35` | Modbus RTU; также ST-LINK VCP при нужных solder bridges |
|
||||
| `PA3` | `USART2_RX` | ST-LINK VCP RX | `CN10` | `37` | Modbus RTU; также ST-LINK VCP при нужных solder bridges |
|
||||
| `PC13` | GPIO/EXTI | `START/STOP` | `CN7` | `23` | кнопка `B1`, переключает логирование |
|
||||
| `PA5` | не используется | `PA5 - DAC` | `CN5` / `CN10` | `6` / `11` | конфликт с `LD2` убран |
|
||||
| `PB3` | GPIO input | `Enc. B/H2` | `CN9` / `CN10` | `4` / `31` | SWO убран из `.ioc` |
|
||||
|
||||
Подробная сверка всех пинов находится в `AD_docs/PIN_USAGE_IHM08M1_COMPARE.md`.
|
||||
|
||||
## Измеряемые параметры
|
||||
|
||||
`AD_Board_ReadMeasurements()` читает ADC и заполняет `AD_Measurements_t`.
|
||||
|
||||
| Величина | Поле | Источник | Примечание |
|
||||
|---|---|---|---|
|
||||
| ток фазы A | `ia_A` | `PA0 / ADC1_IN1` | масштаб тока пока задаётся макросами |
|
||||
| ток фазы B | `ib_A` | `PC1 / ADC1_IN7` | масштаб тока пока задаётся макросами |
|
||||
| ток фазы C | `ic_A` | `PC0 / ADC1_IN6` | масштаб тока пока задаётся макросами |
|
||||
| DC-звено | `vdc_V` | `PA1 / ADC1_IN2` | учтено измерение `10.0 В -> 0.618 В` на ADC |
|
||||
| время | `timestamp_us` | `HAL_GetTick() * 1000` | шаг 1 мс в текущей реализации |
|
||||
|
||||
DC-звено усредняется по `AD_BOARD_ADC_VDC_AVG_SAMPLES=16` выборкам и фильтруется IIR-фильтром `AD_BOARD_ADC_VDC_FILTER_ALPHA=0.125`. Коэффициент делителя:
|
||||
|
||||
```text
|
||||
AD_BOARD_ADC_VDC_BUS_V_PER_ADC_V = 12.1770
|
||||
AD_BOARD_ADC_VDC_LOW_CAL_ADC_V = 0.618
|
||||
AD_BOARD_ADC_VDC_LOW_CAL_BUS_V = 10.0
|
||||
AD_BOARD_ADC_VDC_HIGH_CAL_BUS_V = 14.5
|
||||
```
|
||||
|
||||
## Команда теста
|
||||
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
uint8_t enable;
|
||||
uint8_t test_mode;
|
||||
uint8_t reset_faults;
|
||||
uint16_t pwm_polarity_flags;
|
||||
uint16_t pwm_timing_mode;
|
||||
uint16_t motor_control_type;
|
||||
uint16_t rotation_ramp_time_ms;
|
||||
float pwm_duty_limit;
|
||||
float rotation_frequency_Hz;
|
||||
float rotation_modulation;
|
||||
float current_limit_A;
|
||||
float voltage_limit_V;
|
||||
float undervoltage_limit_V;
|
||||
float speed_limit_rpm;
|
||||
float temperature_limit_C;
|
||||
} AD_Command_t;
|
||||
```
|
||||
|
||||
| Поле | Назначение |
|
||||
|---|---|
|
||||
| `enable` | `1` включает режим, `0` выключает |
|
||||
| `test_mode` | один из `AD_PARAM_ID_MODE_*` |
|
||||
| `reset_faults` | сброс защёлкнутых аварий |
|
||||
| `pwm_polarity_flags` | bit0 инвертирует `UH/VH/WH`, bit1 инвертирует `UL/VL/WL` |
|
||||
| `pwm_timing_mode` | `0` = up-counting PWM, `1` = center-aligned PWM |
|
||||
| `motor_control_type` | `0` = AD/sine, `1` = BLDC/6-step |
|
||||
| `rotation_ramp_time_ms` | время выхода `rotation_frequency_Hz`/`rotation_modulation` на уставку, по умолчанию `3000 ms` |
|
||||
| `pwm_duty_limit` | лимит duty для PWM-тестов и измерительных импульсов |
|
||||
| `rotation_frequency_Hz` | частота режима `AD_PARAM_ID_MODE_ROTATION_3HZ`, по умолчанию `3.0 Hz` |
|
||||
| `rotation_modulation` | коэффициент модуляции режима `AD_PARAM_ID_MODE_ROTATION_3HZ`, по умолчанию `0.35` |
|
||||
| `current_limit_A` | программный предел тока |
|
||||
| `voltage_limit_V` | предел перенапряжения DC-звена |
|
||||
| `undervoltage_limit_V` | предел недонапряжения, `0` отключает проверку |
|
||||
| `speed_limit_rpm` | предел скорости |
|
||||
| `temperature_limit_C` | предел температуры |
|
||||
|
||||
## Режимы
|
||||
|
||||
| Режим | Код | Назначение |
|
||||
|---|---:|---|
|
||||
| `AD_PARAM_ID_MODE_IDLE` | 0 | выключено |
|
||||
| `AD_PARAM_ID_MODE_STATOR_RESISTANCE` | 1 | измерение `Rs_ohm` |
|
||||
| `AD_PARAM_ID_MODE_NO_LOAD_MAGNETIZING` | 2 | измерение `Lm_H` |
|
||||
| `AD_PARAM_ID_MODE_LOCKED_ROTOR_LEAKAGE` | 3 | измерение `Ll_H` и `Rr_ohm` |
|
||||
| `AD_PARAM_ID_MODE_INERTIA_FRICTION` | 4 | измерение `J/B` при наличии `speed_rpm` |
|
||||
| `AD_PARAM_ID_MODE_DATA_LOGGING` | 5 | только сбор данных |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_UH` | 6 | PWM на `PA8 / UH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_UL` | 7 | PWM на `PA7 / UL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_VH` | 8 | PWM на `PA9 / VH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_VL` | 9 | PWM на `PB0 / VL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_WH` | 10 | PWM на `PA10 / WH` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_WL` | 11 | PWM на `PB1 / WL` |
|
||||
| `AD_PARAM_ID_MODE_PWM_TEST_ALL` | 12 | все три плеча, duty фаз `0.5` |
|
||||
| `AD_PARAM_ID_MODE_AUTO_IDENTIFICATION` | 13 | `Rs`, `Ll`, `Rr`, `Lm`, затем `J/B` |
|
||||
| `AD_PARAM_ID_MODE_ROTATION_3HZ` | 14 | 6-step вращение с настраиваемой частотой и модуляцией |
|
||||
|
||||
## Управление из кода
|
||||
|
||||
```c
|
||||
AD_Board_StartDataLogging();
|
||||
AD_Board_StartParamTest(AD_PARAM_ID_MODE_STATOR_RESISTANCE);
|
||||
AD_Board_StartParamTestWithDuty(AD_PARAM_ID_MODE_PWM_TEST_UH, 0.08f);
|
||||
AD_Board_StartParamTestWithDuty(AD_PARAM_ID_MODE_AUTO_IDENTIFICATION, 0.08f);
|
||||
AD_Board_StartParamTestWithDuty(AD_PARAM_ID_MODE_ROTATION_3HZ, 0.35f);
|
||||
AD_Board_StopParamTest();
|
||||
```
|
||||
|
||||
## Условия для реального PWM
|
||||
|
||||
Нужны все условия:
|
||||
|
||||
- сборка с `AD_PROJECT_POWER_TEST_ENABLE=1` или с двумя макросами `AD_PARAM_ID_ENABLE_POWER_TESTS=1` и `AD_INVERTER_ENABLE_OUTPUTS=1`;
|
||||
- `AD_Command_t.enable = 1`;
|
||||
- `current_limit_A > 0`;
|
||||
- `voltage_limit_V > 0`;
|
||||
- нет защёлкнутой аварии;
|
||||
- `BKIN` не активен;
|
||||
- для режима `AD_PARAM_ID_MODE_LOCKED_ROTOR_LEAKAGE` вызван `AD_ParamID_SetLockedRotorAllowed(1)`.
|
||||
|
||||
Если любое условие не выполнено, проект выключает TIM1 и уходит в `DATA_LOGGING`.
|
||||
75
AD_Keil_Project/AD_docs/PIN_USAGE_IHM08M1_COMPARE.md
Normal file
75
AD_Keil_Project/AD_docs/PIN_USAGE_IHM08M1_COMPARE.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Сравнение использованных пинов с X-NUCLEO-IHM08M1
|
||||
|
||||
## Источник
|
||||
|
||||
Основной источник для сверки: официальная схема ST `x-nucleo-ihm08m1_schematic.pdf`.
|
||||
|
||||
```text
|
||||
https://www.st.com/resource/en/schematic_pack/x-nucleo-ihm08m1_schematic.pdf
|
||||
```
|
||||
|
||||
Сверка сделана по текущему проекту `AD_Keil_Project`, файлам:
|
||||
|
||||
- `Core/Inc/main.h`
|
||||
- `Core/Src/main.c`
|
||||
- `Core/Src/stm32g4xx_hal_msp.c`
|
||||
- `Core/Src/ad_board.c`
|
||||
- `Core/Src/ad_inverter.c`
|
||||
- `IHM08M.ioc`
|
||||
|
||||
## Итог коротко
|
||||
|
||||
Проект приведен к распиновке `X-NUCLEO-IHM08M1` для измерений и шести управляющих линий ключей.
|
||||
|
||||
- ADC токов и DC-звена совпадает со схемой IHM08M1.
|
||||
- ШИМ ключей переведен на `TIM1`: `UH/UL`, `VH/VL`, `WH/WL`.
|
||||
- `PA5` больше не используется как `LD2` по умолчанию, чтобы не конфликтовать с линией `PA5 - DAC` на IHM08M1.
|
||||
- `PB3` в `.ioc` больше не `SWO`; он помечен как `ENC_B_H2`.
|
||||
- `PA6 / TIM1_BKIN` добавлен как аппаратный вход аварийного отключения.
|
||||
|
||||
Физические силовые выходы по-прежнему запрещены макросами `AD_INVERTER_ENABLE_OUTPUTS=0` и `AD_PARAM_ID_ENABLE_POWER_TESTS=0`, пока не проверены полярности, dead-time и аварийная цепь на железе.
|
||||
|
||||
## Таблица всех использованных пинов
|
||||
|
||||
| Пин | Где используется в проекте | Текущий режим проекта | Назначение по IHM08M1 | Статус |
|
||||
|---|---|---|---|---|
|
||||
| `PA0` | `ad_board.c`, `.ioc` | `ADC1_IN1` | `PhA`, ток фазы A | Совпадает |
|
||||
| `PC1` | `ad_board.c`, `.ioc` | `ADC1_IN7` | `PhB`, ток фазы B | Совпадает |
|
||||
| `PC0` | `ad_board.c`, `.ioc` | `ADC1_IN6` | `PhC`, ток фазы C | Совпадает |
|
||||
| `PA1` | `ad_board.c`, `.ioc` | `ADC1_IN2` | `BUSV`, напряжение DC-звена | Совпадает, кусочная калибровка: `0.618 В ADC -> 10 В`, выше `14.5 В` масштаб `12.1770 В/В` |
|
||||
| `PC2` | `.ioc`, документация | `ADC1_IN8` | `Temp. Sens.` | Пин задан, чтение температуры еще не реализовано |
|
||||
| `PA8` | `stm32g4xx_hal_msp.c`, `ad_inverter.c`, `.ioc` | `TIM1_CH1` | `UH`, верхний ключ фазы U | Совпадает |
|
||||
| `PA7` | `stm32g4xx_hal_msp.c`, `ad_inverter.c`, `.ioc` | `TIM1_CH1N` | `UL`, нижний ключ фазы U | Совпадает |
|
||||
| `PA9` | `stm32g4xx_hal_msp.c`, `ad_inverter.c`, `.ioc` | `TIM1_CH2` | `VH`, верхний ключ фазы V | Совпадает |
|
||||
| `PB0` | `stm32g4xx_hal_msp.c`, `ad_inverter.c`, `.ioc` | `TIM1_CH2N` | `VL`, нижний ключ фазы V | Совпадает |
|
||||
| `PA10` | `stm32g4xx_hal_msp.c`, `ad_inverter.c`, `.ioc` | `TIM1_CH3` | `WH`, верхний ключ фазы W | Совпадает |
|
||||
| `PB1` | `stm32g4xx_hal_msp.c`, `ad_inverter.c`, `.ioc` | `TIM1_CH3N` | `WL`, нижний ключ фазы W | Совпадает |
|
||||
| `PA6` | `stm32g4xx_hal_msp.c`, `.ioc` | `TIM1_BKIN` | `BKIN`, аппаратная защита | Добавлено, полярность проверить на железе |
|
||||
| `PC13` | `main.c`, `ad_board.c`, `stm32g4xx_it.c`, `.ioc` | `EXTI`, кнопка `B1` | `START/STOP (B1 BUTTON)` | Совпадает |
|
||||
| `PA5` | не инициализируется в `main.c`; LED отключен макросом | не используется по умолчанию | `PA5/PB13`, `PA5 - DAC` | Конфликт с LED убран |
|
||||
| `PB3` | `.ioc` | `GPIO_Input`, метка `ENC_B_H2` | `Enc. B/H2` | Конфликт с SWO убран в `.ioc` |
|
||||
| `PA13` | `main.h`, `.ioc` | `SWDIO` | не силовой сигнал IHM08M1 | Оставлено для отладки |
|
||||
| `PA14` | `main.h`, `.ioc` | `SWCLK` | не силовой сигнал IHM08M1 | Оставлено для отладки |
|
||||
| `PC14` | `main.h`, `.ioc` | `RCC_OSC32_IN` | не назначен как сигнал IHM08M1 | Не относится к шилду |
|
||||
| `PC15` | `main.h`, `.ioc` | `RCC_OSC32_OUT` | не назначен как сигнал IHM08M1 | Не относится к шилду |
|
||||
| `PF0` | `main.h`, `.ioc` | `RCC_OSC_IN` | не назначен как сигнал IHM08M1 | Не относится к шилду |
|
||||
| `PF1` | `main.h`, `.ioc` | `RCC_OSC_OUT` | не назначен как сигнал IHM08M1 | Не относится к шилду |
|
||||
|
||||
## Что сейчас безопасно
|
||||
|
||||
- ADC-измерения `PA0`, `PC1`, `PC0`, `PA1` можно смотреть в `g_ad_debug.adc`.
|
||||
- Для `PA1/BUSV` значение `vdc_adc_V = 0.618 В` пересчитывается примерно в `vdc_V = 10.0 В`.
|
||||
- `PC13/B1` можно использовать для включения и выключения `DATA_LOGGING`.
|
||||
- Силовые выходы физически не разрешены по умолчанию, потому что `AD_INVERTER_ENABLE_OUTPUTS=0` и `AD_PARAM_ID_ENABLE_POWER_TESTS=0`.
|
||||
|
||||
## Что еще проверить на железе
|
||||
|
||||
- Полярность верхних и нижних входов драйверов `UH/UL`, `VH/VL`, `WH/WL`.
|
||||
- Dead-time: сейчас задано `AD_TIM1_DEADTIME_TICKS=100`.
|
||||
- Полярность `BKIN`: сейчас `TIM_BREAKPOLARITY_HIGH`.
|
||||
- Нужно ли использовать `PA5 - DAC` для задания порога защиты.
|
||||
- Нужны ли `PA15/Enc. A/H1`, `PB3/Enc. B/H2`, `PB10/Enc. Z/H3` для скорости.
|
||||
|
||||
## Вывод
|
||||
|
||||
Распиновка проекта теперь соответствует IHM08M1 для измерений, шести ключей, кнопки и `BKIN`. Остались проверки физических полярностей и параметров защиты перед включением силовых макросов.
|
||||
122
AD_Keil_Project/AD_docs/PROJECT_INIT_SEQUENCE.md
Normal file
122
AD_Keil_Project/AD_docs/PROJECT_INIT_SEQUENCE.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# Последовательность инициализации проекта
|
||||
|
||||
Основная точка входа находится в:
|
||||
|
||||
```text
|
||||
AD_Keil_Project/Core/Src/main.c
|
||||
```
|
||||
|
||||
После сброса выполняется такая последовательность:
|
||||
|
||||
```c
|
||||
HAL_Init();
|
||||
SystemClock_Config();
|
||||
MX_GPIO_Init();
|
||||
MX_TIM1_Init();
|
||||
AD_Project_Init();
|
||||
```
|
||||
|
||||
В основном цикле выполняется:
|
||||
|
||||
```c
|
||||
AD_Project_Loop();
|
||||
```
|
||||
|
||||
## Что инициализируется
|
||||
|
||||
| Шаг | Функция | Что делает |
|
||||
|---|---|---|
|
||||
| 1 | `HAL_Init()` | Сбрасывает периферию HAL, запускает SysTick и базовое состояние HAL |
|
||||
| 2 | `SystemClock_Config()` | Настраивает тактирование STM32G4 на 170 МГц от HSI/PLL |
|
||||
| 3 | `MX_GPIO_Init()` | Включает тактирование GPIO, настраивает кнопку `B1` и прерывание `EXTI15_10`; `PA5/LD2` не используется по умолчанию |
|
||||
| 4 | `MX_TIM1_Init()` | Настраивает `TIM1` для шести PWM-линий IHM08M1 `UH/UL`, `VH/VL`, `WH/WL`, dead-time и `PA6/TIM1_BKIN`; PWM не запускается автоматически |
|
||||
| 5 | `AD_Project_Init()` | Общий старт прикладного слоя проекта |
|
||||
|
||||
## Что делает `AD_Project_Init()`
|
||||
|
||||
`AD_Project_Init()` находится в:
|
||||
|
||||
```text
|
||||
AD_Keil_Project/Core/Src/ad_project.c
|
||||
```
|
||||
|
||||
Внутри вызывается `AD_Board_Init()`, а она поднимает прикладные подсистемы:
|
||||
|
||||
| Подсистема | Функция | Состояние после запуска |
|
||||
|---|---|---|
|
||||
| Плата | `AD_Board_Init()` | Сбрасывает флаги кнопки, режим логирования и индикацию |
|
||||
| ADC измерений | внутренний `board_adc_init()` | Настраивает `PA0`, `PA1`, `PC0`, `PC1` как аналоговые входы по схеме IHM08M1 и запускает `ADC1` |
|
||||
| Ключи инвертора | `AD_Inverter_Init()` | Ставит duty в ноль, останавливает PWM, помечает слой как инициализированный |
|
||||
| Интерфейс модели | `SimulinkInterface_Init()` | Сбрасывает входные и выходные шины, телеметрию и команду |
|
||||
| Идентификация | `AD_ParamID_Init()` | Сбрасывает параметры, измерения, защиты, режимы и ошибки |
|
||||
| Команда по умолчанию | внутренний вызов `board_apply_command(0, AD_PARAM_ID_MODE_IDLE)` | Проект стартует в выключенном режиме |
|
||||
|
||||
## Инициализация ключей
|
||||
|
||||
Слой ключей находится в:
|
||||
|
||||
```text
|
||||
AD_Keil_Project/Core/Inc/ad_inverter.h
|
||||
AD_Keil_Project/Core/Src/ad_inverter.c
|
||||
```
|
||||
|
||||
Доступные функции:
|
||||
|
||||
| Функция | Назначение |
|
||||
|---|---|
|
||||
| `AD_Inverter_Init()` | Инициализирует программное состояние инвертора и гарантированно выключает PWM |
|
||||
| `AD_Inverter_Disable()` | Ставит duty в ноль и останавливает основной и комплементарный PWM на подтвержденном канале |
|
||||
| `AD_Inverter_SetDuty()` | Записывает duty A/B/C в состояние; сейчас в регистр TIM1 попадает только подтвержденный канал A |
|
||||
| `AD_Inverter_Enable()` | Пытается запустить PWM, но только если разрешены все программные защиты |
|
||||
| `AD_Inverter_ApplyCommand()` | Применяет команду включения и duty |
|
||||
| `AD_Inverter_GetState()` | Возвращает состояние слоя инвертора для отладки |
|
||||
|
||||
Сейчас для IHM08M1 заведены:
|
||||
|
||||
```text
|
||||
PA8 / TIM1_CH1 -> UH
|
||||
PA7 / TIM1_CH1N -> UL
|
||||
PA9 / TIM1_CH2 -> VH
|
||||
PB0 / TIM1_CH2N -> VL
|
||||
PA10 / TIM1_CH3 -> WH
|
||||
PB1 / TIM1_CH3N -> WL
|
||||
PA6 / TIM1_BKIN -> BKIN
|
||||
```
|
||||
|
||||
Полный трехфазный драйвер требует аппаратной проверки полярностей, dead-time, `BKIN` и каналов измерения перед разрешением силовых макросов.
|
||||
|
||||
## Защитные условия включения PWM
|
||||
|
||||
В стандартной сборке ключи не включатся, даже если вызвать `AD_Inverter_Enable()`.
|
||||
|
||||
Нужно одновременно выполнить условия:
|
||||
|
||||
- в настройках компиляции задан `AD_PARAM_ID_ENABLE_POWER_TESTS=1`;
|
||||
- в настройках компиляции задан `AD_INVERTER_ENABLE_OUTPUTS=1`;
|
||||
- нет защелкнутой аварии;
|
||||
- заданы пределы тока и напряжения;
|
||||
- текущий режим действительно требует силового теста;
|
||||
- для режима locked-rotor отдельно вызван `AD_ParamID_SetLockedRotorAllowed(1)`;
|
||||
- подтверждена аппаратная распиновка и проверены защиты.
|
||||
|
||||
Если хотя бы одно условие не выполнено, `AD_Inverter_Enable()` выключает PWM и возвращает `0`.
|
||||
|
||||
## Состояние проекта для отладки
|
||||
|
||||
Для отладки добавлен:
|
||||
|
||||
```c
|
||||
const AD_ProjectState_t* AD_Project_GetState(void);
|
||||
```
|
||||
|
||||
Структура показывает:
|
||||
|
||||
| Поле | Смысл |
|
||||
|---|---|
|
||||
| `initialized` | Общий прикладной слой запущен |
|
||||
| `board_initialized` | Инициализация платы выполнена |
|
||||
| `inverter_initialized` | Слой инвертора прошел init |
|
||||
| `simulink_initialized` | Интерфейс модели прошел init |
|
||||
| `outputs_allowed_by_build` | Макрос `AD_INVERTER_ENABLE_OUTPUTS` разрешает физические выходы |
|
||||
| `param_id_status` | Текущий статус идентификации |
|
||||
| `param_id_faults` | Текущие ошибки идентификации |
|
||||
128
AD_Keil_Project/AD_docs/SIMULINK_INTEGRATION.md
Normal file
128
AD_Keil_Project/AD_docs/SIMULINK_INTEGRATION.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Интеграция с Simulink
|
||||
|
||||
## Где модель
|
||||
|
||||
Основная модель:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl\inu_im_1wnd_3lvl.slx
|
||||
```
|
||||
|
||||
Версия для R2021b:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl\inu_im_1wnd_3lvl_r2021b.slx
|
||||
```
|
||||
|
||||
Инструкция запуска модели находится в:
|
||||
|
||||
```text
|
||||
AD_Keil_Project\AD_docs\SIMULINK_MODEL_RUN_HELP.md
|
||||
```
|
||||
|
||||
## Что найдено
|
||||
|
||||
| Артефакт | Статус |
|
||||
|---|---|
|
||||
| `Inu_im_1wnd_3lvl/inu_im_1wnd_3lvl.slx` | найден |
|
||||
| `Inu_im_1wnd_3lvl/inu_im_1wnd_3lvl_r2021b.slx` | найден |
|
||||
| `Inu_im_1wnd_3lvl/Inu/wrapper_inu.c` | найден |
|
||||
| `Inu_im_1wnd_3lvl/Inu/controller.c` | найден |
|
||||
| сгенерированный ERT-код `model.c/.h` | не найден |
|
||||
|
||||
Сейчас Keil-проект не является прямой автогенерацией из Simulink. В нём сделан C-интерфейс, через который можно связать модель, хост или ручной код с измерениями и командами.
|
||||
|
||||
## C-интерфейс
|
||||
|
||||
Файлы:
|
||||
|
||||
- `Core/Inc/simulink_interface.h`;
|
||||
- `Core/Src/simulink_interface.c`;
|
||||
- `Core/Inc/ad_parameter_identification.h`;
|
||||
- `Core/Src/ad_parameter_identification.c`.
|
||||
|
||||
Основные функции:
|
||||
|
||||
```c
|
||||
void SimulinkInterface_Init(void);
|
||||
void SimulinkInterface_SetMeasurements(const AD_Measurements_t *meas);
|
||||
void SimulinkInterface_SetCommand(const AD_Command_t *command);
|
||||
void SimulinkInterface_StepFast(void);
|
||||
void SimulinkInterface_StepSlow(void);
|
||||
void SimulinkInterface_PackTelemetry(void);
|
||||
```
|
||||
|
||||
## Команда от модели к MCU
|
||||
|
||||
Использовать `SimulinkInterface_OutputBus_t.command`:
|
||||
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
uint8_t enable;
|
||||
uint8_t test_mode;
|
||||
uint8_t reset_faults;
|
||||
uint16_t pwm_polarity_flags;
|
||||
uint16_t pwm_timing_mode;
|
||||
uint16_t motor_control_type;
|
||||
uint16_t rotation_ramp_time_ms;
|
||||
float pwm_duty_limit;
|
||||
float rotation_frequency_Hz;
|
||||
float rotation_modulation;
|
||||
float current_limit_A;
|
||||
float voltage_limit_V;
|
||||
float undervoltage_limit_V;
|
||||
float speed_limit_rpm;
|
||||
float temperature_limit_C;
|
||||
} AD_Command_t;
|
||||
```
|
||||
|
||||
Минимальные условия для силового режима:
|
||||
|
||||
- `enable = 1`;
|
||||
- `test_mode` равен одному из режимов `1`, `3`, `6..14`;
|
||||
- `current_limit_A > 0`;
|
||||
- `voltage_limit_V > 0`;
|
||||
- сборка с `AD_PROJECT_POWER_TEST_ENABLE=1`;
|
||||
- нет активной аварии.
|
||||
|
||||
## Режимы для модели
|
||||
|
||||
| Код | Режим |
|
||||
|---:|---|
|
||||
| 0 | `AD_PARAM_ID_MODE_IDLE` |
|
||||
| 1 | `AD_PARAM_ID_MODE_STATOR_RESISTANCE` |
|
||||
| 2 | `AD_PARAM_ID_MODE_NO_LOAD_MAGNETIZING` |
|
||||
| 3 | `AD_PARAM_ID_MODE_LOCKED_ROTOR_LEAKAGE` |
|
||||
| 4 | `AD_PARAM_ID_MODE_INERTIA_FRICTION` |
|
||||
| 5 | `AD_PARAM_ID_MODE_DATA_LOGGING` |
|
||||
| 6 | `AD_PARAM_ID_MODE_PWM_TEST_UH` |
|
||||
| 7 | `AD_PARAM_ID_MODE_PWM_TEST_UL` |
|
||||
| 8 | `AD_PARAM_ID_MODE_PWM_TEST_VH` |
|
||||
| 9 | `AD_PARAM_ID_MODE_PWM_TEST_VL` |
|
||||
| 10 | `AD_PARAM_ID_MODE_PWM_TEST_WH` |
|
||||
| 11 | `AD_PARAM_ID_MODE_PWM_TEST_WL` |
|
||||
| 12 | `AD_PARAM_ID_MODE_PWM_TEST_ALL` |
|
||||
| 13 | `AD_PARAM_ID_MODE_AUTO_IDENTIFICATION` |
|
||||
| 14 | `AD_PARAM_ID_MODE_ROTATION_3HZ` |
|
||||
|
||||
## Данные от MCU к модели
|
||||
|
||||
Использовать `SimulinkInterface_InputBus_t`:
|
||||
|
||||
- `measurements` - токи, DC-звено, скорость, температура, время;
|
||||
- `motor_parameters` - оценённые параметры двигателя;
|
||||
- `param_id_status` - флаги состояния;
|
||||
- `param_id_faults` - флаги ошибок;
|
||||
- `param_id_mode` - фактический режим.
|
||||
|
||||
Результаты измерений считаются действительными только по `motor_parameters.valid_mask`.
|
||||
|
||||
## Частоты вызова
|
||||
|
||||
В текущем Keil-проекте:
|
||||
|
||||
- `SimulinkInterface_StepFast()` вызывается на каждой итерации `AD_Project_Loop()`;
|
||||
- `SimulinkInterface_StepSlow()` вызывается раз в 10 мс.
|
||||
|
||||
Для настоящего привода быстрый шаг лучше переносить в прерывание ADC/PWM, но текущая реализация уже позволяет проверить каналы, телеметрию и начальные измерительные импульсы.
|
||||
144
AD_Keil_Project/AD_docs/SIMULINK_MODEL_RUN_HELP.md
Normal file
144
AD_Keil_Project/AD_docs/SIMULINK_MODEL_RUN_HELP.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# Помощь по запуску Simulink-модели
|
||||
|
||||
## Где находится модель
|
||||
|
||||
Simulink-модель находится не в каталоге Keil-проекта, а в исходной папке рабочей области:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl
|
||||
```
|
||||
|
||||
Полный путь к основной модели:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl\inu_im_1wnd_3lvl.slx
|
||||
```
|
||||
|
||||
Относительный путь от рабочей папки `AD`:
|
||||
|
||||
```text
|
||||
Inu_im_1wnd_3lvl/inu_im_1wnd_3lvl.slx
|
||||
```
|
||||
|
||||
Основные файлы:
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `inu_im_1wnd_3lvl.slx` | основная Simulink-модель |
|
||||
| `inu_im_1wnd_3lvl_r2021b.slx` | версия модели для MATLAB/Simulink R2021b |
|
||||
| `init.m` | задание параметров модели |
|
||||
| `wrapper_inu.mexw64` | скомпилированная S-function для Windows 64-bit |
|
||||
| `allmex.m` | скрипт пересборки S-function |
|
||||
| `Inu/*.c`, `Inu/*.h` | исходники S-function и C2000-логики |
|
||||
|
||||
Короткое описание из `ReadMe.txt`: один трёхуровневый инвертор питает однообмоточный асинхронный двигатель.
|
||||
|
||||
## Быстрый запуск
|
||||
|
||||
В MATLAB выполнить:
|
||||
|
||||
```matlab
|
||||
cd('F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl')
|
||||
run('init.m')
|
||||
open_system('inu_im_1wnd_3lvl_r2021b.slx')
|
||||
```
|
||||
|
||||
Если используется более новая версия MATLAB/Simulink, можно открыть:
|
||||
|
||||
```matlab
|
||||
open_system('inu_im_1wnd_3lvl.slx')
|
||||
```
|
||||
|
||||
После открытия модели запустить расчёт кнопкой запуска в Simulink или командой:
|
||||
|
||||
```matlab
|
||||
sim('inu_im_1wnd_3lvl_r2021b')
|
||||
```
|
||||
|
||||
## Что должно быть перед запуском
|
||||
|
||||
- Рабочая папка MATLAB должна быть `Inu_im_1wnd_3lvl`.
|
||||
- Нужно выполнить `init.m`, иначе в workspace не будет параметров двигателя, инвертора и шага моделирования.
|
||||
- В папке должен быть доступен `wrapper_inu.mexw64`.
|
||||
- Разрядность MATLAB должна быть 64-bit Windows, потому что готовый файл имеет расширение `.mexw64`.
|
||||
|
||||
## Если модель ругается на S-function
|
||||
|
||||
Проверьте наличие файла:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl\wrapper_inu.mexw64
|
||||
```
|
||||
|
||||
Если MATLAB сообщает, что S-function не найдена:
|
||||
|
||||
```matlab
|
||||
cd('F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl')
|
||||
which wrapper_inu
|
||||
```
|
||||
|
||||
Если `which` ничего не показывает, добавьте папку модели в путь:
|
||||
|
||||
```matlab
|
||||
addpath('F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl')
|
||||
```
|
||||
|
||||
## Пересборка S-function
|
||||
|
||||
Скрипт `allmex.m` есть, но сейчас он содержит старые абсолютные пути вида:
|
||||
|
||||
```text
|
||||
F:\Work\Projects\MATLAB\Drives_lib_new\...
|
||||
```
|
||||
|
||||
Поэтому пересборка через `allmex.m` без правки путей, скорее всего, не сработает. Для обычного запуска пересборка не нужна, потому что готовый `wrapper_inu.mexw64` уже лежит рядом с моделью.
|
||||
|
||||
Если понадобится пересобрать S-function, нужно:
|
||||
|
||||
1. Исправить include/source пути в `allmex.m` на актуальные.
|
||||
2. Убедиться, что в MATLAB настроен компилятор:
|
||||
|
||||
```matlab
|
||||
mex -setup C
|
||||
```
|
||||
|
||||
3. Запустить:
|
||||
|
||||
```matlab
|
||||
run('allmex.m')
|
||||
```
|
||||
|
||||
## Связь с Keil-проектом
|
||||
|
||||
Keil-проект находится здесь:
|
||||
|
||||
```text
|
||||
F:\set\workspace\setcorp\set506\AD\AD_Keil_Project\MDK-ARM\IHM08M.uvprojx
|
||||
```
|
||||
|
||||
Simulink-модель не является сгенерированным Keil-проектом. Сейчас это отдельная модель/симулятор, а Keil-проект содержит безопасный STM32-каркас и интерфейсные структуры:
|
||||
|
||||
- `AD_Measurements_t`;
|
||||
- `AD_MotorParameters_t`;
|
||||
- `AD_Command_t`;
|
||||
- `SimulinkInterface_InputBus_t`;
|
||||
- `SimulinkInterface_OutputBus_t`.
|
||||
|
||||
Для настоящей связки Simulink -> STM32 нужно либо генерировать код из модели, либо вручную связать модельные сигналы с этими структурами.
|
||||
|
||||
## Минимальная проверка модели
|
||||
|
||||
В MATLAB:
|
||||
|
||||
```matlab
|
||||
cd('F:\set\workspace\setcorp\set506\AD\Inu_im_1wnd_3lvl')
|
||||
run('init.m')
|
||||
exist('wrapper_inu', 'file')
|
||||
open_system('inu_im_1wnd_3lvl_r2021b.slx')
|
||||
```
|
||||
|
||||
Ожидаемо:
|
||||
|
||||
- `exist('wrapper_inu', 'file')` возвращает `3` для MEX-файла;
|
||||
- модель открывается без ошибки отсутствующей S-function;
|
||||
- параметры `Ts`, `Rs`, `Rr`, `Lls`, `Llr`, `Lm`, `UdcNom`, `Inom` появились в workspace.
|
||||
455
AD_Keil_Project/AD_docs/TELEMETRY_PROTOCOL.md
Normal file
455
AD_Keil_Project/AD_docs/TELEMETRY_PROTOCOL.md
Normal file
@@ -0,0 +1,455 @@
|
||||
# Протокол телеметрии
|
||||
|
||||
Документ описывает текущий бинарный пакет телеметрии из прошивки
|
||||
`AD_Keil_Project`.
|
||||
|
||||
Основные файлы реализации:
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `Core/Inc/simulink_interface.h` | Формат пакета, версия, размеры, API |
|
||||
| `Core/Src/simulink_interface.c` | Заполнение пакета и CRC16 |
|
||||
| `Core/Inc/ad_binary_transport.h` | Выбор протокола и транспорта |
|
||||
| `Core/Src/ad_binary_transport.c` | Отправка готового пакета |
|
||||
| `Core/Src/ad_usb_cdc.c` | USB FS CDC ACM транспорт |
|
||||
| `Core/Src/ad_can_telemetry.c` | FDCAN1 classic CAN транспорт |
|
||||
| `Core/Src/ad_modbus.c` | Modbus-регистры включения бинарной телеметрии |
|
||||
|
||||
## Кратко
|
||||
|
||||
Прошивка формирует один бинарный пакет `SimulinkTelemetryPacket_t`.
|
||||
Пакет можно отдавать через USB CDC, через FDCAN1 classic CAN или одновременно
|
||||
через оба транспорта.
|
||||
|
||||
По умолчанию бинарный поток выключен:
|
||||
|
||||
```c
|
||||
AD_HOST_PROTOCOL_DEFAULT = 0
|
||||
AD_BINARY_TELEMETRY_TRANSPORT_DEFAULT = 0
|
||||
```
|
||||
|
||||
То есть после старта активен режим `0` - Modbus-контроль без бинарной
|
||||
телеметрии. Чтобы включить поток, нужно через Modbus записать:
|
||||
|
||||
```text
|
||||
0x001D / 29 = транспорт
|
||||
0x001C / 28 = 1
|
||||
```
|
||||
|
||||
Где транспорт:
|
||||
|
||||
| Значение | Транспорт |
|
||||
|---:|---|
|
||||
| `0` | USB CDC |
|
||||
| `1` | CAN/FDCAN1 |
|
||||
| `2` | USB CDC и CAN/FDCAN1 одновременно |
|
||||
|
||||
Чтобы выключить бинарный поток:
|
||||
|
||||
```text
|
||||
0x001C / 28 = 0
|
||||
```
|
||||
|
||||
## Частота
|
||||
|
||||
Пакет обновляется в `SimulinkInterface_StepSlow()`, который вызывается из
|
||||
`AD_Board_Loop()` раз в `AD_BOARD_SLOW_PERIOD_MS = 10` мс.
|
||||
|
||||
Отправка из `AD_BinaryTransport_Loop()` также ограничена периодом:
|
||||
|
||||
```c
|
||||
AD_BINARY_TELEMETRY_PERIOD_MS = 10
|
||||
```
|
||||
|
||||
Итого штатная частота телеметрии - около `100 Гц`, если главный цикл успевает
|
||||
обслуживать транспорт.
|
||||
|
||||
## Кодирование данных
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Порядок байт | little-endian, как у STM32 Cortex-M |
|
||||
| `float` | IEEE-754 binary32, 4 байта |
|
||||
| Выравнивание | обычное C-выравнивание ARMCLANG, без `packed` |
|
||||
| Текущий размер заголовка | `16` байт |
|
||||
| Текущий размер payload | `136` байт |
|
||||
| Текущий размер полного пакета | `152` байта |
|
||||
| Максимум, разрешенный кодом | `SIMULINK_TELEMETRY_MAX_BYTES = 256` |
|
||||
|
||||
Если структура в C будет изменена, PC-парсер должен проверять
|
||||
`header.version` и `header.payload_size`.
|
||||
|
||||
## Заголовок пакета
|
||||
|
||||
Тип: `SimulinkTelemetryHeader_t`.
|
||||
|
||||
Смещения указаны от начала пакета.
|
||||
|
||||
| Offset | Размер | Тип | Поле | Значение / описание |
|
||||
|---:|---:|---|---|---|
|
||||
| `0` | `4` | `uint32_t` | `magic` | `0x41444944` |
|
||||
| `4` | `2` | `uint16_t` | `version` | `3` |
|
||||
| `6` | `2` | `uint16_t` | `payload_size` | `136` для текущей версии |
|
||||
| `8` | `4` | `uint32_t` | `sequence` | Увеличивается при каждой упаковке |
|
||||
| `12` | `2` | `uint16_t` | `crc16` | CRC16-CCITT по payload |
|
||||
| `14` | `2` | `uint16_t` | `reserved` | `0` |
|
||||
|
||||
`magic` сравнивать как `uint32_t` little-endian. На проводе байты идут так:
|
||||
|
||||
```text
|
||||
44 49 44 41
|
||||
```
|
||||
|
||||
## CRC16
|
||||
|
||||
CRC считается только по payload, без заголовка.
|
||||
|
||||
Параметры:
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Алгоритм | CRC16-CCITT |
|
||||
| Начальное значение | `0xFFFF` |
|
||||
| Полином | `0x1021` |
|
||||
| Reflection | нет |
|
||||
| Final XOR | нет |
|
||||
|
||||
Проверка на стороне ПК:
|
||||
|
||||
```text
|
||||
crc16_ccitt(packet[16 : 16 + payload_size]) == header.crc16
|
||||
```
|
||||
|
||||
## Payload
|
||||
|
||||
Тип: `SimulinkTelemetryPayload_t`.
|
||||
|
||||
Смещения в таблице указаны от начала payload. Чтобы получить смещение от начала
|
||||
пакета, прибавь `16`.
|
||||
|
||||
### Измерения
|
||||
|
||||
Блок `measurements`, тип `AD_Measurements_t`, размер `64` байта.
|
||||
|
||||
| Payload offset | Тип | Поле | Единицы |
|
||||
|---:|---|---|---|
|
||||
| `0` | `float` | `measurements.ia_A` | A |
|
||||
| `4` | `float` | `measurements.ib_A` | A |
|
||||
| `8` | `float` | `measurements.ic_A` | A |
|
||||
| `12` | `float` | `measurements.ia_rms_A` | A RMS |
|
||||
| `16` | `float` | `measurements.ib_rms_A` | A RMS |
|
||||
| `20` | `float` | `measurements.ic_rms_A` | A RMS |
|
||||
| `24` | `float` | `measurements.vdc_V` | V |
|
||||
| `28` | `float` | `measurements.va_V` | V |
|
||||
| `32` | `float` | `measurements.vb_V` | V |
|
||||
| `36` | `float` | `measurements.vc_V` | V |
|
||||
| `40` | `float` | `measurements.speed_rpm` | rpm |
|
||||
| `44` | `float` | `measurements.torque_Nm` | N*m |
|
||||
| `48` | `float` | `measurements.temperature_C` | град C |
|
||||
| `52` | `uint32_t` | `measurements.timestamp_us` | us |
|
||||
| `56` | `uint32_t` | `measurements.status_flags` | `AD_MEAS_STATUS_*` |
|
||||
| `60` | `float` | `measurements.slip_percent` | % |
|
||||
|
||||
`measurements.status_flags`:
|
||||
|
||||
| Бит | Маска | Флаг |
|
||||
|---:|---:|---|
|
||||
| `0` | `0x00000001` | `AD_MEAS_STATUS_OVERCURRENT` |
|
||||
| `1` | `0x00000002` | `AD_MEAS_STATUS_OVERVOLTAGE` |
|
||||
| `2` | `0x00000004` | `AD_MEAS_STATUS_UNDERVOLTAGE` |
|
||||
| `3` | `0x00000008` | `AD_MEAS_STATUS_OVERTEMPERATURE` |
|
||||
| `4` | `0x00000010` | `AD_MEAS_STATUS_DRIVER_FAULT` |
|
||||
| `5` | `0x00000020` | `AD_MEAS_STATUS_EMERGENCY_STOP` |
|
||||
|
||||
### Параметры двигателя
|
||||
|
||||
Блок `motor_parameters`, тип `AD_MotorParameters_t`, размер `60` байт.
|
||||
|
||||
| Payload offset | Тип | Поле | Единицы |
|
||||
|---:|---|---|---|
|
||||
| `64` | `float` | `motor_parameters.Rs_ohm` | Ohm |
|
||||
| `68` | `float` | `motor_parameters.Rr_ohm` | Ohm |
|
||||
| `72` | `float` | `motor_parameters.Ls_H` | H |
|
||||
| `76` | `float` | `motor_parameters.Lr_H` | H |
|
||||
| `80` | `float` | `motor_parameters.Lm_H` | H |
|
||||
| `84` | `float` | `motor_parameters.Ll_H` | H |
|
||||
| `88` | `float` | `motor_parameters.J_kg_m2` | kg*m2 |
|
||||
| `92` | `float` | `motor_parameters.B_Nm_s` | N*m*s |
|
||||
| `96` | `float` | `motor_parameters.pole_pairs` | пары полюсов |
|
||||
| `100` | `float` | `motor_parameters.nominal_voltage_V` | V |
|
||||
| `104` | `float` | `motor_parameters.nominal_current_A` | A |
|
||||
| `108` | `float` | `motor_parameters.nominal_frequency_Hz` | Hz |
|
||||
| `112` | `float` | `motor_parameters.nominal_power_W` | W |
|
||||
| `116` | `float` | `motor_parameters.nominal_speed_rpm` | rpm |
|
||||
| `120` | `uint32_t` | `motor_parameters.valid_mask` | `AD_MOTOR_PARAM_VALID_*` |
|
||||
|
||||
`valid_mask`:
|
||||
|
||||
| Бит | Маска | Флаг | Поле |
|
||||
|---:|---:|---|---|
|
||||
| `0` | `0x00000001` | `AD_MOTOR_PARAM_VALID_RS` | `Rs_ohm` |
|
||||
| `1` | `0x00000002` | `AD_MOTOR_PARAM_VALID_RR` | `Rr_ohm` |
|
||||
| `2` | `0x00000004` | `AD_MOTOR_PARAM_VALID_LS` | `Ls_H` |
|
||||
| `3` | `0x00000008` | `AD_MOTOR_PARAM_VALID_LR` | `Lr_H` |
|
||||
| `4` | `0x00000010` | `AD_MOTOR_PARAM_VALID_LM` | `Lm_H` |
|
||||
| `5` | `0x00000020` | `AD_MOTOR_PARAM_VALID_LL` | `Ll_H` |
|
||||
| `6` | `0x00000040` | `AD_MOTOR_PARAM_VALID_J` | `J_kg_m2` |
|
||||
| `7` | `0x00000080` | `AD_MOTOR_PARAM_VALID_B` | `B_Nm_s` |
|
||||
| `8` | `0x00000100` | `AD_MOTOR_PARAM_VALID_NOMINALS` | nominal fields |
|
||||
|
||||
Перед использованием результата идентификации обязательно проверять
|
||||
соответствующий бит `valid_mask`.
|
||||
|
||||
### Статус идентификации и команда
|
||||
|
||||
| Payload offset | Тип | Поле | Описание |
|
||||
|---:|---|---|---|
|
||||
| `124` | `uint32_t` | `param_id_status` | `AD_PARAM_ID_STATUS_*` |
|
||||
| `128` | `uint32_t` | `param_id_faults` | `AD_PARAM_ID_FAULT_*` |
|
||||
| `132` | `uint8_t` | `param_id_mode` | Текущий режим `AD_PARAM_ID_MODE_*` |
|
||||
| `133` | `uint8_t` | `command_enable` | Последняя команда enable |
|
||||
| `134` | `uint8_t` | `command_test_mode` | Последняя команда test mode |
|
||||
| `135` | `uint8_t` | `reserved` | `0` |
|
||||
|
||||
`param_id_status`:
|
||||
|
||||
| Бит | Маска | Флаг |
|
||||
|---:|---:|---|
|
||||
| `0` | `0x00000001` | `AD_PARAM_ID_STATUS_ACTIVE` |
|
||||
| `1` | `0x00000002` | `AD_PARAM_ID_STATUS_POWER_TEST_BLOCKED` |
|
||||
| `2` | `0x00000004` | `AD_PARAM_ID_STATUS_POWER_STAGE_ARMED` |
|
||||
| `3` | `0x00000008` | `AD_PARAM_ID_STATUS_FAULT_LATCHED` |
|
||||
| `4` | `0x00000010` | `AD_PARAM_ID_STATUS_TIMEOUT` |
|
||||
| `5` | `0x00000020` | `AD_PARAM_ID_STATUS_LOCKED_ROTOR_BLOCKED` |
|
||||
| `6` | `0x00000040` | `AD_PARAM_ID_STATUS_SAFETY_LIMITS_UNKNOWN` |
|
||||
| `7` | `0x00000080` | `AD_PARAM_ID_STATUS_DATA_VALID` |
|
||||
| `8` | `0x00000100` | `AD_PARAM_ID_STATUS_COMPLETE` |
|
||||
| `9` | `0x00000200` | `AD_PARAM_ID_STATUS_PARTIAL_COMPLETE` |
|
||||
| `10` | `0x00000400` | `AD_PARAM_ID_STATUS_STEP_FAILED` |
|
||||
| `11` | `0x00000800` | `AD_PARAM_ID_STATUS_LOCKED_ROTOR_SKIPPED` |
|
||||
|
||||
`param_id_faults`:
|
||||
|
||||
| Бит | Маска | Флаг |
|
||||
|---:|---:|---|
|
||||
| `0` | `0x00000001` | `AD_PARAM_ID_FAULT_OVERCURRENT` |
|
||||
| `1` | `0x00000002` | `AD_PARAM_ID_FAULT_OVERVOLTAGE` |
|
||||
| `2` | `0x00000004` | `AD_PARAM_ID_FAULT_UNDERVOLTAGE` |
|
||||
| `3` | `0x00000008` | `AD_PARAM_ID_FAULT_OVERTEMPERATURE` |
|
||||
| `4` | `0x00000010` | `AD_PARAM_ID_FAULT_DRIVER` |
|
||||
| `5` | `0x00000020` | `AD_PARAM_ID_FAULT_EMERGENCY_STOP` |
|
||||
| `6` | `0x00000040` | `AD_PARAM_ID_FAULT_TIMEOUT` |
|
||||
| `7` | `0x00000080` | `AD_PARAM_ID_FAULT_NULL_INPUT` |
|
||||
|
||||
Режимы `param_id_mode` и `command_test_mode`:
|
||||
|
||||
| Значение | Режим |
|
||||
|---:|---|
|
||||
| `0` | `AD_PARAM_ID_MODE_IDLE` |
|
||||
| `1` | `AD_PARAM_ID_MODE_STATOR_RESISTANCE` |
|
||||
| `2` | `AD_PARAM_ID_MODE_NO_LOAD_MAGNETIZING` |
|
||||
| `3` | `AD_PARAM_ID_MODE_LOCKED_ROTOR_LEAKAGE` |
|
||||
| `4` | `AD_PARAM_ID_MODE_INERTIA_FRICTION` |
|
||||
| `5` | `AD_PARAM_ID_MODE_DATA_LOGGING` |
|
||||
| `6` | `AD_PARAM_ID_MODE_PWM_TEST_UH` |
|
||||
| `7` | `AD_PARAM_ID_MODE_PWM_TEST_UL` |
|
||||
| `8` | `AD_PARAM_ID_MODE_PWM_TEST_VH` |
|
||||
| `9` | `AD_PARAM_ID_MODE_PWM_TEST_VL` |
|
||||
| `10` | `AD_PARAM_ID_MODE_PWM_TEST_WH` |
|
||||
| `11` | `AD_PARAM_ID_MODE_PWM_TEST_WL` |
|
||||
| `12` | `AD_PARAM_ID_MODE_PWM_TEST_ALL` |
|
||||
| `13` | `AD_PARAM_ID_MODE_AUTO_IDENTIFICATION` |
|
||||
| `14` | `AD_PARAM_ID_MODE_ROTATION_3HZ` |
|
||||
|
||||
## USB CDC транспорт
|
||||
|
||||
USB реализован как CDC ACM устройство на USB FS:
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Линии | `PA11 USB_DM`, `PA12 USB_DP` |
|
||||
| Тактирование | `HSI48` |
|
||||
| VID/PID | `0x0483 / 0x5740` |
|
||||
| Product string | `AD Telemetry CDC` |
|
||||
| Data IN endpoint | `0x81`, bulk, 64 байта |
|
||||
| Data OUT endpoint | `0x01`, bulk, 64 байта |
|
||||
| CMD endpoint | `0x82`, interrupt, 8 байт |
|
||||
|
||||
Код вызывает `HAL_PCD_EP_Transmit()` на весь пакет сразу, но CDC на стороне ПК
|
||||
нужно считать потоком байт. Один `read()` на ПК не обязан совпадать с одним
|
||||
пакетом прошивки.
|
||||
|
||||
Рекомендуемый парсер:
|
||||
|
||||
1. Искать в потоке magic bytes `44 49 44 41`.
|
||||
2. Дочитать 16-байтный заголовок.
|
||||
3. Проверить `version == 3`.
|
||||
4. Проверить `payload_size == 136` или обработать совместимую новую версию.
|
||||
5. Дочитать `payload_size` байт.
|
||||
6. Проверить CRC16.
|
||||
7. Передать payload в декодер.
|
||||
|
||||
## CAN/FDCAN транспорт
|
||||
|
||||
CAN реализован через FDCAN1 в режиме classic CAN, кадры по 8 байт.
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Периферия | `FDCAN1` |
|
||||
| RX/TX | `PB8 / PB9` |
|
||||
| Frame format | Classic CAN |
|
||||
| Bit rate switch | Off |
|
||||
| Default base standard ID | `0x5A0` |
|
||||
| Payload одного CAN-кадра | до 8 байт |
|
||||
|
||||
Базовый ID задается:
|
||||
|
||||
```c
|
||||
AD_CAN_TELEMETRY_STD_ID_BASE = 0x5A0
|
||||
```
|
||||
|
||||
Полный бинарный пакет режется последовательно:
|
||||
|
||||
| CAN ID | Данные |
|
||||
|---:|---|
|
||||
| `0x5A0` | bytes `0..7` |
|
||||
| `0x5A1` | bytes `8..15` |
|
||||
| `0x5A2` | bytes `16..23` |
|
||||
| `...` | `...` |
|
||||
|
||||
Для текущего пакета `152` байта нужно `19` CAN-кадров:
|
||||
|
||||
```text
|
||||
ceil(152 / 8) = 19
|
||||
IDs: 0x5A0..0x5B2
|
||||
```
|
||||
|
||||
Последний кадр несет полный 8-байтный блок.
|
||||
|
||||
Рекомендация для приемника CAN:
|
||||
|
||||
1. Считать кадр с `base_id`.
|
||||
2. Начать буфер нового пакета.
|
||||
3. Добавлять кадры `base_id + index`.
|
||||
4. После первых 16 байт прочитать `payload_size`.
|
||||
5. Ждать `16 + payload_size` байт.
|
||||
6. Проверить `magic`, `version`, `sequence`, `crc16`.
|
||||
7. При пропуске ID или смене `sequence` сбросить сборку пакета.
|
||||
|
||||
## Включение через Modbus
|
||||
|
||||
Modbus RTU остается каналом управления.
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| UART | `USART2` |
|
||||
| TX/RX | `PA2 / PA3` |
|
||||
| Скорость | `512000` |
|
||||
| Формат | `8N1` |
|
||||
| Slave address | `1` |
|
||||
|
||||
Регистры:
|
||||
|
||||
| Адрес hex / dec | Имя | Доступ | Значение |
|
||||
|---:|---|---|---|
|
||||
| `0x001C` / `28` | `control_host_protocol` | R/W | `0` = Modbus, `1` = binary telemetry |
|
||||
| `0x001D` / `29` | `control_binary_transport` | R/W | `0` = USB, `1` = CAN, `2` = USB + CAN |
|
||||
|
||||
Пример включения USB CDC:
|
||||
|
||||
```text
|
||||
write 0x001D / 29 = 0
|
||||
write 0x001C / 28 = 1
|
||||
```
|
||||
|
||||
Пример включения CAN:
|
||||
|
||||
```text
|
||||
write 0x001D / 29 = 1
|
||||
write 0x001C / 28 = 1
|
||||
```
|
||||
|
||||
Пример одновременной отправки USB и CAN:
|
||||
|
||||
```text
|
||||
write 0x001D / 29 = 2
|
||||
write 0x001C / 28 = 1
|
||||
```
|
||||
|
||||
Остановка бинарной телеметрии:
|
||||
|
||||
```text
|
||||
write 0x001C / 28 = 0
|
||||
```
|
||||
|
||||
## Состояние транспорта в отладчике
|
||||
|
||||
Основной debug-view:
|
||||
|
||||
```c
|
||||
g_ad_debug.binary_transport
|
||||
g_ad_debug.modbus
|
||||
```
|
||||
|
||||
`g_ad_debug.binary_transport.status_flags`:
|
||||
|
||||
| Бит | Маска | Флаг |
|
||||
|---:|---:|---|
|
||||
| `0` | `0x00000001` | `AD_BINARY_TRANSPORT_STATUS_INITIALIZED` |
|
||||
| `1` | `0x00000002` | `AD_BINARY_TRANSPORT_STATUS_USB_READY` |
|
||||
| `2` | `0x00000004` | `AD_BINARY_TRANSPORT_STATUS_CAN_READY` |
|
||||
| `3` | `0x00000008` | `AD_BINARY_TRANSPORT_STATUS_USB_CONFIGURED` |
|
||||
| `4` | `0x00000010` | `AD_BINARY_TRANSPORT_STATUS_USB_TX_BUSY` |
|
||||
| `5` | `0x00000020` | `AD_BINARY_TRANSPORT_STATUS_CAN_TX_BUSY` |
|
||||
| `6` | `0x00000040` | `AD_BINARY_TRANSPORT_STATUS_LAST_DROPPED` |
|
||||
|
||||
Полезные счетчики:
|
||||
|
||||
| Поле | Значение |
|
||||
|---|---|
|
||||
| `tx_packets` | Сколько пакетов успешно поставлено хотя бы в один транспорт |
|
||||
| `usb_packets` | Сколько пакетов принято USB TX |
|
||||
| `can_packets` | Сколько пакетов принято CAN TX |
|
||||
| `dropped_packets` | Сколько пакетов сброшено из-за busy/error/size |
|
||||
| `last_size_bytes` | Последний размер пакета, сейчас должен быть `152` |
|
||||
| `last_tx_tick_ms` | `HAL_GetTick()` последней успешной постановки |
|
||||
|
||||
## API прошивки
|
||||
|
||||
```c
|
||||
void SimulinkInterface_PackTelemetry(void);
|
||||
const SimulinkTelemetryPacket_t* SimulinkInterface_GetTelemetryPacket(void);
|
||||
const uint8_t* SimulinkInterface_GetTelemetryBytes(void);
|
||||
size_t SimulinkInterface_GetTelemetrySize(void);
|
||||
|
||||
void AD_BinaryTransport_Init(void);
|
||||
void AD_BinaryTransport_Loop(void);
|
||||
uint8_t AD_BinaryTransport_SetProtocol(uint16_t protocol);
|
||||
uint8_t AD_BinaryTransport_SetTransport(uint16_t transport);
|
||||
const AD_BinaryTransportState_t* AD_BinaryTransport_GetState(void);
|
||||
```
|
||||
|
||||
## Минимальный Python-декодер CRC
|
||||
|
||||
```python
|
||||
def crc16_ccitt(data: bytes) -> int:
|
||||
crc = 0xFFFF
|
||||
for value in data:
|
||||
crc ^= value << 8
|
||||
for _ in range(8):
|
||||
if crc & 0x8000:
|
||||
crc = ((crc << 1) ^ 0x1021) & 0xFFFF
|
||||
else:
|
||||
crc = (crc << 1) & 0xFFFF
|
||||
return crc
|
||||
```
|
||||
|
||||
Поля unpack для текущей версии:
|
||||
|
||||
```python
|
||||
HEADER_FMT = "<IHHIHH"
|
||||
PAYLOAD_SIZE_V3 = 136
|
||||
PACKET_SIZE_V3 = 16 + PAYLOAD_SIZE_V3
|
||||
MAGIC = 0x41444944
|
||||
VERSION = 3
|
||||
```
|
||||
Reference in New Issue
Block a user