Сохранить состояние TESTLAMP при кратких провалах входа и исключить повторный вход Timer1 во время передачи индикации. Явно сбрасывать служебный обмен CAN при запуске и выбирать соседнюю фазу по локальному индексу канала АЦП. Сохранить текущую последовательность DATA/CLK и проверочные варианты таймингов, добавить поведенческие тесты и обновить образ прошивки с картой памяти.
614 lines
51 KiB
C
614 lines
51 KiB
C
/* Штатный 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;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
}
|