Files
Balsam_167/Source/Internal/ecan.c
Andrey 04a9d989fb Исправить TESTLAMP, запуск CAN и расчёт фазных токов
Сохранить состояние TESTLAMP при кратких провалах входа и исключить повторный вход Timer1 во время передачи индикации.
Явно сбрасывать служебный обмен CAN при запуске и выбирать соседнюю фазу по локальному индексу канала АЦП.
Сохранить текущую последовательность DATA/CLK и проверочные варианты таймингов, добавить поведенческие тесты и обновить образ прошивки с картой памяти.
2026-10-13 14:13:43 +03:00

614 lines
51 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Штатный eCAN и отдельный служебный обмен УМП/GAS. Русские пояснения сохранены в UTF-8. */
/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
/* Подключает "DSP2833x_SWPrioritizedIsrLevels.h": поставляемое TI описание SWPrioritizedIsrLevels для семейства C2833x. */
#include "DSP2833x_SWPrioritizedIsrLevels.h"
/* Подключает "filter_bat2.h": накопительный фильтр измерительных каналов. */
#include "filter_bat2.h"
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
#include "measure.h"
/* Подключает "package.h": адреса устройств, типы плат и псевдонимы технологических регистров. */
#include "package.h" // DSP281x Headerfile Include File
/* Подключает "ecan.h": штатный eCAN и отдельный служебный обмен УМП/GAS. */
#include "ecan.h" // DSP281x Headerfile Include File
/* Подключает "tools.h": настройка внешней памяти и служебные задержки. */
#include "tools.h" // DSP281x Headerfile Include File
/* Подключает "RS485.h": приём и передача SCI-A/SCI-B, упаковка команд и FIFO первого порта. */
#include "RS485.h"
/* Подключает "message.h": обработка Modbus, заводские параметры и сохранение настроек. */
#include "message.h"
/* Подключает "peripher.h": перемычки режима платы, дискретные входы и выходы. */
#include "peripher.h"
/* Подключает "log_to_mem.h": двухбанковый регистратор событий нагрузки во внешней RAM. */
#include "log_to_mem.h"
/* Подключает "DAC.h": выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
#include "DAC.h"
/* Подключает "ump_can_protocol.h": настройки и интерфейс ump_can_protocol. */
#include "ump_can_protocol.h"
/* Подключает "gas167.h": дополнительная карта GAS 167/v1 только для новой EEPROM M95M02. */
#include "gas167.h"
// Prototype statements for functions found within this file.
/* Принимает CAN в прерывании, разбирает служебный запрос или передаёт данные штатному протоколу. */
interrupt void CANa_handler(void);
/* Объявляет интерфейс функции CANa_reset_err; реализация вызывается через этот прототип. */
interrupt void CANa_reset_err(void);
// Global variable for this example
/* Объявляет ErrorCount — ошибка число. */
Uint32 ErrorCount;
/* Объявляет MessageReceivedCount — Message Received число. */
Uint32 MessageReceivedCount;
/* Объявляет MessageTransivedCount — Message Transived число. Начальное значение задаётся справа от знака равенства. */
Uint32 MessageTransivedCount=0;
/* Объявляет TestMbox1 — данные TestMbox1. Начальное значение задаётся справа от знака равенства. */
Uint32 TestMbox1 = 0;
/* Объявляет TestMbox2 — данные TestMbox2. Начальное значение задаётся справа от знака равенства. */
Uint32 TestMbox2 = 0;
/* Объявляет TestMbox3 — данные TestMbox3. Начальное значение задаётся справа от знака равенства. */
Uint32 TestMbox3 = 0;
/* Объявляет CanTimeOutErrorTR — CAN Time Out ошибка TR. Начальное значение задаётся справа от знака равенства. */
int CanTimeOutErrorTR = 0;
/* Объявляет wait — данные wait. Начальное значение задаётся справа от знака равенства. */
int wait=0;
/* MBOX2 выделен под ответы регистратора; штатный MBOX0 продолжает
* передавать технологические данные независимо. ISR только ставит запрос,
* а снимок и отправка короткими шагами выполняются в основном цикле. */
/* Объявляет ump_can_pending — флаг ожидающего запроса служебного CAN между ISR и главным циклом. volatile требует фактического чтения или записи при каждом доступе. */
static volatile unsigned int ump_can_pending;
/* Объявляет ump_can_tag — ump CAN tag; ump_can_address — ump CAN адрес; ump_can_value — ump CAN value. volatile требует фактического чтения или записи при каждом доступе. */
static volatile unsigned int ump_can_tag, ump_can_address, ump_can_value;
/* Объявляет ump_can_reply — замороженные слова ответа служебного CAN. */
static unsigned int ump_can_reply[UMP_CAN_MAX_WORDS];
/* Объявляет ump_can_length — ump CAN длина; ump_can_index — ump CAN index; ump_can_reply_tag — ump CAN reply tag. */
static unsigned int ump_can_length, ump_can_index, ump_can_reply_tag;
/* Объявляет ump_can_waiting — ump CAN waiting. */
static unsigned int ump_can_waiting;
/* Объявляет ump_can_sent_at — время последней передачи фрагмента ответа CAN. */
static unsigned long ump_can_sent_at;
/* Сбрасывает служебный обмен до включения CAN: загрузка COFF не гарантирует обнуление неинициализированной RAM. */
static void ump_can_init(void)
/* Начинает сброс состояния; InitCan вызывается при запрещённых глобальных прерываниях. */
{
/* Убирает остаточный запрос, чтобы главный цикл не обрабатывал команду из RAM предыдущего запуска. */
ump_can_pending = 0;
/* Сбрасывает идентификатор и функцию запроса; действительные значения поступят из CANa_handler. */
ump_can_tag = 0;
/* Сбрасывает адрес запрошенного регистра до приёма новой команды. */
ump_can_address = 0;
/* Сбрасывает прежнее значение записи или число запрошенных слов. */
ump_can_value = 0;
/* Нулевая длина запрещает отправку старого буфера; новый запрос заполнит все доступные для передачи слова. */
ump_can_length = 0;
/* Начинает следующий подготовленный ответ с первого слова, исключая продолжение старого фрагмента. */
ump_can_index = 0;
/* Убирает прежний идентификатор ответа и код ошибки до подготовки новой команды. */
ump_can_reply_tag = 0;
/* Отменяет ожидание подтверждения старой передачи, которая после включения ещё не запускалась. */
ump_can_waiting = 0;
/* Сбрасывает отметку тайм-аута в тактах Timer1; новый фрагмент установит актуальное время отправки. */
ump_can_sent_at = 0;
/* Завершает сброс управляющих полей; содержимое буфера недоступно при нулевой длине ответа. */
}
/* Настраивает eCAN, скорость, почтовые ящики и маршрутизацию прерываний для выбранного режима платы. */
void InitCan(int Port, int DevNum)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Описывает структуру ECAN_REGS ECanShadow;; порядок полей определяет расположение данных. */
struct ECAN_REGS ECanShadow;
/* Продолжает список аргументов, полей или выражение volatile struct ECAN_REGS * ECanRegs;; порядок элементов сохраняется. */
volatile struct ECAN_REGS * ECanRegs;
/* Продолжает список аргументов, полей или выражение volatile struct ECAN_MBOXES * ECanMboxes;; порядок элементов сохраняется. */
volatile struct ECAN_MBOXES * ECanMboxes;
/* Продолжает список аргументов, полей или выражение volatile struct MOTO_REGS * ECanMOTORegs;; порядок элементов сохраняется. */
volatile struct MOTO_REGS * ECanMOTORegs;
/* Объявляет id — данные id. Начальное значение задаётся справа от знака равенства. */
long id = 0x80BA0000;
/* Обнуляет состояние служебного обмена до настройки mailbox и разрешения прерываний CAN. */
ump_can_init();
/* Изменяет счётчик в выражении DevNum--; на один для следующего шага. */
DevNum--;
/* Проверяет if(DevNum<0)DevNum=0; последующий оператор выполняется только при истинном условии. */
if(DevNum<0)DevNum=0;
/* Проверяет if(DevNum>15)DevNum=15; последующий оператор выполняется только при истинном условии. */
if(DevNum>15)DevNum=15;
// Configure CAN pins using GPIO regs here
/* Разрешение записи в защищённые регистры периферии. */
EALLOW;
/* Записывает ECanRegs значением &ECanaRegs; E CAN Regs. */
ECanRegs = &ECanaRegs;
/* Записывает ECanMboxes значением &ECanaMboxes; E CAN Mboxes. */
ECanMboxes = &ECanaMboxes;
/* Записывает ECanMOTORegs значением &ECanaMOTORegs; E CAN MOTO Regs. */
ECanMOTORegs = &ECanaMOTORegs;
/* Записывает GpioCtrlRegs.GPAMUX2.bit.GPIO30 значением 1; аппаратная линия ввода/вывода GPIO30. */
GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1;
/* Записывает GpioCtrlRegs.GPAMUX2.bit.GPIO31 значением 1; аппаратная линия ввода/вывода GPIO31. */
GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1;
// Configure the eCAN RX and TX pins for eCAN transmissions
/* Записывает ECanRegs->CANTIOC.all значением 8; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANTIOC.all = 8; // only 3rd bit, TXFUNC, is significant
/* Записывает ECanRegs->CANRIOC.all значением 8; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANRIOC.all = 8; // only 3rd bit, RXFUNC, is significant
// Specify that 8 bits will be sent/received
/* Записывает ECanMboxes->MBOX0.MSGCTRL.all значением 0x00000008; представление регистра целым словом без разбиения на битовые поля. */
ECanMboxes->MBOX0.MSGCTRL.all = 0x00000008;
/* Записывает ECanMboxes->MBOX1.MSGCTRL.all значением 0x00000008; представление регистра целым словом без разбиения на битовые поля. */
ECanMboxes->MBOX1.MSGCTRL.all = 0x00000008;
/* Записывает ECanMboxes->MBOX2.MSGCTRL.all значением 0x00000008; представление регистра целым словом без разбиения на битовые поля. */
ECanMboxes->MBOX2.MSGCTRL.all = 0x00000008;
// Disable all Mailboxes
// Required before writing the MSGIDs
/* Записывает ECanRegs->CANME.all значением 0; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANME.all = 0;
// задаем адрес 0 ащикa на передачу
/* Записывает ECanMboxes->MBOX0.MSGID.all значением id + 0x10 + DevNum; представление регистра целым словом без разбиения на битовые поля. */
ECanMboxes->MBOX0.MSGID.all = id + 0x10 + DevNum;
// задаем адрес 1 ащикa на прием
/* Записывает ECanMboxes->MBOX1.MSGID.all значением id + DevNum; представление регистра целым словом без разбиения на битовые поля. */
ECanMboxes->MBOX1.MSGID.all = id + DevNum; //поменать!!!! 1 и 0!!!
// MBOX0 и MBOX2 передают данные; MBOX1 принимает команды.
/* Записывает ECanMboxes->MBOX2.MSGID.all значением id + 0x20 + DevNum; представление регистра целым словом без разбиения на битовые поля. */
ECanMboxes->MBOX2.MSGID.all = id + 0x20 + DevNum;
/* Записывает ECanRegs->CANMD.all значением 0xFFFFFFFA; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANMD.all = 0xFFFFFFFA;
// Включаем три mailbox: телеметрия, команды и ответы логгера.
/* Записывает ECanRegs->CANME.all значением 0x00000007; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANME.all = 0x00000007;
// Clear all TAn bits
/* Записывает ECanRegs->CANTA.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANTA.all = 0xFFFFFFFF;
// Clear all RMPn bits
/* Записывает ECanRegs->CANRMP.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANRMP.all = 0xFFFFFFFF;
// Clear all interrupt flag bits
/* Записывает ECanRegs->CANGIF0.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANGIF0.all = 0xFFFFFFFF;
/* Записывает ECanRegs->CANGIF1.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANGIF1.all = 0xFFFFFFFF;
// Clear all error and status bits
/* Записывает ECanRegs->CANES.all значением 0xffffffff; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANES.all=0xffffffff;
// Request permission to change the configuration registers
/* Записывает ECanShadow.CANMC.all значением 0; представление регистра целым словом без разбиения на битовые поля. */
ECanShadow.CANMC.all = 0;
/* Записывает ECanShadow.CANMC.bit.MBCC значением 1; данные MBCC. */
ECanShadow.CANMC.bit.MBCC = 1; // Mailbox timestamp counter clear bit
/* Записывает ECanShadow.CANMC.bit.TCC значением 1; данные TCC. */
ECanShadow.CANMC.bit.TCC = 1; // Time stamp counter MSB clear bit
/* Записывает ECanShadow.CANMC.bit.SCB значением 1; данные SCB. */
ECanShadow.CANMC.bit.SCB = 1; // eCAN mode (reqd to access 32 mailboxes)
/* Записывает ECanShadow.CANMC.bit.WUBA значением 1; данные WUBA. */
ECanShadow.CANMC.bit.WUBA = 1; // Wake up on bus activity
/* Записывает ECanShadow.CANMC.bit.ABO значением 1; данные ABO. */
ECanShadow.CANMC.bit.ABO = 1; // Auto bus on
/* Записывает ECanShadow.CANMC.bit.CCR значением 1; данные CCR. */
ECanShadow.CANMC.bit.CCR = 1;
// ECanShadow.CANMC.bit.STM = 1; // self-test loop-back
/* Записывает ECanRegs->CANMC.all значением ECanShadow.CANMC.all; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANMC.all = ECanShadow.CANMC.all;
/* Повторяет или ожидает, пока выполняется while(!ECanRegs->CANES.bit.CCE);. */
while(!ECanRegs->CANES.bit.CCE); // Wait for CCE bit to be set..
// настриваем скорость CAN
/* Записывает ECanShadow.CANBTC.all значением ECanRegs->CANBTC.all; представление регистра целым словом без разбиения на битовые поля. */
ECanShadow.CANBTC.all = ECanRegs->CANBTC.all;
/* Записывает ECanShadow.CANBTC.bit.SJWREG значением 1; данные SJWREG. */
ECanShadow.CANBTC.bit.SJWREG=1;
/* Записывает ECanShadow.CANBTC.bit.BRPREG значением (CLKMULT * 3) - 1; данные BRPREG. */
ECanShadow.CANBTC.bit.BRPREG = (CLKMULT * 3) - 1;
/* Записывает ECanShadow.CANBTC.bit.TSEG1REG значением 15; данные TSEG1REG. */
ECanShadow.CANBTC.bit.TSEG1REG = 15;
/* Записывает ECanShadow.CANBTC.bit.TSEG2REG значением 2; данные TSEG2REG. */
ECanShadow.CANBTC.bit.TSEG2REG = 2;
/* Записывает ECanRegs->CANBTC.all значением ECanShadow.CANBTC.all; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANBTC.all = ECanShadow.CANBTC.all;
/* Записывает ECanShadow.CANMC.bit.CCR значением 0; данные CCR. */
ECanShadow.CANMC.bit.CCR = 0; // Set CCR = 0
/* Записывает ECanRegs->CANMC.all значением ECanShadow.CANMC.all; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANMC.all = ECanShadow.CANMC.all;
/* Повторяет или ожидает, пока выполняется while(ECanRegs->CANES.bit.CCE);. */
while(ECanRegs->CANES.bit.CCE); // Wait for CCE bit to be cleared..
// задаем таймауты дла ожиданиа отправки получениа посылки
/* Записывает ECanMOTORegs->MOTO0 значением 550000; E CAN MOTO Regs 0. */
ECanMOTORegs->MOTO0 = 550000;
/* Записывает ECanMOTORegs->MOTO1 значением 550000; E CAN MOTO Regs 1. */
ECanMOTORegs->MOTO1 = 550000;
/* Записывает ECanRegs->CANTOC.all значением 1; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANTOC.all = 1;
/* Записывает ECanRegs->CANTOS.all значением 0; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANTOS.all = 0; // clear all time-out flags
/* Записывает ECanRegs->CANTSC значением 0; E CAN Regs CANTSC. */
ECanRegs->CANTSC = 0; // clear time-out counter
/* Записывает ECanShadow.CANGIM.all значением 0; представление регистра целым словом без разбиения на битовые поля. */
ECanShadow.CANGIM.all = 0;
/* Записывает ECanRegs->CANMIM.all значением 2; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANMIM.all = 2; // Enable interrupts of box 1
/* Записывает ECanRegs->CANMIL.all значением 0x00000000; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANMIL.all = 0x00000000; // All mailbox interrupts are generated on interrupt line 0.
/* Записывает ECanShadow.CANGIM.bit.I0EN значением 1; данные I0EN. */
ECanShadow.CANGIM.bit.I0EN = 1;
/* Записывает ECanShadow.CANGIM.bit.MTOM значением 1; данные MTOM. */
ECanShadow.CANGIM.bit.MTOM = 1;
/* Записывает ECanShadow.CANGIM.bit.I1EN значением 1; данные I1EN. */
ECanShadow.CANGIM.bit.I1EN = 1;
/* Записывает ECanShadow.CANGIM.bit.GIL значением 1; данные GIL. */
ECanShadow.CANGIM.bit.GIL = 1;
/* Записывает ECanRegs->CANGIM.all значением ECanShadow.CANGIM.all; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANGIM.all = ECanShadow.CANGIM.all;
/* Записывает PieVectTable.ECAN0INTA значением &CANa_handler; данные ECAN0INTA. */
PieVectTable.ECAN0INTA = &CANa_handler;
/* Записывает PieCtrlRegs.PIEIER9.bit.INTx5 значением 1; данные INTx5. */
PieCtrlRegs.PIEIER9.bit.INTx5=1; // PIE Group 9, INT6
/* Записывает PieVectTable.ECAN1INTA значением &CANa_reset_err; данные ECAN1INTA. */
PieVectTable.ECAN1INTA = &CANa_reset_err;
/* Записывает PieCtrlRegs.PIEIER9.bit.INTx6 значением 1; данные INTx6. */
PieCtrlRegs.PIEIER9.bit.INTx6=1; // PIE Group 9, INT6
/* Устанавливает биты IER значением M_INT9; регистр разрешения прерываний ядра C28x. */
IER |= M_INT9; // Enable CPU INT
/* Закрытие доступа к защищённым регистрам периферии. */
EDIS;
// завершили настройку CAN ащиков
/* Записывает MessageReceivedCount значением 0; Message Received число. */
MessageReceivedCount = 0;
/* Записывает ErrorCount значением 0; ошибка число. */
ErrorCount = 0;
/* Записывает CanTimeOutErrorTR значением 0; CAN Time Out ошибка TR. */
CanTimeOutErrorTR=0;
/* Записывает MessageTransivedCount значением 0; Message Transived число. */
MessageTransivedCount=0;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Упаковывает адрес и технологические слова в штатный CAN-кадр и запускает передачу mailbox. */
void CAN_send(int Port, int data[], int Addr)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет hiword — данные hiword; loword — данные loword. */
unsigned long hiword,loword;
/* Продолжает список аргументов, полей или выражение volatile struct ECAN_REGS * ECanRegs;; порядок элементов сохраняется. */
volatile struct ECAN_REGS * ECanRegs;
/* Продолжает список аргументов, полей или выражение volatile struct ECAN_MBOXES * ECanMboxes;; порядок элементов сохраняется. */
volatile struct ECAN_MBOXES * ECanMboxes;
/* Записывает ECanRegs значением &ECanaRegs; E CAN Regs. */
ECanRegs = &ECanaRegs;
/* Записывает ECanMboxes значением &ECanaMboxes; E CAN Mboxes. */
ECanMboxes = &ECanaMboxes;
/* Проверяет if(wait); последующий оператор выполняется только при истинном условии. */
if(wait)
/* Проверяет if(!(ECanRegs->CANTA.all & 1)); последующий оператор выполняется только при истинном условии. */
if(!(ECanRegs->CANTA.all & 1))
/* Проверяет if(!(ECanRegs->CANAA.all & 1)); последующий оператор выполняется только при истинном условии. */
if(!(ECanRegs->CANAA.all & 1))
/* Завершает CAN_send без возвращаемого значения. */
return;
/* Записывает ECanRegs->CANTA.all значением 1; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANTA.all = 1;
/* Записывает ECanRegs->CANAA.all значением 1; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANAA.all = 1;
/* Записывает hiword значением ((((Uint32) Addr ) & 0xffff)<<16)| 0xE0000000 |; данные hiword. */
hiword= ((((Uint32) Addr ) & 0xffff)<<16)| 0xE0000000 |
/* Продолжает список аргументов, полей или выражение ((((Uint32)data[Addr ]) & 0xffff) );; порядок элементов сохраняется. */
((((Uint32)data[Addr ]) & 0xffff) );
/* Записывает loword значением ((((Uint32)data[Addr+1]) & 0xffff)<<16)|; данные loword. */
loword= ((((Uint32)data[Addr+1]) & 0xffff)<<16)|
/* Продолжает список аргументов, полей или выражение ((((Uint32)data[Addr+2]) & 0xffff) );; порядок элементов сохраняется. */
((((Uint32)data[Addr+2]) & 0xffff) );
/* Записывает ECanMboxes->MBOX0.MDH.all значением hiword; представление регистра целым словом без разбиения на битовые поля. */
ECanMboxes->MBOX0.MDH.all = hiword;
/* Записывает ECanMboxes->MBOX0.MDL.all значением loword; представление регистра целым словом без разбиения на битовые поля. */
ECanMboxes->MBOX0.MDL.all = loword;
/* Разрешение записи в защищённые регистры периферии. */
EALLOW;
/* Записывает ECanRegs->CANTSC значением 0; E CAN Regs CANTSC. */
ECanRegs->CANTSC = 0; // clear time-out counter
/* Закрытие доступа к защищённым регистрам периферии. */
EDIS;
/* Записывает ECanRegs->CANTRS.all значением 1; представление регистра целым словом без разбиения на битовые поля. */
ECanRegs->CANTRS.all = 1; // запустить передачу
/* Записывает wait значением 1; данные wait. */
wait=1;
/* Вызывает led1_toggle с аргументами () в текущей последовательности операций. */
led1_toggle();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Начинает функцию Handlai; назначение модуля — штатный eCAN и отдельный служебный обмен УМП/GAS. */
void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* adr адресует очередное технологическое слово, slot выбирает одно из трёх слов кадра, mask хранит их биты достоверности 15..13. */
unsigned int adr, slot, mask;
/* Объявляет hiword — данные hiword; loword — данные loword. */
unsigned long hiword,loword;
/* Объявляет Data — данные. */
int Data[3];
/* Записывает Lonely значением 0; данные Lonely. */
Lonely=0;
/* Записывает hiword значением ECanMboxes->MBOX1.MDH.all; данные hiword. */
hiword = ECanMboxes->MBOX1.MDH.all;
/* Записывает loword значением ECanMboxes->MBOX1.MDL.all; данные loword. */
loword = ECanMboxes->MBOX1.MDL.all;
/* Служебный запрос логгера не является командой УМП и сам не должен
* заполнять журнал CAN-событиями при онлайн-чтении. Короткие кадры
* отбрасываются: незаполненные байты mailbox могли остаться от прошлого. */
/* Проверяет if ((unsigned int)(hiword >> 16) == UMP_CAN_MARKER); последующий оператор выполняется только при истинном условии. */
if ((unsigned int)(hiword >> 16) == UMP_CAN_MARKER) {
/* Проверяет if (ECanMboxes->MBOX1.MSGCTRL.bit.DLC == 8 и (hiword & 0xFF00UL)); последующий оператор выполняется только при истинном условии. */
if (ECanMboxes->MBOX1.MSGCTRL.bit.DLC == 8 && (hiword & 0xFF00UL)) {
/* Записывает ump_can_tag значением (unsigned int)hiword; ump CAN tag. */
ump_can_tag = (unsigned int)hiword;
/* Записывает ump_can_address значением (unsigned int)(loword >> 16); ump CAN адрес. */
ump_can_address = (unsigned int)(loword >> 16);
/* Записывает ump_can_value значением (unsigned int)loword; ump CAN value. */
ump_can_value = (unsigned int)loword;
/* Записывает ump_can_pending значением 1; флаг ожидающего запроса служебного CAN между ISR и главным циклом. */
ump_can_pending = 1;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Завершает Handlai без возвращаемого значения. */
return;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Записывает adr значением (hiword >> 16); данные adr. */
adr = (hiword >> 16);
/* Маска 0xE000 объединяет биты достоверности трёх слов CAN; сдвиг в цикле последовательно выводит каждый из них в бит 15. */
mask = adr & 0xE000U;
/* Оставляет биты маски adr значением 0x1fff; данные adr. */
adr &= 0x1fff;
/* Записывает Data[0] значением (hiword ) & 0xffff; данные. */
Data[0] = (hiword ) & 0xffff;
/* Записывает Data[1] значением (loword>>16) & 0xffff; данные. */
Data[1] = (loword>>16) & 0xffff;
/* Записывает Data[2] значением (loword ) & 0xffff; данные. */
Data[2] = (loword ) & 0xffff;
/* Обрабатывает ровно три слова CAN; адрес растёт независимо от маски, а её сдвиг выбирает достоверность следующего слова. */
for (slot = 0; slot < 3; slot++, adr++, mask <<= 1)
/* Бит 15 текущей маски разрешает запись только в опубликованные 128 регистров, исключая выход за массив. */
if ((mask & 0x8000U) && adr < ANSWER_LEN &&
/* Для LOAD сохраняет статус 0x7C и отклоняет ноль в лимите 0x7D; остальные значения сохраняются как исходное 16-битное слово. */
!(Desk == dsk_LOAD && (adr == 0x7CU || (adr == 0x7DU && !(unsigned int)Data[slot])))) modbus[adr] = Data[slot];
/* Фиксируем применённую команду до выхода из обработчика CAN. */
/* A short frame cannot confirm voltage freshness. Service frames
* UMP_MARKER return above and do not refresh this timeout. */
/* Проверяет if (ECanMboxes->MBOX1.MSGCTRL.bit.DLC == 8); последующий оператор выполняется только при истинном условии. */
if (ECanMboxes->MBOX1.MSGCTRL.bit.DLC == 8)
/* Вызывает Load_voltage_can. Принимает напряжение выбранной нагрузки из достоверных слов CAN и сбрасывает возраст только нужного измерения. */
Load_voltage_can((unsigned int)(hiword >> 16), Data[0], Data[1], Data[2]);
/* Вызывает ump_log_can. Обновляет последние CAN-данные и напряжения для следующего снимка регистратора. */
ump_log_can((unsigned int)(hiword >> 16), Data[0], Data[1], Data[2]);
/* Вызывает led2_toggle с аргументами () в текущей последовательности операций. */
led2_toggle();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Принимает CAN в прерывании, разбирает служебный запрос или передаёт данные штатному протоколу. */
interrupt void CANa_handler(void)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
// Set interrupt priority:
/* Объявляет TempPIEIER — сохранённая маска разрешённых прерываний группы PIE. volatile требует фактического чтения или записи при каждом доступе. Начальное значение задаётся справа от знака равенства. */
volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;
/* Устанавливает биты IER значением M_INT9; регистр разрешения прерываний ядра C28x. */
IER |= M_INT9;
/* Оставляет биты маски IER значением MINT9; регистр разрешения прерываний ядра C28x. */
IER &= MINT9; // Set "global" priority
/* Оставляет биты маски PieCtrlRegs.PIEIER9.all значением MG95; представление регистра целым словом без разбиения на битовые поля. */
PieCtrlRegs.PIEIER9.all &= MG95; // Set "group" priority
/* Записывает PieCtrlRegs.PIEACK.all значением 0xFFFF; представление регистра целым словом без разбиения на битовые поля. */
PieCtrlRegs.PIEACK.all = 0xFFFF; // Enable PIE interrupts
/* Разрешение маскируемых прерываний ядра. */
EINT;
/* Вызывает Handlai с аргументами (&ECanaMboxes) в текущей последовательности операций. */
Handlai(&ECanaMboxes);
/* Записывает ECanaRegs.CANRMP.all значением 2; представление регистра целым словом без разбиения на битовые поля. */
ECanaRegs.CANRMP.all = 2;
/* Устанавливает биты PieCtrlRegs.PIEACK.bit.ACK9 значением 1; данные ACK9. */
PieCtrlRegs.PIEACK.bit.ACK9 |= 1;
// Restore registers saved:
/* Запрет маскируемых прерываний ядра. */
DINT;
/* Записывает PieCtrlRegs.PIEIER9.all значением TempPIEIER; представление регистра целым словом без разбиения на битовые поля. */
PieCtrlRegs.PIEIER9.all = TempPIEIER;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Начинает функцию CANa_reset_err; назначение модуля — штатный eCAN и отдельный служебный обмен УМП/GAS. */
interrupt void CANa_reset_err(void)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
// Set interrupt priority:
/* Объявляет TempPIEIER — сохранённая маска разрешённых прерываний группы PIE. volatile требует фактического чтения или записи при каждом доступе. Начальное значение задаётся справа от знака равенства. */
volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;
/* Устанавливает биты IER значением M_INT9; регистр разрешения прерываний ядра C28x. */
IER |= M_INT9;
/* Оставляет биты маски IER значением MINT9; регистр разрешения прерываний ядра C28x. */
IER &= MINT9; // Set "global" priority
/* Оставляет биты маски PieCtrlRegs.PIEIER9.all значением MG96; представление регистра целым словом без разбиения на битовые поля. */
PieCtrlRegs.PIEIER9.all &= MG96; // Set "group" priority
/* Записывает PieCtrlRegs.PIEACK.all значением 0xFFFF; представление регистра целым словом без разбиения на битовые поля. */
PieCtrlRegs.PIEACK.all = 0xFFFF; // Enable PIE interrupts
/* Разрешение маскируемых прерываний ядра. */
EINT;
/* Записывает ECanaRegs.CANTRR.all значением 1; представление регистра целым словом без разбиения на битовые поля. */
ECanaRegs.CANTRR.all = 1;
/* Изменяет счётчик в выражении CanTimeOutErrorTR++; на один для следующего шага. */
CanTimeOutErrorTR++;
/* Устанавливает биты PieCtrlRegs.PIEACK.bit.ACK9 значением 1; данные ACK9. */
PieCtrlRegs.PIEACK.bit.ACK9 |= 1;
// Restore registers saved:
/* Запрет маскируемых прерываний ядра. */
DINT;
/* Записывает PieCtrlRegs.PIEIER9.all значением TempPIEIER; представление регистра целым словом без разбиения на битовые поля. */
PieCtrlRegs.PIEIER9.all = TempPIEIER;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
//===========================================================================
// No more.
//===========================================================================
/* Один вызов обслуживает максимум один кадр и никогда не ждёт ACK в цикле.
* Снимок фиксируется один раз на запрос: CAN-фрагменты не смешивают
* значения до/после переключения кольцевого банка. Новые запросы забираем
* после завершения предыдущего ответа. GUI держит только один запрос. */
/* В главном цикле готовит замороженный ответ служебного CAN и отправляет его двухсловными фрагментами. */
void UMP_CAN_service(void)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет saved — данные saved; tag — данные tag; address — адрес; value — данные value; error — ошибка. */
unsigned int saved, tag, address, value, error;
/* Объявляет hiword — данные hiword; loword — данные loword. */
uint32_t hiword, loword;
/* Проверяет if (ump_can_waiting); последующий оператор выполняется только при истинном условии. */
if (ump_can_waiting) {
/* Проверяет if (ECanaRegs.CANTA.all & 4UL); последующий оператор выполняется только при истинном условии. */
if (ECanaRegs.CANTA.all & 4UL) {
/* Записывает ECanaRegs.CANTA.all значением 4UL; представление регистра целым словом без разбиения на битовые поля. */
ECanaRegs.CANTA.all = 4UL;
/* Записывает ump_can_waiting значением 0; ump CAN waiting. */
ump_can_waiting = 0;
/* Проверяет else if ((ECanaRegs.CANAA.all & 4UL) или; последующий оператор выполняется только при истинном условии. */
} else if ((ECanaRegs.CANAA.all & 4UL) ||
/* Продолжает список аргументов, полей или выражение ((unsigned long)CpuTimer1.InterruptCount - ump_can_sent_at > 250UL)) {; порядок элементов сохраняется. */
((unsigned long)CpuTimer1.InterruptCount - ump_can_sent_at > 250UL)) {
/* Нет подтверждения шины: отменяем только служебный mailbox.
* GUI обнаружит неполный ответ по тайм-ауту; управление MBOX0
* и приём команд MBOX1 продолжаются. */
/* Записывает ECanaRegs.CANTRR.all значением 4UL; представление регистра целым словом без разбиения на битовые поля. */
ECanaRegs.CANTRR.all = 4UL;
/* До фактического завершения отмены mailbox не переиспользуем. */
/* Проверяет if (!(ECanaRegs.CANAA.all & 4UL)) return; последующий оператор выполняется только при истинном условии. */
if (!(ECanaRegs.CANAA.all & 4UL)) return;
/* Записывает ECanaRegs.CANAA.all значением 4UL; представление регистра целым словом без разбиения на битовые поля. */
ECanaRegs.CANAA.all = 4UL;
/* Записывает ump_can_waiting значением 0; ump CAN waiting. */
ump_can_waiting = 0;
/* Записывает ump_can_length значением 0; ump CAN длина. */
ump_can_length = 0;
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
} else return;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Проверяет if (ump_can_index >= ump_can_length и ump_can_pending); последующий оператор выполняется только при истинном условии. */
if (ump_can_index >= ump_can_length && ump_can_pending) {
/* Записывает saved значением __disable_interrupts(); данные saved. */
saved = __disable_interrupts();
/* Записывает tag значением ump_can_tag; address = ump_can_address; value = ump_can_value; данные tag. */
tag = ump_can_tag; address = ump_can_address; value = ump_can_value;
/* Записывает ump_can_pending значением 0; флаг ожидающего запроса служебного CAN между ISR и главным циклом. */
ump_can_pending = 0;
/* Проверяет if (address >= 0x1300U и address < 0x1308U); последующий оператор выполняется только при истинном условии. */
if (address >= 0x1300U && address < 0x1308U)
/* Записывает ump_can_length значением Load_protection_prepare(tag & 0xFF, address, value, ump_can_reply, &error); ump CAN длина. */
ump_can_length = Load_protection_prepare(tag & 0xFF, address, value, ump_can_reply, &error);
/* Условие компиляции EEPROM_M95M02: выбранный блок включается в текущий вариант прошивки. */
#if EEPROM_M95M02
/* Проверяет else if (gas167_contains(address)); последующий оператор выполняется только при истинном условии. */
else if (gas167_contains(address))
/* Записывает ump_can_length значением gas167_prepare(tag & 0xFF, address, value, 1, ump_can_reply, &error); ump CAN длина. */
ump_can_length = gas167_prepare(tag & 0xFF, address, value, 1, ump_can_reply, &error);
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
#endif
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
else ump_can_length = ump_can_prepare(tag & 0xFF, address, value, ump_can_reply, &error);
/* Записывает ump_can_reply_tag значением (tag & 0xFF00) | error; ump CAN reply tag. */
ump_can_reply_tag = (tag & 0xFF00) | error;
/* Записывает ump_can_index значением 0; ump CAN index. */
ump_can_index = 0;
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
__restore_interrupts(saved);
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Проверяет if (ump_can_index >= ump_can_length) return; последующий оператор выполняется только при истинном условии. */
if (ump_can_index >= ump_can_length) return;
/* Перед следующим фрагментом уступаем штатной телеметрии MBOX0. */
/* Проверяет if (ECanaRegs.CANTRS.all & 1UL) return; последующий оператор выполняется только при истинном условии. */
if (ECanaRegs.CANTRS.all & 1UL) return;
/* Проверяет if (!ump_tms28335_fragment(ump_can_reply, ump_can_length, ump_can_index/2,; последующий оператор выполняется только при истинном условии. */
if (!ump_tms28335_fragment(ump_can_reply, ump_can_length, ump_can_index/2,
/* Продолжает список аргументов, полей или выражение ump_can_reply_tag >> 8, ump_can_reply_tag & 255U, &loword, &hiword)) {; порядок элементов сохраняется. */
ump_can_reply_tag >> 8, ump_can_reply_tag & 255U, &loword, &hiword)) {
/* Записывает ump_can_length значением 0; ump CAN длина. */
ump_can_length = 0;
/* Завершает UMP_CAN_service без возвращаемого значения. */
return;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Записывает ECanaRegs.CANTA.all значением 4UL; ECanaRegs.CANAA.all = 4UL; представление регистра целым словом без разбиения на битовые поля. */
ECanaRegs.CANTA.all = 4UL; ECanaRegs.CANAA.all = 4UL;
/* Записывает ECanaMboxes.MBOX2.MDH.all значением hiword; представление регистра целым словом без разбиения на битовые поля. */
ECanaMboxes.MBOX2.MDH.all = hiword;
/* Записывает ECanaMboxes.MBOX2.MDL.all значением loword; представление регистра целым словом без разбиения на битовые поля. */
ECanaMboxes.MBOX2.MDL.all = loword;
/* Записывает ump_can_sent_at значением CpuTimer1.InterruptCount; время последней передачи фрагмента ответа CAN. */
ump_can_sent_at = CpuTimer1.InterruptCount;
/* Записывает ECanaRegs.CANTRS.all значением 4UL; представление регистра целым словом без разбиения на битовые поля. */
ECanaRegs.CANTRS.all = 4UL;
/* Записывает ump_can_waiting значением 1; ump CAN waiting. */
ump_can_waiting = 1;
/* Увеличивает ump_can_index значением 2; ump CAN index. */
ump_can_index += 2;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}