/* Штатный 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; /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ }